From 9e5122c5d8e4795e9835ac7842fb85cd478ea84f Mon Sep 17 00:00:00 2001 From: wandalen Date: Mon, 23 May 2022 11:51:07 +0300 Subject: [PATCH] version 1.0.20 --- node_modules/Joined.s | 247719 +++++++++++++++ node_modules/async/retry.js | 159 + node_modules/async/retryable.js | 77 + .../portscanner/node_modules/async/retry.js | 156 + .../node_modules/async/retryable.js | 65 + .../wfilesencoders/node_modules/.bin/js-yaml | 1 + .../node_modules/argparse/CHANGELOG.md | 216 + .../node_modules/argparse/LICENSE | 254 + .../node_modules/argparse/README.md | 84 + .../node_modules/argparse/argparse.js | 3707 + .../node_modules/argparse/lib/sub.js | 67 + .../node_modules/argparse/lib/textwrap.js | 440 + .../node_modules/argparse/package.json | 31 + .../node_modules/js-yaml/CHANGELOG.md | 616 + .../node_modules/js-yaml/LICENSE | 21 + .../node_modules/js-yaml/README.md | 246 + .../node_modules/js-yaml/bin/js-yaml.js | 126 + .../node_modules/js-yaml/dist/js-yaml.js | 3874 + .../node_modules/js-yaml/dist/js-yaml.min.js | 2 + .../node_modules/js-yaml/dist/js-yaml.mjs | 3851 + .../node_modules/js-yaml/index.js | 47 + .../node_modules/js-yaml/lib/common.js | 59 + .../node_modules/js-yaml/lib/dumper.js | 965 + .../node_modules/js-yaml/lib/exception.js | 55 + .../node_modules/js-yaml/lib/loader.js | 1727 + .../node_modules/js-yaml/lib/schema.js | 121 + .../node_modules/js-yaml/lib/schema/core.js | 11 + .../js-yaml/lib/schema/default.js | 22 + .../js-yaml/lib/schema/failsafe.js | 17 + .../node_modules/js-yaml/lib/schema/json.js | 19 + .../node_modules/js-yaml/lib/snippet.js | 101 + .../node_modules/js-yaml/lib/type.js | 66 + .../node_modules/js-yaml/lib/type/binary.js | 125 + .../node_modules/js-yaml/lib/type/bool.js | 35 + .../node_modules/js-yaml/lib/type/float.js | 97 + .../node_modules/js-yaml/lib/type/int.js | 156 + .../node_modules/js-yaml/lib/type/map.js | 8 + .../node_modules/js-yaml/lib/type/merge.js | 12 + .../node_modules/js-yaml/lib/type/null.js | 35 + .../node_modules/js-yaml/lib/type/omap.js | 44 + .../node_modules/js-yaml/lib/type/pairs.js | 53 + .../node_modules/js-yaml/lib/type/seq.js | 8 + .../node_modules/js-yaml/lib/type/set.js | 29 + .../node_modules/js-yaml/lib/type/str.js | 8 + .../js-yaml/lib/type/timestamp.js | 88 + .../node_modules/js-yaml/package.json | 66 + package.json | 5 +- will.yml | 2 +- 48 files changed, 265689 insertions(+), 4 deletions(-) create mode 100644 node_modules/Joined.s create mode 100644 node_modules/async/retry.js create mode 100644 node_modules/async/retryable.js create mode 100644 node_modules/portscanner/node_modules/async/retry.js create mode 100644 node_modules/portscanner/node_modules/async/retryable.js create mode 120000 node_modules/wfilesencoders/node_modules/.bin/js-yaml create mode 100644 node_modules/wfilesencoders/node_modules/argparse/CHANGELOG.md create mode 100644 node_modules/wfilesencoders/node_modules/argparse/LICENSE create mode 100644 node_modules/wfilesencoders/node_modules/argparse/README.md create mode 100644 node_modules/wfilesencoders/node_modules/argparse/argparse.js create mode 100644 node_modules/wfilesencoders/node_modules/argparse/lib/sub.js create mode 100644 node_modules/wfilesencoders/node_modules/argparse/lib/textwrap.js create mode 100644 node_modules/wfilesencoders/node_modules/argparse/package.json create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/CHANGELOG.md create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/LICENSE create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/README.md create mode 100755 node_modules/wfilesencoders/node_modules/js-yaml/bin/js-yaml.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/dist/js-yaml.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/dist/js-yaml.min.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/dist/js-yaml.mjs create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/index.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/common.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/dumper.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/exception.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/loader.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/schema.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/core.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/default.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/failsafe.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/json.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/snippet.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/type.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/type/binary.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/type/bool.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/type/float.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/type/int.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/type/map.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/type/merge.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/type/null.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/type/omap.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/type/pairs.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/type/seq.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/type/set.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/type/str.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/lib/type/timestamp.js create mode 100644 node_modules/wfilesencoders/node_modules/js-yaml/package.json diff --git a/node_modules/Joined.s b/node_modules/Joined.s new file mode 100644 index 00000000..620050e4 --- /dev/null +++ b/node_modules/Joined.s @@ -0,0 +1,247719 @@ + +/* */ /* begin of library Joined_s */ ( function _library_() { + +/* */ /* begin of predefined */ ( function _predefined_() { + + + + 'use strict'; + + /* */ + + let _global = get(); + if( !_global._globals_ ) + { + _global._globals_ = Object.create( null ); + _global._globals_.real = _global._realGlobal_ || _global; + _global._realGlobal_ = _global; + _global._global_ = _global; + } + + /* */ + + function get() + { + let _global = undefined; + if( typeof _global_ !== 'undefined' && _global_._global_ === _global_ ) + _global = _global_; + else if( typeof globalThis !== 'undefined' && globalThis.globalThis === globalThis ) + _global = globalThis; + else if( typeof Global !== 'undefined' && Global.Global === Global ) + _global = Global; + else if( typeof global !== 'undefined' && global.global === global ) + _global = global; + else if( typeof window !== 'undefined' && window.window === window ) + _global = window; + else if( typeof self !== 'undefined' && self.self === self ) + _global = self; + return _global; + } + + /* */ + + if( !_global_.Config ) + _global_.Config = Object.create( null ); + if( _global_.Config.interpreter === undefined ) + _global_.Config.interpreter = ( ( typeof module !== 'undefined' ) && ( typeof process !== 'undefined' ) ) ? 'njs' : 'browser'; + if( _global_.Config.isWorker === undefined ) + _global_.Config.isWorker = !!( typeof self !== 'undefined' && self.self === self && typeof importScripts !== 'undefined' ); + + /* */ + + if( _global._starter_ && _global._starter_._inited ) + return; + + let _starter_ = _global._starter_ = _global._starter_ || Object.create( null ); + let _ = _starter_; + const Self = _starter_; + + _realGlobal_.HashMap = Map; + _realGlobal_.HashMapWeak = WeakMap; + + // special tokens + + Self.def = Symbol.for( 'def' ); + Self.null = Symbol.for( 'null' ); + Self.undefined = Symbol.for( 'undefined' ); + Self.nothing = Symbol.for( 'nothing' ); + Self.anything = Symbol.for( 'anything' ); + Self.maybe = Symbol.for( 'maybe' ); + Self.unknown = Symbol.for( 'unknown' ); + Self.dont = Symbol.for( 'dont' ); + Self.self = Symbol.for( 'self' ); + Self.optional = Symbol.for( 'optional' ); + + _realGlobal_.unrollSymbol = Symbol.for( 'unroll' ); + +; + +/* */ _global_._starter_.debug = 1; +/* */ _global_._starter_.interpreter = 'njs'; +/* */ _global_._starter_.proceduring = 0; +/* */ _global_._starter_.globing = 1; +/* */ _global_._starter_.catchingUncaughtErrors = 1; +/* */ _global_._starter_.loggingApplication = 0; +/* */ _global_._starter_.loggingSourceFiles = 0; +/* */ _global_._starter_.withServer = 0; +/* */ _global_._starter_.redirectingConsole = 0; +/* */ _global_._starter_.loggingPath = 'ws://127.0.0.1:15000/.log/'; + +/* */ _global_.Config.debug = 1; + + + +; + +/* */ /* end of predefined */ })(); + + +/* */ /* begin of early */ ( function _early_() { + + + + 'use strict'; + + const _global = _global_; + let _starter_ = _global._starter_ = _global._starter_ || Object.create( null ); + let _ = _starter_; + + let str = _starter_.str = _starter_.str || Object.create( null ); + let date = _starter_.date = _starter_.date || Object.create( null ); + let entity = _starter_.entity = _starter_.entity || Object.create( null ); + let _class = _starter_.class = _starter_.class || Object.create( null ); + let path = _starter_.path = _starter_.path || Object.create( null ); + let uri = _starter_.uri = _starter_.uri || Object.create( null ); + let property = _starter_.props = _starter_.props || Object.create( null ); + _starter_.uri.path = _starter_.path; + let introspector = _starter_.introspector = _starter_.introspector || Object.create( null ); + let error = _starter_.error = _starter_.error || Object.create( null ); + let setup = _starter_.setup = _starter_.setup || Object.create( null ); + let event = _starter_.event = _starter_.event || Object.create( null ); + let sourcesMap = _starter_.sourcesMap = _starter_.sourcesMap || Object.create( null ); + let requireCache = _starter_.requireCache = _starter_.requireCache || Object.create( null ); + let moduleMainFilesMap = _starter_.moduleMainFilesMap = _starter_.moduleMainFilesMap || Object.create( null ); + let color = _starter_.color = _starter_.color || Object.create( null ); + let colorRgba = _starter_.color.rgba = _starter_.color.rgba || Object.create( null ); + let Logger = _starter_.Logger = _starter_.Logger || Object.create( null ); + + let long = _starter_.long = _starter_.long || Object.create( null ); + let argumentsArray = _starter_.argumentsArray = _starter_.argumentsArray || Object.create( null ); + let array = _starter_.array = _starter_.array || Object.create( null ); + let unroll = _starter_.unroll = _starter_.unroll || Object.create( null ); + let buffer = _starter_.buffer = _starter_.buffer || Object.create( null ); + let bufferRaw = _starter_.bufferRaw = _starter_.bufferRaw || Object.create( null ); + let bufferTyped = _starter_.bufferTyped = _starter_.bufferTyped || Object.create( null ); + let bufferNode = _starter_.bufferNode = _starter_.bufferNode || Object.create( null ); + let vector = _starter_.vector = _starter_.vector || Object.create( null ); + + let primitive = _starter_.primitive = _starter_.primitive || Object.create( null ); + let number = _starter_.number = _starter_.number || Object.create( null ); + let symbol = _starter_.symbol = _starter_.symbol || Object.create( null ); + let bool = _starter_.bool = _starter_.bool || Object.create( null ); + + let countable = _starter_.countable = _starter_.countable || Object.create( null ); + let constructible = _starter_.constructible = _starter_.constructible || Object.create( null ); + let aux = _starter_.aux = _starter_.aux || Object.create( null ); + let object = _starter_.object = _starter_.object || Object.create( null ); + let map = _starter_.map = _starter_.map || Object.create( null ); + let hashMap = _starter_.hashMap = _starter_.hashMap || Object.create( null ); + let props = _starter_.props = _starter_.props || Object.create( null ); + let set = _starter_.set = _starter_.set || Object.create( null ); + + let routine = _starter_.routine = _starter_.routine || Object.create( null ); + let routines = _starter_.routine.s = _starter_.routine.s || Object.create( null ); + let regexp = _starter_.regexp = _starter_.regexp || Object.create( null ); + + let container = _starter_.container = _starter_.container || Object.create( null ); + + // + + function assert( good ) + { + if( !good ) + { + throw new Error( 'Something wrong!' ); + return false; + } + return true; + } + + // + + function assertRoutineOptions() + { + return arguments[ 0 ]; + } + + // + + function assertMapHasOnly() + { + } + + // + + function assertMapHasNoUndefine() + { + } + + // + + function dir( filePath ) + { + let canonized = this.canonize( filePath ); + let splits = canonized.split( '/' ); + if( splits[ splits.length-1 ] ) + splits.pop(); + return splits.join( '/' ); + } + + // + + function nativize() + { + if( _global.process && _global.process.platform === 'win32' ) + this.nativize = this._nativizeWindows; + else + this.nativize = this._nativizePosix; + return this.nativize.apply( this, arguments ); + } + + // + + function toStr( src ) + { + try + { + return String( src ); + } + catch( err ) + { + return '{- UNKNOWN DATA TYPE -}'; + } + } + + // + + function mapFields( src ) + { + let result = Object.create( null ); + if( !src ) + return result; + for( let s in src ) + result[ s ] = src[ s ]; + return result; + } + // + // // + // + // ProcedureInit = function init( o ) + // { + // let procedure = this; + // + // // _.workpiece.initFields( procedure ); + // // Object.preventExtensions( procedure ); + // // procedure.copy( o ); + // _.props.extend( procedure, o ); + // + // _.assert( _.strIs( procedure._stack ) ); + // // _.assert( procedure._sourcePath === null ); + // + // procedure._sourcePath = procedure._stack.split( '\n' )[ 0 ]; + // + // procedure._longNameMake(); + // + // _.arrayAppendOnceStrictly( _.Procedure.InstancesArray, procedure ); + // + // _.assert( _.strIs( procedure._sourcePath ) ); + // _.assert( arguments.length === 1 ); + // // _.assert( _.Procedure.NamesMap[ procedure._longName ] === procedure, () => `${procedure._longName} not found` ); + // + // return procedure; + // }; + +; + + + let StarterExtension = + { + + assert, + assertRoutineOptions, + assertMapHasOnly, + assertMapHasNoUndefine, + toStr, + mapFields, + + path, + + } + + Object.assign( _starter_, StarterExtension ); + + let PathExtension = + { + + dir, + nativize, + + } + + Object.assign( _starter_.path, PathExtension ); + + // let ProcedureExtension = + // { + // + // ProcedureInit + // + // } + // + // Object.assign( _starter_.Procedure.prototype, PathExtension ); + +; + +/* */ /* end of early */ })(); + + +/* */ /* begin of extract */ ( function _extract_() { + + + + 'use strict'; + + const _global = _global_; + let _starter_ = _global_._starter_; + let _ = _starter_; + + let stackSymbol = Symbol.for( 'stack' ); + let _diagnosticCodeExecuting = 0; + // let notLongSymbol = Symbol.for( 'notLong' ); + let iteratorSymbol = Symbol.iterator; + + // let _errorCounter = 0; + // let _errorMaking = false; + let _ArrayIndexOf = Array.prototype.indexOf; + let _ArrayIncludes = Array.prototype.includes; + if( !_ArrayIncludes ) + _ArrayIncludes = function( e ){ _ArrayIndexOf.call( this, e ) } + +; + + + _.strQuote = function quote( o ) +{ + + if( !_.mapIs( o ) ) + o = { src : arguments[ 0 ], quote : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + if( o.quote === undefined || o.quote === null ) + o.quote = quote.defaults.quote; + _.map.assertHasOnly( o, quote.defaults ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( _.arrayIs( o.src ) ) + { + let result = []; + for( let s = 0 ; s < o.src.length ; s++ ) + result.push( _.strQuote({ src : o.src[ s ], quote : o.quote }) ); + return result; + } + + let src = o.src; + + if( !_.primitive.is( src ) ) + src = _.entity.exportString( src ); + + _.assert( _.primitive.is( src ) ); + + let result = o.quote + String( src ) + o.quote; + + return result; +} +_.strQuote.defaults = +{ "src" : null, "quote" : `"` } + +// + + + _.err = function err() +{ + return _._err + ({ + args : arguments, + level : 2, + }); +} + +// + + + _._err = function _err( o ) +{ + const exportString = _.entity.exportString ? _.entity.exportString.bind( _.entity ) : String; + let error; + + if( arguments.length !== 1 ) + throw Error( '_err : Expects single argument : options map' ); + + if( !_.mapIs( o ) ) + throw Error( '_err : Expects single argument : options map' ); + + if( !_.longIs( o.args ) ) + throw Error( '_err : Expects Long option::args' ); + + for( let e in o ) + { + if( _err.defaults[ e ] === undefined ) + { + debugger; + throw Error( `Unknown option::${e}` ); + } + } + + for( let e in _err.defaults ) + { + if( o[ e ] === undefined ) + o[ e ] = _err.defaults[ e ]; + } + + if( _.error._errorMaking ) + { + throw Error( 'Recursive dead lock because of error inside of routine _err()!' ); + } + _.error._errorMaking = true; + + if( o.level === undefined || o.level === null ) + o.level = null; + + /* let */ + + if( !o.message ) + o.message = ''; + let fallBackMessage = ''; + let errors = []; + let combinedStack = ''; + + /* algorithm */ + + try + { + + argumentsPreprocessArguments(); + argumentsPreprocessErrors(); + locationForm(); + stackAndErrorForm(); + attributesForm(); + catchesForm(); + sourceCodeForm(); + originalMessageForm(); + + error = _.error._make + ({ + error, + throwLocation : o.throwLocation, + sections : o.sections, + concealed : o.concealed, + exposed : o.exposed, + + attended : o.attended, + logged : o.logged, + brief : o.brief, + stackCondensing : o.stackCondensing, + + originalMessage : o.message, + combinedStack, + throwCallsStack : o.throwCallsStack, + throwsStack : o.throwsStack, + asyncCallsStack : o.asyncCallsStack, + sourceCode : o.sourceCode, + reason : o.reason, + }); + + } + catch( err2 ) + { + _.error._errorMaking = false; + console.log( err2.message ); + console.log( err2.stack ); + } + _.error._errorMaking = false; + + return error; + + /* */ + + function argumentsPreprocessArguments() + { + + for( let a = 0 ; a < o.args.length ; a++ ) + { + let arg = o.args[ a ]; + + if( !_.error.is( arg ) && _.routine.is( arg ) ) + { + if( arg.length === 0 ) + { + try + { + arg = o.args[ a ] = arg(); + } + catch( err ) + { + let original = arg; + arg = o.args[ a ] = 'Error throwen by callback for formatting of error string'; + console.error( String( err ) ); + if( _.strLinesSelect ) /* aaa : for Dmytro : make sure it works and cover */ /* Dmytro : works, covered. Test routine `_errWithArgsIncludedRoutine` */ + console.error( _.strLinesSelect + ({ + src : original.toString(), + line : 0, + nearestLines : 5, + numbering : 1, + })); + else + console.error( original.toString() ); + } + } + if( _.unrollIs( arg ) ) + { + debugger; + o.args = [ ... Array.prototype.slice.call( o.args, 0, a ), ... arg, ... Array.prototype.slice.call( o.args, a+1, o.args.length ) ]; + // o.args = _.longBut_( null, o.args, [ a, a ], arg ); + // o.args = _.longBut( o.args, [ a, a+1 ], arg ); + a -= 1; + continue; + } + } + + } + + } + + /* */ + + function argumentsPreprocessErrors() + { + + for( let a = 0 ; a < o.args.length ; a++ ) + { + let arg = o.args[ a ]; + + if( _.error.is( arg ) ) + { + + errProcess( arg ); + o.args[ a ] = _.error.originalMessage( arg ) + + } + else if( _.strIs( arg ) && _.error._inStr( arg ) ) + { + + let err = _.error.fromStr( arg ); + errProcess( err ); + o.args[ a ] = _.error.originalMessage( err ); + + } + + } + + } + + /* */ + + function errProcess( arg ) + { + + if( !error ) + { + error = arg; + if( !o.sourceCode ) + o.sourceCode = arg.sourceCode || null; + if( o.attended === null ) + o.attended = arg.attended || false; + if( o.logged === null ) + o.logged = arg.logged || false; + } + + if( arg.throwCallsStack ) + if( !o.throwCallsStack ) + o.throwCallsStack = arg.throwCallsStack; + + // if( arg.asyncCallsStack ) + // if( !o.asyncCallsStack ) + // o.asyncCallsStack = arg.asyncCallsStack; + + if( arg.throwsStack ) + if( o.throwsStack ) + o.throwsStack += '\n' + arg.throwsStack; + else + o.throwsStack = arg.throwsStack; + + if( arg.constructor ) + fallBackMessage = fallBackMessage || arg.constructor.name; + errors.push( arg ); + + } + + /* */ + + function locationForm() + { + + if( !error ) + for( let a = 0 ; a < o.args.length ; a++ ) + { + let arg = o.args[ a ]; + if( !_.primitive.is( arg ) && _.object.like( arg ) ) + try + { + o.throwLocation = _.introspector.location + ({ + error : arg, + location : o.throwLocation, + }); + } + catch( err2 ) + { + console.error( err2 ); + } + } + + o.throwLocation = o.throwLocation || Object.create( null ); + o.catchLocation = o.catchLocation || Object.create( null ); + + } + + /* */ + + function stackAndErrorForm() + { + + if( error ) + { + + /* qqq : cover each if-branch. ask how to. *difficult problem* */ + + if( !o.throwCallsStack ) + if( o.throwLocation ) + o.throwCallsStack = _.introspector.locationToStack( o.throwLocation ); + if( !o.throwCallsStack ) + o.throwCallsStack = _.error.originalStack( error ); + if( !o.throwCallsStack ) + o.throwCallsStack = _.introspector.stack([ ( o.level || 0 ) + 1, Infinity ]); + + if( !o.catchCallsStack && o.catchLocation ) + o.catchCallsStack = _.introspector.locationToStack( o.catchLocation ); + if( !o.catchCallsStack ) + o.catchCallsStack = _.introspector.stack( o.catchCallsStack, [ ( o.level || 0 ) + 1, Infinity ] ); + + if( !o.throwCallsStack && o.catchCallsStack ) + o.throwCallsStack = o.catchCallsStack; + if( !o.throwCallsStack ) + o.throwCallsStack = _.introspector.stack( error, [ ( o.level || 0 ) + 1, Infinity ] ); + + o.level = 0; + + } + else + { + + error = new Error( o.message + '\n' ); + if( o.throwCallsStack ) + { + error.stack = o.throwCallsStack; + o.catchCallsStack = _.introspector.stack( o.catchCallsStack, [ o.level + 1, Infinity ] ); + o.level = 0; + } + else + { + if( o.catchCallsStack ) + { + o.throwCallsStack = error.stack = o.catchCallsStack; + } + else + { + if( o.level === undefined || o.level === null ) + o.level = 1; + o.level += 1; + o.throwCallsStack = error.stack = _.introspector.stack( error.stack, [ o.level, Infinity ] ); + } + o.level = 0; + if( !o.catchCallsStack ) + o.catchCallsStack = o.throwCallsStack; + } + + } + + _.assert( o.level === 0 ); + + if( ( o.stackRemovingBeginIncluding || o.stackRemovingBeginExcluding ) && o.throwCallsStack ) + o.throwCallsStack = _.introspector.stackRemoveLeft + ( + o.throwCallsStack, o.stackRemovingBeginIncluding || null, o.stackRemovingBeginExcluding || null + ); + + if( !o.throwCallsStack ) + o.throwCallsStack = error.stack = o.fallBackStack; + + combinedStack = o.throwCallsStack; + + _.assert + ( + error.asyncCallsStack === undefined + || error.asyncCallsStack === null + || error.asyncCallsStack === '' + || _.arrayIs( error.asyncCallsStack ) + ); + if( error.asyncCallsStack && error.asyncCallsStack.length ) + { + o.asyncCallsStack = o.asyncCallsStack || []; + o.asyncCallsStack.push( ... error.asyncCallsStack ); + // _.arrayAppendArray( o.asyncCallsStack, error.asyncCallsStack ); + } + + if( o.asyncCallsStack === null || o.asyncCallsStack === undefined ) + if( _.Procedure && _.Procedure.ActiveProcedure ) + o.asyncCallsStack = [ _.Procedure.ActiveProcedure.stack() ]; + + _.assert( o.asyncCallsStack === null || _.arrayIs( o.asyncCallsStack ) ); + if( o.asyncCallsStack && o.asyncCallsStack.length ) + { + combinedStack += '\n\n' + o.asyncCallsStack.join( '\n\n' ); + } + + _.assert( _.strIs( combinedStack ) ); + if( o.stackCondensing ) + combinedStack = _.introspector.stackCondense( combinedStack ); + + } + + /* */ + + function attributesForm() + { + + try + { + o.catchLocation = _.introspector.location + ({ + stack : o.catchCallsStack, + location : o.catchLocation, + }); + } + catch( err2 ) + { + console.error( err2 ); + } + + try + { + o.throwLocation = _.introspector.location + ({ + error : error, + stack : o.throwCallsStack, + location : o.throwLocation, + }); + } + catch( err2 ) + { + console.error( err2 ); + } + + } + + /* */ + + function catchesForm() + { + + if( o.throws ) + { + _.assert( _.arrayIs( o.throws ) ); + o.throws.forEach( ( c ) => + { + c = _.introspector.locationFromStackFrame( c ).routineFilePathLineCol; + if( o.throwsStack ) + o.throwsStack += `\nthrown at ${c}`; + else + o.throwsStack = `thrown at ${c}`; + }); + } + + _.assert( _.number.is( o.catchLocation.abstraction ) ); + if( !o.catchLocation.abstraction || o.catchLocation.abstraction === 1 ) + { + if( o.throwsStack ) + o.throwsStack += `\nthrown at ${o.catchLocation.routineFilePathLineCol}`; + else + o.throwsStack = `thrown at ${o.catchLocation.routineFilePathLineCol}`; + } + + } + + /* */ + + function sourceCodeForm() + { + + if( !o.usingSourceCode ) + return; + + if( o.sourceCode ) + return; + + if( error.sourceCode === undefined ) + { + let c = _.introspector.code + ({ + location : o.throwLocation, + sourceCode : o.sourceCode, + asMap : 1, + }); + if( c && c.code && c.code.length < 400 ) + { + o.sourceCode = c; + } + } + + } + + /* */ + + function originalMessageForm() + { + let result = []; + + if( o.message ) + return; + + for( let a = 0 ; a < o.args.length ; a++ ) + { + let arg = o.args[ a ]; + let str; + + if( arg && !_.primitive.is( arg ) ) + { + + if( _.routine.is( arg.toStr ) ) + { + str = arg.toStr(); + } + else if( _.error.is( arg ) && _.strIs( arg.originalMessage ) ) + { + str = arg.originalMessage; + } + else if( _.error.is( arg ) ) + { + if( _.strIs( arg.message ) ) + str = arg.message; + else + str = exportString( arg ); + } + else + { + str = exportString( arg, { levels : 2 } ); + } + } + else if( arg === undefined ) + { + str = '\n' + String( arg ) + '\n'; + } + else + { + str = String( arg ); + } + + result[ a ] = str; + + } + + let o2 = + { + onToStr : eachMessageFormat, + onPairWithDelimeter : strConcatenateCounting + }; + o.message = _.strConcat( result, o2 ); + + /* + remove redundant spaces at the begin and the end of lines + */ + + o.message = o.message || fallBackMessage || 'UnknownError'; + o.message = o.message.replace( /^\s*/, '' ); + o.message = o.message.replace( /\x20*$/gm, '' ); + o.message = o.message.replace( /\s*$/, '' ); + + } + + /* */ + + function eachMessageFormat( str ) + { + let strBeginsWithRegular = _.strBegins( str, /\S/ ); + let strEndsWithRegular = _.strEnds( str, /\S/ ); + + if( !strBeginsWithRegular ) + { + let notSpaceLikeSymbol = /\S/.exec( str ); + + if( notSpaceLikeSymbol === null ) + { + str = str.replace( /\x20+/g, '' ); + strEndsWithRegular = true; + } + else + { + let before = str.substring( 0, notSpaceLikeSymbol.index ); + let spaces = /(?<=\n)\x20+$/.exec( before ); + before = before.replace( /\x20+/g, '' ); + before += spaces ? spaces[ 0 ] : ''; + + str = before + str.substring( notSpaceLikeSymbol.index ); + } + } + + if( str && !strEndsWithRegular ) + { + let notSpaceLikeSymbol = /\S\s*$/.exec( str ); + + let after = str.substring( notSpaceLikeSymbol.index + 1 ); + let spaces = /^\x20+(?=\n)/.exec( after ); + after = after.replace( /\x20+/g, '' ); + after += spaces ? spaces[ 0 ] : ''; + + str = str.substring( 0, notSpaceLikeSymbol.index + 1 ) + after; + } + + return str; + } + + /* */ + + function strConcatenateCounting( src1, src2 ) + { + let result; + if( _.strEnds( src1, '\n' ) && _.strBegins( src2, '\n' ) ) + { + let right = /\n+$/.exec( src1 ); + let left = /^\n+/.exec( src2 ); + + result = src1.substring( 0, right.index ); + result += right[ 0 ].length > left[ 0 ].length ? right[ 0 ] : left[ 0 ]; + result += src2.substring( left[ 0 ].length ); + } + else + { + result = src1 + src2; + } + return result; + } +} +_._err.defaults = +{ + "args" : null, + "sections" : null, + "concealed" : null, + "exposed" : null, + "level" : 1, + "message" : null, + "reason" : null, + "sourceCode" : null, + "stackRemovingBeginIncluding" : 0, + "stackRemovingBeginExcluding" : 0, + "usingSourceCode" : 1, + "stackCondensing" : 1, + "attended" : null, + "logged" : null, + "brief" : null, + "throwLocation" : null, + "catchLocation" : null, + "asyncCallsStack" : null, + "throwCallsStack" : null, + "catchCallsStack" : null, + "fallBackStack" : null, + "throwsStack" : ``, + "throws" : null +} + +// + + + _._errMake = function _make( o ) +{ + const logger = _global_.logger || _global_.console; + + if( arguments.length !== 1 ) + throw Error( 'Expects single argument : options map' ); + + if( !_.mapIs( o ) ) + throw Error( 'Expects single argument : options map' ); + + for( let k in o ) + { + if( _make.defaults[ k ] === undefined ) + throw Error( `Unknown option::${k}` ); + } + + for( let k in _.error._make.defaults ) + { + if( o[ k ] === undefined ) + o[ k ] = _.error._make.defaults[ k ]; + } + + if( !_.error.is( o.error ) ) + throw Error( 'Expects option.error:Error' ); + + if( !_.strIs( o.originalMessage ) ) + throw Error( 'Expects option.originalMessage:String' ); + + if( !_.strIs( o.combinedStack ) ) + throw Error( 'Expects option.combinedStack:String' ); + + if( !_.strIs( o.throwCallsStack ) ) + throw Error( 'Expects option.throwCallsStack:String' ); + + if( !_.strIs( o.throwsStack ) ) + throw Error( 'Expects option.throwsStack:String' ); + + if( !o.throwLocation ) + throw Error( 'Expects option.throwLocation:Location' ); + + attributesForm(); + exposedForm(); + sectionsForm(); + _.error._messageForm( o ); + form(); + + return o.error; + + /* */ + + function attributesForm() + { + + if( o.attended === null || o.attended === undefined ) + o.attended = o.error.attended; + o.attended = !!o.attended; + + if( o.logged === null || o.logged === undefined ) + o.logged = o.error.logged; + o.logged = !!o.logged; + + if( o.brief === null || o.brief === undefined ) + o.brief = o.error.brief; + o.brief = !!o.brief; + + if( o.reason === null || o.reason === undefined ) + o.reason = o.error.reason; + + o.sections = o.sections || Object.create( null ); + if( o.error.section ) + _.props.supplement( o.sections, o.error.section ); + + o.id = o.error.id; + if( !o.id ) + { + _.error._errorCounter += 1; + o.id = _.error._errorCounter; + } + + } + + /* */ + + function exposedForm() + { + var has = false; + for( let k in o.error ) + { + has = true; + break; + } + if( has ) + { + if( o.exposed ) + { + for( let k in o.error ) + if( !Reflect.has( o.exposed, k ) ) + o.exposed[ k ] = o.error[ k ]; + } + else + { + o.exposed = Object.create( null ); + for( let k in o.error ) + o.exposed[ k ] = o.error[ k ]; + } + } + } + + /* */ + + function sectionsForm() + { + let result = ''; + + // sectionAdd( 'message', `Message of Error#${o.id}`, o.originalMessage ); + sectionAdd( 'message', `Message of ${o.error.name || 'error'}#${o.id}`, o.originalMessage ); + sectionAdd( 'combinedStack', o.stackCondensing ? 'Beautified calls stack' : 'Calls stack', o.combinedStack ); + sectionAdd( 'throwsStack', `Throws stack`, o.throwsStack ); + + /* xxx : postpone */ + if( o.sourceCode ) + if( _.strIs( o.sourceCode ) ) + sectionAdd( 'sourceCode', `Source code`, o.sourceCode ); + else if( _.routine.is( o.sourceCode.read ) ) + sectionAdd( 'sourceCode', `Source code from ${o.sourceCode.path}`, o.sourceCode.read ); + else if( _.strIs( o.sourceCode.code ) ) + sectionAdd( 'sourceCode', `Source code from ${o.sourceCode.path}`, o.sourceCode.code ); + else + console.error( 'Unknown format of {- o.sourceCode -}' ); + + if( o.exposed && Object.keys( o.exposed ).length > 0 ) + _.error._sectionExposedAdd( o ); + + for( let s in o.sections ) + { + let section = o.sections[ s ]; + if( !_.strIs( section.head ) ) + { + logger.error + ( + `Each section of an error should have head, but head of section::${s} is ${_.entity.strType(section.head)}` + ); + delete o.sections[ s ]; + } + if( !_.strIs( section.body ) ) + { + logger.error + ( + `Each section of an error should have body, but body of section::${s} is ${_.entity.strType(section.body)}` + ); + delete o.sections[ s ]; + } + } + + return result; + } + + /* */ + + function sectionAdd( name, head, body ) + { + _.error._sectionAdd({ name, head, body, sections : o.sections }); + } + + /* */ + + function form() + { + + nonenumerable( 'originalMessage', o.originalMessage ); + logging( 'stack' ); + nonenumerable( 'reason', o.reason ); + + nonenumerable( 'combinedStack', o.combinedStack ); + nonenumerable( 'throwCallsStack', o.throwCallsStack ); + nonenumerable( 'asyncCallsStack', o.asyncCallsStack ); + nonenumerable( 'throwsStack', o.throwsStack ); + nonenumerable( 'catchCounter', o.error.catchCounter ? o.error.catchCounter+1 : 1 ); + + nonenumerable( 'attended', o.attended ); + nonenumerable( 'logged', o.logged ); + nonenumerable( 'brief', o.brief ); + + if( o.throwLocation.line !== undefined ) + nonenumerable( 'lineNumber', o.throwLocation.line ); + if( o.error.throwLocation === undefined ) + nonenumerable( 'location', o.throwLocation ); + nonenumerable( 'sourceCode', o.sourceCode || null ); + nonenumerable( 'id', o.id ); + + nonenumerable( 'toString', function() { return this.stack } ); + nonenumerable( 'sections', o.sections ); + + getter( 'name', function() { return this.constructor.name } ); + + o.error[ Symbol.for( 'nodejs.util.inspect.custom' ) ] = o.error.toString; + + if( o.concealed ) + { + for( let k in o.concealed ) + nonenumerable( k, o.concealed[ k ] ); + } + + } + + /* */ + + function nonenumerable( propName, value ) + { + try + { + let o2 = + { + enumerable : false, + configurable : true, + writable : true, + value, + }; + Object.defineProperty( o.error, propName, o2 ); + } + catch( err2 ) + { + console.error( err2 ); + } + } + + /* */ + + function getter( propName, get ) + { + try + { + let o2 = + { + enumerable : false, + configurable : true, + get, + }; + Object.defineProperty( o.error, propName, o2 ); + } + catch( err2 ) + { + console.error( err2 ); + } + } + + /* */ + + function logging( propName ) + { + try + { + let o2 = + { + enumerable : false, + configurable : true, + get, + set, + }; + Object.defineProperty( o.error, propName, o2 ); + } + catch( err2 ) + { + console.error( err2 ); + } + function get() + { + /* + workaround to avoid Njs issue: Njs stingify inherited error + */ + /* zzz : qqq : find better solution */ + if( ( new Error().stack ).split( '\n' ).length !== 3 ) + { + _.error.logged( this ); + _.error.attend( this ); + } + return this.message; + } + function set( src ) + { + this.message = src; + return src; + } + } + +} +_._errMake.defaults = +{ + "error" : null, + "id" : null, + "throwLocation" : null, + "sections" : null, + "concealed" : null, + "exposed" : null, + "attended" : null, + "logged" : null, + "brief" : null, + "stackCondensing" : null, + "originalMessage" : null, + "combinedStack" : ``, + "throwCallsStack" : ``, + "throwsStack" : ``, + "asyncCallsStack" : ``, + "sourceCode" : null, + "reason" : null +} + +// + + + _.errLogged = function logged( err, value ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + if( value === undefined ) + value = Config.debug ? _.introspector.stack([ 0, Infinity ]) : true; + // console.log( `logged ${value}` ); + return _.error.concealedSet( err, { logged : value } ); +} + +// + + + _.errAttend = function attend( err, value ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + if( value === undefined ) + value = Config.debug ? _.introspector.stack([ 0, Infinity ]) : true; + let result = _.error.concealedSet( err, { attended : value } ); + return result; +} + +// + + + _.errProcess = function process( err ) +{ + + if( arguments.length !== 1 || !_.error.isFormed( err ) ) + err = _.err( ... arguments ); + + if( _.process && _.process.entryPointInfo ) + { + let body = _.process.entryPointInfo(); + if( body ) + _.error.sectionAdd( err, { name : 'process', body }); + } + + return err; +} + +// + + + _.assert = function assert( condition, ... args ) +{ + + if( Config.debug === false ) + return true; + + if( condition !== true ) + { + _assertDebugger( condition, arguments ); + if( !_._err ) + throw Error( ... args ); + if( arguments.length === 1 ) + throw _._err + ({ + args : [ 'Assertion fails' ], + level : 2, + }); + else if( arguments.length === 2 ) + throw _._err + ({ + args : [ arguments[ 1 ] ], + level : 2, + }); + else + throw _._err + ({ + args : Array.prototype.slice.call( arguments, 1 ), + level : 2, + }); + } + + return true; + + function _assertDebugger( condition, args ) + { + if( !_.error.breakpointOnAssertEnabled ) + return; + debugger; /* eslint-disable-line no-debugger */ + } + +} + +// + + + + _.error.isFormed = function isFormed( src ) +{ + if( !_.error.is( src ) ) + return false; + return src.originalMessage !== undefined; +} + +// + + + _.error.isAttended = function isAttended( src ) +{ + if( !_.error.is( src ) ) + return false; + return !!src.attended; +} + +// + + + _.error.originalMessage = function originalMessage( err ) +{ + + if( arguments.length !== 1 ) + throw Error( 'error.originalMessage : Expects single argument' ); + + if( _.strIs( err ) ) + return err; + + if( !err ) + return; + + if( err.originalMessage ) + return err.originalMessage; + + let message = err.message; + + if( !message && message !== '' ) + message = err.msg; + if( !message && message !== '' ) + message = err.name; + + return message; +} + +// + + + _.error.originalStack = function originalStack( err ) +{ + + if( arguments.length !== 1 ) + throw Error( 'error.originalStack : Expects single argument' ); + + if( !_.error.is( err ) ) + throw Error( 'error.originalStack : Expects error' ); + + if( err.throwCallsStack ) + return err.throwCallsStack; + + if( err.combinedStack ) + return err.combinedStack; + + if( err[ stackSymbol ] ) + return err[ stackSymbol ]; + + if( err.stack ) + return _.introspector.stack( err.stack ); + + /* should return null if nothing found */ + return null; +} + +// + + + /* _.error.set = undefined; + +// + + // Dmytro : routine does not exist exposedSet and concealedSet are used instead */ + _.error.is = function is( src ) +{ + return src instanceof Error || Object.prototype.toString.call( src ) === '[object Error]'; +} + +// + + + _.error._make = function _make( o ) +{ + const logger = _global_.logger || _global_.console; + + if( arguments.length !== 1 ) + throw Error( 'Expects single argument : options map' ); + + if( !_.mapIs( o ) ) + throw Error( 'Expects single argument : options map' ); + + for( let k in o ) + { + if( _make.defaults[ k ] === undefined ) + throw Error( `Unknown option::${k}` ); + } + + for( let k in _.error._make.defaults ) + { + if( o[ k ] === undefined ) + o[ k ] = _.error._make.defaults[ k ]; + } + + if( !_.error.is( o.error ) ) + throw Error( 'Expects option.error:Error' ); + + if( !_.strIs( o.originalMessage ) ) + throw Error( 'Expects option.originalMessage:String' ); + + if( !_.strIs( o.combinedStack ) ) + throw Error( 'Expects option.combinedStack:String' ); + + if( !_.strIs( o.throwCallsStack ) ) + throw Error( 'Expects option.throwCallsStack:String' ); + + if( !_.strIs( o.throwsStack ) ) + throw Error( 'Expects option.throwsStack:String' ); + + if( !o.throwLocation ) + throw Error( 'Expects option.throwLocation:Location' ); + + attributesForm(); + exposedForm(); + sectionsForm(); + _.error._messageForm( o ); + form(); + + return o.error; + + /* */ + + function attributesForm() + { + + if( o.attended === null || o.attended === undefined ) + o.attended = o.error.attended; + o.attended = !!o.attended; + + if( o.logged === null || o.logged === undefined ) + o.logged = o.error.logged; + o.logged = !!o.logged; + + if( o.brief === null || o.brief === undefined ) + o.brief = o.error.brief; + o.brief = !!o.brief; + + if( o.reason === null || o.reason === undefined ) + o.reason = o.error.reason; + + o.sections = o.sections || Object.create( null ); + if( o.error.section ) + _.props.supplement( o.sections, o.error.section ); + + o.id = o.error.id; + if( !o.id ) + { + _.error._errorCounter += 1; + o.id = _.error._errorCounter; + } + + } + + /* */ + + function exposedForm() + { + var has = false; + for( let k in o.error ) + { + has = true; + break; + } + if( has ) + { + if( o.exposed ) + { + for( let k in o.error ) + if( !Reflect.has( o.exposed, k ) ) + o.exposed[ k ] = o.error[ k ]; + } + else + { + o.exposed = Object.create( null ); + for( let k in o.error ) + o.exposed[ k ] = o.error[ k ]; + } + } + } + + /* */ + + function sectionsForm() + { + let result = ''; + + // sectionAdd( 'message', `Message of Error#${o.id}`, o.originalMessage ); + sectionAdd( 'message', `Message of ${o.error.name || 'error'}#${o.id}`, o.originalMessage ); + sectionAdd( 'combinedStack', o.stackCondensing ? 'Beautified calls stack' : 'Calls stack', o.combinedStack ); + sectionAdd( 'throwsStack', `Throws stack`, o.throwsStack ); + + /* xxx : postpone */ + if( o.sourceCode ) + if( _.strIs( o.sourceCode ) ) + sectionAdd( 'sourceCode', `Source code`, o.sourceCode ); + else if( _.routine.is( o.sourceCode.read ) ) + sectionAdd( 'sourceCode', `Source code from ${o.sourceCode.path}`, o.sourceCode.read ); + else if( _.strIs( o.sourceCode.code ) ) + sectionAdd( 'sourceCode', `Source code from ${o.sourceCode.path}`, o.sourceCode.code ); + else + console.error( 'Unknown format of {- o.sourceCode -}' ); + + if( o.exposed && Object.keys( o.exposed ).length > 0 ) + _.error._sectionExposedAdd( o ); + + for( let s in o.sections ) + { + let section = o.sections[ s ]; + if( !_.strIs( section.head ) ) + { + logger.error + ( + `Each section of an error should have head, but head of section::${s} is ${_.entity.strType(section.head)}` + ); + delete o.sections[ s ]; + } + if( !_.strIs( section.body ) ) + { + logger.error + ( + `Each section of an error should have body, but body of section::${s} is ${_.entity.strType(section.body)}` + ); + delete o.sections[ s ]; + } + } + + return result; + } + + /* */ + + function sectionAdd( name, head, body ) + { + _.error._sectionAdd({ name, head, body, sections : o.sections }); + } + + /* */ + + function form() + { + + nonenumerable( 'originalMessage', o.originalMessage ); + logging( 'stack' ); + nonenumerable( 'reason', o.reason ); + + nonenumerable( 'combinedStack', o.combinedStack ); + nonenumerable( 'throwCallsStack', o.throwCallsStack ); + nonenumerable( 'asyncCallsStack', o.asyncCallsStack ); + nonenumerable( 'throwsStack', o.throwsStack ); + nonenumerable( 'catchCounter', o.error.catchCounter ? o.error.catchCounter+1 : 1 ); + + nonenumerable( 'attended', o.attended ); + nonenumerable( 'logged', o.logged ); + nonenumerable( 'brief', o.brief ); + + if( o.throwLocation.line !== undefined ) + nonenumerable( 'lineNumber', o.throwLocation.line ); + if( o.error.throwLocation === undefined ) + nonenumerable( 'location', o.throwLocation ); + nonenumerable( 'sourceCode', o.sourceCode || null ); + nonenumerable( 'id', o.id ); + + nonenumerable( 'toString', function() { return this.stack } ); + nonenumerable( 'sections', o.sections ); + + getter( 'name', function() { return this.constructor.name } ); + + o.error[ Symbol.for( 'nodejs.util.inspect.custom' ) ] = o.error.toString; + + if( o.concealed ) + { + for( let k in o.concealed ) + nonenumerable( k, o.concealed[ k ] ); + } + + } + + /* */ + + function nonenumerable( propName, value ) + { + try + { + let o2 = + { + enumerable : false, + configurable : true, + writable : true, + value, + }; + Object.defineProperty( o.error, propName, o2 ); + } + catch( err2 ) + { + console.error( err2 ); + } + } + + /* */ + + function getter( propName, get ) + { + try + { + let o2 = + { + enumerable : false, + configurable : true, + get, + }; + Object.defineProperty( o.error, propName, o2 ); + } + catch( err2 ) + { + console.error( err2 ); + } + } + + /* */ + + function logging( propName ) + { + try + { + let o2 = + { + enumerable : false, + configurable : true, + get, + set, + }; + Object.defineProperty( o.error, propName, o2 ); + } + catch( err2 ) + { + console.error( err2 ); + } + function get() + { + /* + workaround to avoid Njs issue: Njs stingify inherited error + */ + /* zzz : qqq : find better solution */ + if( ( new Error().stack ).split( '\n' ).length !== 3 ) + { + _.error.logged( this ); + _.error.attend( this ); + } + return this.message; + } + function set( src ) + { + this.message = src; + return src; + } + } + +} +_.error._make.defaults = +{ + "error" : null, + "id" : null, + "throwLocation" : null, + "sections" : null, + "concealed" : null, + "exposed" : null, + "attended" : null, + "logged" : null, + "brief" : null, + "stackCondensing" : null, + "originalMessage" : null, + "combinedStack" : ``, + "throwCallsStack" : ``, + "throwsStack" : ``, + "asyncCallsStack" : ``, + "sourceCode" : null, + "reason" : null +} + +// + + + _.error._sectionAdd = function _sectionAdd( o ) +{ + + if( Config.debug ) + for( let k in _sectionAdd.defaults ) + { + if( o[ k ] === undefined ) + throw Error( `Expects defined option::${k}` ); + } + + let section = Object.create( null ); + section.name = o.name; + section.head = o.head; + section.body = o.body; + o.sections[ o.name ] = section; + return section; +} +_.error._sectionAdd.defaults = +{ + "sections" : null, + "name" : null, + "head" : null, + "body" : null +} + +// + + + _.error._sectionExposedAdd = function _sectionExposedAdd( o ) +{ + const exportString = _.entity.exportString ? _.entity.exportString.bind( _.entity ) : String; + + if( Config.debug ) + for( let k in _sectionExposedAdd.defaults ) + { + if( o[ k ] === undefined ) + throw Error( `Expects defined option::${k}` ); + } + + let i = 0; + let body = ''; + for( let k in o.exposed ) + { + if( i > 0 ) + body += `\n`; + body += `${k} : ${exportString( o.exposed[ k ] )}`; + i += 1; + } + + _.error._sectionAdd + ({ + sections : o.sections, + name : 'exposed', + head : 'Exposed', + body, + }); +} +_.error._sectionExposedAdd.defaults = +{ "sections" : null, "exposed" : null } + +// + + + _.error._messageForm = function _messageForm( o ) +{ + + o.message = o.message || ''; + + if( !_.strIs( o.originalMessage ) ) + throw 'Expects string {- o.originalMessage -}'; + + // _.map.assertHasAll( o, _messageForm.defaults ); + + if( Config.debug ) + for( let k in _messageForm.defaults ) + { + if( o[ k ] === undefined ) + throw Error( `Expects defined option::${k}` ); + } + + if( o.brief ) + { + o.message += o.originalMessage; + } + else + { + o.message = _.error._sectionsJoin( o ); + } + + if( o.error ) + nonenumerable( 'message', o.message ); + + return o.message; + + /* */ + + function nonenumerable( propName, value ) + { + try + { + let o2 = + { + enumerable : false, + configurable : true, + writable : true, + value, + }; + Object.defineProperty( o.error, propName, o2 ); + } + catch( err2 ) + { + console.error( err2 ); + } + } + +} +_.error._messageForm.defaults = +{ + "error" : null, + "sections" : null, + "brief" : false, + "message" : `` +} + +// + + + _.error._sectionsJoin = function _sectionsJoin( o ) +{ + o.message = o.message || ''; + + // _.map.assertHasAll( o, _sectionsJoin.defaults ); + + if( Config.debug ) + for( let k in _sectionsJoin.defaults ) + { + if( o[ k ] === undefined ) + throw Error( `Expects defined option::${k}` ); + } + + for( let s in o.sections ) + { + let section = o.sections[ s ]; + let head = section.head || ''; + let body = strLinesIndentation( section.body, ' ' ); + if( !body.trim().length ) + continue; + o.message += ` = ${head}\n${body}\n\n`; + } + + return o.message; + + function strLinesIndentation( str, indentation ) + { + if( _.strLinesIndentation ) + return indentation + _.strLinesIndentation( str, indentation ); + else + return str; + } + +} +_.error._sectionsJoin.defaults = +{ "sections" : null, "message" : `` } + +// + + + _.error._inStr = function _inStr( errStr ) +{ + _.assert( _.strIs( errStr ) ); + + if( !_.strHas( errStr, /\=\s+Message of/m ) ) + return false; + + if( !_.strHas( errStr, /(^|\n)\s*=\s+Beautified calls stack/m ) ) + return false; + + return true; +} + +// + + + _.error.fromStr = function fromStr( errStr ) +{ + + try + { + + errStr = _.str.lines.strip( errStr ); + + let sectionBeginRegexp = /[=]\s+(.*?)\s*\n/mg; + let splits = _.strSplitFast + ({ + src : errStr, + delimeter : sectionBeginRegexp, + }); + + let sectionName; + let throwCallsStack = ''; + let throwsStack = ''; + let stackCondensing = true; + let messages = []; + for( let s = 0 ; s < splits.length ; s++ ) + { + let split = splits[ s ]; + let sectionNameParsed = sectionBeginRegexp.exec( split + '\n' ); + if( sectionNameParsed ) + { + sectionName = sectionNameParsed[ 1 ]; + continue; + } + + if( !sectionName ) + messages.push( split ); + else if( !sectionName || _.strBegins( sectionName, 'Message of' ) ) + messages.push( split ); + else if( _.strBegins( sectionName, 'Beautified calls stack' ) ) + throwCallsStack = split; + else if( _.strBegins( sectionName, 'Throws stack' ) ) + throwsStack = split; + + } + + let error = new Error(); + + let throwLocation = _.introspector.locationFromStackFrame( throwCallsStack || error.stack ); + + let originalMessage = messages.join( '\n' ); + + let result = _.error._make + ({ + error, + throwLocation, + stackCondensing, + originalMessage, + combinedStack : throwCallsStack, + throwCallsStack, + throwsStack, + }); + + return result; + } + catch( err2 ) + { + console.error( err2 ); + return Error( errStr ); + } +} + +// + + + _.error.logged = function logged( err, value ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + if( value === undefined ) + value = Config.debug ? _.introspector.stack([ 0, Infinity ]) : true; + // console.log( `logged ${value}` ); + return _.error.concealedSet( err, { logged : value } ); +} + +// + + + _.error.attend = function attend( err, value ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + if( value === undefined ) + value = Config.debug ? _.introspector.stack([ 0, Infinity ]) : true; + let result = _.error.concealedSet( err, { attended : value } ); + return result; +} + +// + + + _.error.exposedSet = function exposedSet( args, props ) +{ + + _.assert( arguments.length === 2 ); + _.assert( _.mapIs( props ) ) + + if( !_.longIs( args ) ) + args = [ args ]; + + let err = args[ 0 ]; + + if( _.symbol.is( err ) ) + { + _.assert( args.length === 1 ); + return err; + } + + if( args.length !== 1 || !_.error.isFormed( err ) ) + err = _._err + ({ + args, + level : 2, + }); + + /* */ + + try + { + + for( let f in props ) + { + err[ f ] = props[ f ]; + } + + } + catch( err ) + { + if( Config.debug ) + console.error( `Cant assign "${f}" property to error\n${err.toString()}` ); + } + + /* */ + + return err; +} + +// + + + _.error.concealedSet = function concealedSet( args, props ) +{ + + _.assert( arguments.length === 2 ); + _.assert( _.mapIs( props ) ) + + if( !_.longIs( args ) ) + args = [ args ]; + + let err = args[ 0 ]; + + if( _.symbol.is( err ) ) + { + _.assert( args.length === 1 ); + return err; + } + + if( args.length !== 1 || !_.error.isFormed( err ) ) + err = _._err + ({ + args, + level : 2, + }); + + /* */ + + try + { + + for( let f in props ) + { + let o = + { + enumerable : false, + configurable : true, + writable : true, + value : props[ f ], + }; + Object.defineProperty( err, f, o ); + } + + } + catch( err ) + { + if( Config.debug ) + console.error( `Cant assign "${f}" property to error\n${err.toString()}` ); + } + + /* */ + + return err; +} + +// + + + _.error.process = function process( err ) +{ + + if( arguments.length !== 1 || !_.error.isFormed( err ) ) + err = _.err( ... arguments ); + + if( _.process && _.process.entryPointInfo ) + { + let body = _.process.entryPointInfo(); + if( body ) + _.error.sectionAdd( err, { name : 'process', body }); + } + + return err; +} + +// + + + + + + _.date.is = function is( src ) +{ + return Object.prototype.toString.call( src ) === '[object Date]'; +} + +// + + + + _.introspector.code = function code( o ) +{ + + _.routine.options( code, o ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( _diagnosticCodeExecuting ) + return; + _diagnosticCodeExecuting += 1; + + try + { + + if( !o.location ) + { + if( o.error ) + o.location = _.introspector.location({ error : o.error, level : o.level }); + else + o.location = _.introspector.location({ stack : o.stack, level : o.stack ? o.level : o.level+1 }); + } + + if( !_.number.is( o.location.line ) ) + return end(); + + /* */ + + if( !o.sourceCode ) + { + + if( !o.location.filePath ) + return end(); + + let codeProvider = _.codeProvider || _.fileProvider; + if( !codeProvider && _globals_.testing && _globals_.testing.wTools ) + codeProvider = _globals_.testing.wTools.codeProvider || _globals_.testing.wTools.fileProvider; + + if( !codeProvider ) + return end(); + + try + { + + let filePath = codeProvider.path.normalizeTolerant( o.location.filePath ); + if( codeProvider.path.isAbsolute( filePath ) ) + o.sourceCode = read( codeProvider, filePath ); + + } + catch( err ) + { + o.sourceCode = ` ! Cant load source code of "${ o.location.filePath }"`; + } + + if( !o.sourceCode ) + return end(); + + } + + /* */ + + let code = _.strLinesSelect + ({ + src : o.sourceCode, + line : o.location.line, + nearestLines : o.nearestLines, + selectMode : o.selectMode, + zeroLine : 1, + numbering : 1, + }); + + if( code && _.strLinesIndentation && o.identation ) + code = o.identation + _.strLinesIndentation( code, o.identation ); + + let result = code; + if( o.withPath ) + { + if( o.asMap ) + result = { path : o.location.filePathLineCol, code }; + else + result = o.location.filePathLineCol + '\n' + code; + } + + return end( result ); + } + catch( err ) + { + console.log( err.toString() ); + return; + } + + /* */ + + function end( result ) + { + _diagnosticCodeExecuting -= 1; + return result; + } + + /* */ + + function read( codeProvider, filePath ) + { + let result = codeProvider.fileRead + ({ + filePath, + sync : 1, + throwing : 0, + }); + return result; + } + + /* */ + +} +_.introspector.code.defaults = +{ + "level" : 0, + "nearestLines" : 5, + "withPath" : 1, + "asMap" : 0, + "selectMode" : `center`, + "identation" : null, + "stack" : null, + "error" : null, + "location" : null, + "sourceCode" : null +} + +// + + + _.introspector.stack = function stack( stack, range ) +{ + + if( arguments.length === 1 ) + { + if( !_.error.is( stack ) ) + if( !_.strIs( stack ) ) + { + range = arguments[ 0 ]; + stack = undefined; + } + } + + if( stack === undefined || stack === null ) + { + stack = new Error(); + if( range === undefined ) + { + range = [ 1, Infinity ]; + } + else + { + if( _.number.is( range[ 0 ] ) ) /* Dmytro : previous implementation affects range - not a number value + number => NaN, so assertion does not word properly */ + range[ 0 ] += 1; + if( _.number.is( range[ 1 ] ) && range[ 1 ] >= 0 ) + range[ 1 ] += 1; + } + } + + if( range === undefined ) + range = [ 0, Infinity ]; + + if( arguments.length !== 0 && arguments.length !== 1 && arguments.length !== 2 ) + { + debugger; + throw Error( 'stack : expects one or two or none arguments' ); + } + + if( !_.intervalIs( range ) ) + { + debugger; + throw Error( 'stack : expects range but, got ' + _.entity.strType( range ) ); + } + + let first = range[ 0 ]; + let last = range[ 1 ]; + + // if( !_.number.is( first ) ) // Dmytro : it's unnecessary assertions, _.intervalIs checks number value in passed array + // { + // debugger; + // throw Error( 'stack : expects number range[ 0 ], but got ' + _.entity.strType( first ) ); + // } + // + // if( !_.number.is( last ) ) + // { + // debugger; + // throw Error( 'stack : expects number range[ 0 ], but got ' + _.entity.strType( last ) ); + // } + + let errIs = 0; + if( _.error.is( stack ) ) + { + stack = _.error.originalStack( stack ); + errIs = 1; + } + + if( !stack ) + return ''; + + if( !_.arrayIs( stack ) && !_.strIs( stack ) ) + return; + + // if( !_.arrayIs( stack ) && !_.strIs( stack ) ) // Dmytro : previous condition is almost identical + // { + // debugger; + // throw Error( 'stack expects array or string' ); + // } + + if( !_.arrayIs( stack ) ) + stack = stack.split( '\n' ); + + // debugger; + + /* remove redundant lines */ + + while( stack.length ) + { + let splice = 0; + splice |= ( _.strHas( stack[ 0 ], /(^| )at / ) === false && stack[ 0 ].indexOf( '@' ) === -1 ); + splice |= stack[ 0 ].indexOf( '(vm.js:' ) !== -1; + splice |= stack[ 0 ].indexOf( '(module.js:' ) !== -1; + splice |= stack[ 0 ].indexOf( '(internal/module.js:' ) !== -1; + if( splice ) + stack.splice( 0, 1 ); + else break; + } + + if( stack[ 0 ] ) + if( stack[ 0 ].indexOf( 'at ' ) === -1 && stack[ 0 ].indexOf( '@' ) === -1 ) // Dmytro : it's dubious - while loop removes all strings if stack[ 0 ] has not 'at ' or '@' + { + console.error( 'stack : failed to parse stack' ); + debugger; + } + + stack = stack.map( ( line ) => line.trim() ); + stack = stack.filter( ( line ) => line ); + + /* */ + + first = first === undefined ? 0 : first; + last = last === undefined ? stack.length : last; + + // if( _.number.is( first ) ) // Dmytro : first and last - is always some numbers, see above about assertions + if( first < 0 ) + first = stack.length + first; + + // if( _.number.is( last ) ) + if( last < 0 ) + last = stack.length + last + 1; + + /* */ + + if( first !== 0 || last !== stack.length ) + { + stack = stack.slice( first || 0, last ); + } + + /* */ + + stack = String( stack.join( '\n' ) ); + + return stack; +} + +// + + + _.introspector.stackCondense = function stackCondense( stack ) +{ + + if( arguments.length !== 1 ) + throw Error( 'Expects single arguments' ); + + if( !_.strIs( stack ) ) + { + debugger; + throw Error( 'Expects string' ); + } + + stack = stack.split( '\n' ); + + for( let s = stack.length-1 ; s >= 0 ; s-- ) + { + let line = stack[ s ]; + if( s > 0 ) + if( /(\W|^)__\w+/.test( line ) ) + { + stack.splice( s, 1 ); + continue; + } + if( _.strHas( line, '.test.' ) ) + line += ' *'; + stack[ s ] = line; + } + + return stack.join( '\n' ); +} + +// + + + _.introspector.location = function location( o ) +{ + if( _.number.is( o ) ) + o = { level : o } + else if( _.strIs( o ) ) + o = { stack : o, level : 0 } + else if( _.error.is( o ) ) + o = { error : o, level : 0 } + else if( o === undefined ) + o = { stack : _.introspector.stack([ 1, Infinity ]) }; + + /* */ + + if( location.defaults ) + for( let e in o ) + { + if( location.defaults[ e ] === undefined ) + throw Error( 'Unknown option ' + e ); + } + + if( location.defaults ) + for( let e in location.defaults ) + { + if( o[ e ] === undefined ) + o[ e ] = location.defaults[ e ]; + } + + if( !( arguments.length === 0 || arguments.length === 1 ) ) + throw Error( 'Expects single argument or none' ); + + if( !_.mapIs( o ) ) + throw Error( 'Expects options map' ); + + if( !o.level ) + o.level = 0; + + /* */ + + if( !o.location ) + o.location = Object.create( null ); + + /* */ + + if( o.error ) + { + let location2 = o.error.location || Object.create( null ); + + var args0 = + [ + location2.filePath, + o.location.filePath, + o.error.filename, + o.error.fileName + ]; + o.location.filePath = _.longLeftDefined( args0 ).element; + + var args1 = + [ + location2.line, + o.location.line, + o.error.line, + o.error.linenumber, + o.error.lineNumber, + o.error.lineNo, + o.error.lineno + ]; + o.location.line = _.longLeftDefined( args1 ).element; + + var args2 = + [ + location2.col, + o.location.col, + o.error.col, + o.error.colnumber, + o.error.colNumber, + o.error.colNo, + o.error.colno + ]; + o.location.col = _.longLeftDefined( args2 ).element; + + } + + /* */ + + if( !o.stack ) + { + if( o.error ) + { + o.stack = _.introspector.stack( o.error, undefined ); + } + else + { + o.stack = _.introspector.stack(); + o.level += 1; + } + } + + if( o.stack === null || o.stack === undefined ) + return o.location; + + _.assert( _.strIs( o.stack ) || _.arrayIs( o.stack ) ); + + let stack = o.stack; + if( _.strIs( stack ) ) + stack = stack.split( '\n' ); + let stackFrame = stack[ o.level ]; + + return _.introspector.locationFromStackFrame({ stackFrame, location : o.location }); +} +_.introspector.location.defaults = +{ + "level" : 0, + "stack" : null, + "error" : null, + "location" : null +} + +// + + + _.introspector.locationFromStackFrame = function locationFromStackFrame( o ) +{ + + if( _.strIs( o ) ) + o = { stackFrame : o }; + + if( !( arguments.length === 1 ) ) + throw Error( 'Expects single argument' ); + + if( !_.mapIs( o ) ) + throw Error( 'Expects options map' ); + + /* */ + + if( locationFromStackFrame.defaults ) /* Dmytro : maybe it is the redundant condition, the routine has defaults */ + for( let e in o ) + { + if( locationFromStackFrame.defaults[ e ] === undefined ) + throw Error( 'Unknown option : ' + e ); + } + + if( locationFromStackFrame.defaults ) /* Dmytro : maybe it is the redundant condition, the routine has defaults */ + for( let e in locationFromStackFrame.defaults ) + { + if( o[ e ] === undefined ) + o[ e ] = locationFromStackFrame.defaults[ e ]; + } + + /* */ + + if( !( _.strIs( o.stackFrame ) ) ) + throw Error( `Expects string {- stackFrame -}, but got ${_.entity.strType( o.stackFrame )}` ); + + if( o.location && !_.mapIs( o.location ) ) + throw Error( 'Expects map option::location' ); + + /* */ + + if( !o.location ) + o.location = Object.create( null ); + o.location.original = o.stackFrame; + _.introspector.locationNormalize( o.location ); + return o.location; +} +_.introspector.locationFromStackFrame.defaults = +{ "stackFrame" : null, "location" : null } + +// + + + _.introspector.locationToStack = function locationToStack( o ) +{ + if( !( arguments.length === 1 ) ) + throw Error( 'Expects single argument' ); + + if( !_.mapIs( o ) ) + throw Error( 'Expects options map' ); + + /* */ + + // _.map.assertHasOnly( o, locationToStack.defaults ); + if( Config.debug ) + { + let extraKeys = mapButKeys( o, locationToStack.defaults ); + _.assert( extraKeys.length === 0, () => `Routine "locationToStack" does not expect options: ${ keysQuote( extraKeys ) }` ); + } + + _.introspector.locationNormalize( o ); + + if( !o.filePathLineCol ) + return null; + + // if( o.routineFilePathLineCol ) + // { + // _.assert( 0, 'not tested' ); + // } + + if( o.routineName ) + return `at ${o.routineName} (${o.filePathLineCol})`; + else + return `at (${o.filePathLineCol})`; + + /* + at Object.locationToStack (http://127.0.0.1:5000//builder/include/wtools/abase/l0/l3/Introspector.s:723:10) + */ + + /* */ + + function mapButKeys( srcMap, butMap ) + { + let result = []; + + for( let s in srcMap ) + if( !( s in butMap ) ) + result.push( s ); + + return result; + } + + /* */ + + function keysQuote( keys ) + { + let result = `"${ keys[ 0 ] }"`; + for( let i = 1 ; i < keys.length ; i++ ) + result += `, "${ keys[ i ] }"`; + return result.trim(); + } +} +_.introspector.locationToStack.defaults = +{ + "original" : null, + "filePath" : null, + "routineName" : null, + "routineAlias" : null, + "internal" : null, + "abstraction" : null, + "line" : null, + "col" : null, + "filePathLineCol" : null, + "routineFilePathLineCol" : null, + "fileName" : null, + "fileNameLineCol" : null +} + +// + + + _.introspector.locationNormalize = function locationNormalize( o ) +{ + + if( !( arguments.length === 1 ) ) + throw Error( 'Expects single argument' ); + + if( !_.mapIs( o ) ) + throw Error( 'Expects options map' ); + + /* */ + + if( locationNormalize.defaults ) + for( let e in o ) + { + if( locationNormalize.defaults[ e ] === undefined ) + throw Error( 'Unknown option ' + e ); + } + + if( locationNormalize.defaults ) + for( let e in locationNormalize.defaults ) + { + if( o[ e ] === undefined ) + o[ e ] = locationNormalize.defaults[ e ]; + } + + /* */ + + let hadPath = !!o.filePath; + if( !o.filePath ) + o.filePath = pathFromStack(); + + pathCanonize(); + routineFromStack(); + routineAliasFromStack(); + internalForm(); + abstractionForm(); + + // if( !_.strIs( o.filePath ) ) + // return end(); + + if( !_.number.defined( o.line ) || !_.number.defined( o.col ) ) + o.filePath = lineColFromPath( o.filePath ); + + if( !_.number.is( o.line ) && hadPath ) + { + let path = pathFromStack(); + if( path ) + lineColFromPath( path ); + } + + return end(); + + /* */ + + function end() + { + let path = o.filePath; + + /* filePathLineCol */ + + o.filePathLineCol = path || ''; + if( _.number.defined( o.line ) ) + { + o.filePathLineCol += ':' + o.line; + if( _.number.defined( o.col ) ) + o.filePathLineCol += ':' + o.col; + } + + /* routineFilePathLineCol */ + + if( o.routineName ) + o.routineFilePathLineCol = o.routineName + ' @ ' + o.filePathLineCol; + + /* fileName */ + + if( path ) + { + let fileName = path; + _.assert( _.routine.is( fileName.lastIndexOf ) ); + let i1 = fileName.lastIndexOf( '/' ); + let i2 = fileName.lastIndexOf( '\\' ); + let i = Math.max( i1, i2 ); + if( i !== -1 ) + fileName = fileName.substr( i+1 ); + o.fileName = fileName; + } + + /* fileNameLineCol */ + + o.fileNameLineCol = o.fileName || ''; + if( _.number.defined( o.line ) ) + { + o.fileNameLineCol += ':' + o.line; + if( _.number.defined( o.col ) ) + o.fileNameLineCol += ':' + o.col; + } + + return o; + } + + /* */ + + function pathCanonize() + { + if( !o.filePath ) + return; + + if( _.path && _.path.canonize ) + o.filePath = _.path.canonize( o.filePath ); + } + + /* */ + + function routineFromStack() + { + let routineName; + + if( o.routineName ) + return o.routineName; + if( !o.original ) + return o.routineName; + + routineName = o.original; + + // if( !_.strIs( routineName ) ) // xxx /* Dmytro : deprecated comment, delete with label, please */ + // return '{-anonymous-}'; + if( !_.strIs( routineName ) ) // xxx /* Dmytro : deprecated comment, delete with label, please */ + { + routineName = '{-anonymous-}'; + } + else + { + routineName = routineName.replace( /at eval \(eval at/, '' ); + let t = /^\s*(?:at\s+)?([\w.<>]+)\s*.+/; + let executed = t.exec( routineName ); + if( executed ) + routineName = executed[ 1 ] || ''; + + routineName = routineName.replace( //gm, '{-anonymous-}' ); + + if( _.strEnds( routineName, '.' ) ) + routineName += '{-anonymous-}'; + } + + o.routineName = routineName; + return o.routineName; + } + + /* */ + + function routineAliasFromStack() + { + let routineAlias; + + if( o.routineAlias ) + return o.routineAlias; + if( !o.original ) + return o.routineAlias; + + routineAlias = null; + + let t = /\[as ([^\]]*)\]/; + let executed = t.exec( o.original ); + if( executed ) + routineAlias = executed[ 1 ] || null; + + if( routineAlias ) + routineAlias = routineAlias.replace( //gm, '{-anonymous-}' ); + + o.routineAlias = routineAlias; + return o.routineAlias; + } + + /* */ + + function internalForm() + { + + if( _.number.defined( o.internal ) ) + return; + + o.internal = 0; + + if( o.filePath ) + { + if( o.internal < 2 ) + if( _.strBegins( o.filePath, 'internal/' ) ) + o.internal = 2; + + if( o.internal < 2 ) + if( _.strBegins( o.filePath, 'node:internal/' ) ) + o.internal = 2; + + } + + } + + /* */ + + function abstractionForm() + { + + if( _.number.defined( o.abstraction ) ) + return; + + o.abstraction = 0; + + if( o.routineName ) + { + if( o.abstraction < 2 ) + if( _.strBegins( o.routineName, '__' ) || o.routineName.indexOf( '.__' ) !== -1 ) + o.abstraction = 2; + if( o.abstraction < 1 ) + if( _.strBegins( o.routineName, '_' ) || o.routineName.indexOf( '._' ) !== -1 ) + o.abstraction = 1; + } + + if( o.routineAlias ) + { + if( o.abstraction < 2 ) + if( _.strBegins( o.routineAlias, '__' ) || o.routineAlias.indexOf( '.__' ) !== -1 ) + o.abstraction = 2; + if( o.abstraction < 1 ) + if( _.strBegins( o.routineAlias, '_' ) || o.routineAlias.indexOf( '._' ) !== -1 ) + o.abstraction = 1; + } + + } + + /* */ + + function pathFromStack() + { + let path = o.original; + + if( !_.strIs( path ) ) + return; + + path = path.replace( /^\s+/, '' ); + path = path.replace( /^\w+@/, '' ); + path = path.replace( /^at/, '' ); + path = path.replace( /^\s+/, '' ); + path = path.replace( /\s+$/, '' ); + + let regexp = /^.*\(([^)]*)\).*$/; + var parsed = regexp.exec( path ); + if( parsed ) + path = parsed[ 1 ]; + + return path; + } + + /* line / col number from path */ + + function lineColFromPath( path ) + { + if( !path ) + { + if( o.line ) + o.line = numberFromToInt( o.line ); + if( o.col ) + o.col = numberFromToInt( o.col ) + } + else + { + let lineNumber, colNumber; + let postfix = /(.+?):(\d+)(?::(\d+))?[^:/]*$/; + let parsed = postfix.exec( path ); + + if( parsed ) + { + path = parsed[ 1 ]; + lineNumber = parsed[ 2 ]; + colNumber = parsed[ 3 ]; + } + + lineNumber = numberFromToInt( lineNumber ); + colNumber = numberFromToInt( colNumber ); + + if( !_.number.defined( o.line ) ) + if( _.number.defined( lineNumber ) ) + o.line = lineNumber; + + if( !_.number.defined( o.col ) ) + if( _.number.defined( colNumber ) ) + o.col = colNumber; + } + + if( !_.number.defined( o.line ) ) + o.line = null; + if( !_.number.defined( o.col ) ) + o.col = null; + + return path; + } + + /* */ + + function numberFromToInt( src ) + { + if( _.strIs( src ) ) + src = parseInt( src ); + else + src = Math.floor( Number( src ) ); + + return src; + } + +} +_.introspector.locationNormalize.defaults = +{ + "original" : null, + "filePath" : null, + "routineName" : null, + "routineAlias" : null, + "internal" : null, + "abstraction" : null, + "line" : null, + "col" : null, + "filePathLineCol" : null, + "routineFilePathLineCol" : null, + "fileName" : null, + "fileNameLineCol" : null +} + +// + + + + _.long._functor_functor = function _functor_functor( methodName, typer, which ) +{ + _.assert( !!( methodName ) ); + if( !typer ) + typer = 'namespaceOf'; + if( !which ) + which = 0; + if( which === 0 ) + return end( _functor0 ); + if( which === 1 ) + return end( _functor1 ); + _.assert( 0 ); + + function _functor0( container ) + { + _.assert( arguments.length === 1 ); + _.assert( _.routine.is( this[ typer ] ), () => `No routine::${typer} in the namesapce::${this.NamespaceName}` ); + const namespace = this[ typer ]( container ); + _.assert( _.routine.is( namespace[ methodName ] ), `No routine::${methodName} in the namesapce::${namespace.NamespaceName}` ); + return namespace[ methodName ].bind( namespace, container ); + } + + function _functor1( container ) + { + _.assert( arguments.length === 1 ); + _.assert( _.routine.is( this[ typer ] ), () => `No routine::${typer} in the namesapce::${this.NamespaceName}` ); + const namespace = this[ typer ]( container ); + _.assert( _.routine.is( namespace[ methodName ] ), `No routine::${methodName} in the namesapce::${namespace.NamespaceName}` ); + const routine0 = namespace[ methodName ]; + return routine1.bind( namespace ); + function routine1( arg1, ... args ) + { + return routine0.call( this, arg1, container, ... args ); + } + } + + function end( result ) + { + result.functor = new Function( `return _.long._functor_functor( '${methodName}', '${typer}', ${which} )` ); + return result; + } + +} + +// + + + + _.entity.strType = function strTypeWithTraits( src ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.aux.is( src ) ) + { + + if( _.mapIsPure( src ) ) + return end( 'Map.pure' ); + else if( _.mapIsPolluted( src ) ) + return end( 'Map.polluted' ); + else if( _.aux.isPure( src ) && _.aux.isPrototyped( src ) ) + return end( 'Aux.pure.prototyped' ); + else if( _.aux.isPolluted( src ) && _.aux.isPrototyped( src ) ) + return end( 'Aux.polluted.prototyped' ); + else _.assert( 0, 'undexpected' ); + + } + + if( _.primitive.is( src ) ) + return end( _.entity.strTypeSecondary( src ) ); + + let proto = Object.getPrototypeOf( src ); + if( proto && proto.constructor && proto.constructor !== Object && proto.constructor.name ) + return end( proto.constructor.name ); + + return end( _.entity.strTypeSecondary( src ) ); + + function end( result ) + { + let translated = _.entity.TranslatedTypeMap[ result ]; + if( translated ) + result = translated; + + if( !_.entity.StandardTypeSet.has( result ) ) + { + if( _.countableIs( src ) ) + result += '.countable'; + if( _.constructibleIs( src ) ) + result += '.constructible'; + } + + return result; + } + +} + +// + + + _.entity.strTypeSecondary = function strTypeSecondary( src ) +{ + + let name = Object.prototype.toString.call( src ); + let result = /\[(\w+) (\w+)\]/.exec( name ); + _.assert( !!result, 'unknown type', name ); + return result[ 2 ]; +} + +// + + + _.entity.namespaceOf = function namespaceForIterating( src ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 1 ); + + if( src === undefined ) + return _.blank; + if( _.primitive.is( src ) ) + return _.itself; + if( _.hashMap.like( src ) ) + return _.hashMap; + if( _.set.like( src ) ) + return _.set; + if( _.long.is( src ) ) + return _.long; + if( _.buffer.like( src ) ) + return _.buffer; + if( _.countable.is( src ) ) + return _.object; + if( _.aux.is( src ) ) + return _.aux; + if( _.object.is( src ) ) + return _.object; + + return _.props; +} + +// + + + _.entity.lengthOf = ( function() +{ + const lengthOf = function lengthOf( src ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 1 ); + return lengthOf.functor.call( this, src )(); +}; + lengthOf.functor = ( function anonymous( +) { +return _.long._functor_functor( 'lengthOf', 'namespaceOf', 0 ) +} )();; + return lengthOf; +})(); + +// + + + _.lengthOf = _.entity.lengthOf.bind( _.entity ) + _.strType = _.entity.strType.bind( _.entity ) + _.entity.makeUndefined = ( function() +{ + const makeUndefined = function makeUndefined( container, ... args ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + return makeUndefined.functor.call( this, container )( ... args ); +}; + makeUndefined.functor = ( function anonymous( +) { +return _.long._functor_functor( 'makeUndefined', 'namespaceOf', 0 ) +} )();; + return makeUndefined; +})(); + +// + + + _.entity.TranslatedTypeMap = { + "BigUint64Array" : `U64x`, + "Uint32Array" : `U32x`, + "Uint16Array" : `U16x`, + "Uint8Array" : `U8x`, + "Uint8ClampedArray" : `U8xClamped`, + "BigInt64Array" : `I64x`, + "Int32Array" : `I32x`, + "Int16Array" : `I16x`, + "Int8Array" : `I8x`, + "Float64Array" : `F64x`, + "Float32Array" : `F32x`, + "Buffer" : `BufferNode`, + "ArrayBuffer" : `BufferRaw`, + "SharedArrayBuffer" : `BufferRawShared`, + "Map" : `HashMap`, + "WeakMap" : `HashMapWeak`, + "Function" : `Routine`, + "Arguments" : `ArgumentsArray` +}; + +// + + + _.entity.StandardTypeSet = new Set([ + `U64x`, + `U32x`, + `U16x`, + `U8x`, + `U8xClamped`, + `I64x`, + `I32x`, + `I16x`, + `I8x`, + `F64x`, + `F32x`, + `BufferNode`, + `BufferRaw`, + `BufferRawShared`, + `HashMap`, + `HashMapWeak`, + `ArgumentsArray`, + `Array`, + `Set`, + `Routine`, + `Global` +]); + +// + + + + _.class.methodIteratorOf = function methodIteratorOf( src ) +{ + if( !src ) + return; + if( _.routine.like( src[ iteratorSymbol ] ) ) + return src[ iteratorSymbol ]; + return; +} + +// + + + + _.path.refine = function refine( src ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ) ); + + let result = src; + + if( result[ 1 ] === ':' ) + { + if( result[ 2 ] === '\\' || result[ 2 ] === '/' ) + { + if( result.length > 3 ) + result = '/' + result[ 0 ] + '/' + result.substring( 3 ); + else + result = '/' + result[ 0 ] + } + else if( result.length === 2 ) + { + result = '/' + result[ 0 ]; + } + } + + result = result.replace( /\\/g, '/' ); + + return result; +} + +// + + + _.path._normalize = function _normalize( o ) +{ + // let debug = 0; + // if( 0 ) + // debug = 1; + + _.routine.assertOptions( _normalize, arguments ); + _.assert( _.strIs( o.src ), 'Expects string' ); + + if( !o.src.length ) + return ''; + + let result = o.src; + + result = this.refine( result ); + + // if( debug ) + // console.log( 'normalize.refined : ' + result ); + + /* detrailing */ + + if( o.tolerant ) + { + /* remove "/" duplicates */ + result = result.replace( this._delUpDupRegexp, this.upToken ); + } + + let endsWithUp = false; + let beginsWithHere = false; + + /* remove right "/" */ + + if( result !== this.upToken && !_.strEnds( result, this.upToken + this.upToken ) && _.strEnds( result, this.upToken ) ) + { + endsWithUp = true; + result = _.strRemoveEnd( result, this.upToken ); + } + + /* undoting */ + + while( !_.strBegins( result, this.hereUpToken + this.upToken ) && _.strBegins( result, this.hereUpToken ) ) + { + beginsWithHere = true; + result = _.strRemoveBegin( result, this.hereUpToken ); + } + + /* remove second "." */ + + if( result.indexOf( this.hereToken ) !== -1 ) + { + + while( this._delHereRegexp.test( result ) ) + result = result.replace( this._delHereRegexp, function( match, postSlash ) + { + return postSlash || ''; + }); + if( result === '' ) + result = this.upToken; + + } + + /* remove .. */ + + if( result.indexOf( this.downToken ) !== -1 ) + { + + while( this._delDownRegexp.test( result ) ) + result = result.replace( this._delDownRegexp, function( /* match, notBegin, split, preSlash, postSlash */ ) + { + let match = arguments[ 0 ]; + let notBegin = arguments[ 1 ]; + let split = arguments[ 2 ]; + let preSlash = arguments[ 3 ]; + let postSlash = arguments[ 4 ]; + + if( preSlash === '' ) + return notBegin; + if( !notBegin ) + return notBegin + preSlash; + else + return notBegin + ( postSlash || '' ); + }); + + } + + /* nothing left */ + + if( !result.length ) + result = '.'; + + /* dot and trail */ + + if( o.detrailing ) + if( result !== this.upToken && !_.strEnds( result, this.upToken + this.upToken ) ) + result = _.strRemoveEnd( result, this.upToken ); + + if( !o.detrailing && endsWithUp ) + if( result !== this.rootToken ) + result = result + this.upToken; + + if( !o.undoting && beginsWithHere ) + result = this._dot( result ); + + // if( debug ) + // console.log( 'normalize.result : ' + result ); + + return result; +} +_.path._normalize.defaults = +{ + "src" : null, + "tolerant" : false, + "detrailing" : false, + "undoting" : false +} + +// + + + _.path.normalize = function normalize( src ) +{ + let result = this._normalize({ src, tolerant : false, detrailing : false, undoting : false }); + + _.assert( _.strIs( src ), 'Expects string' ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( result.lastIndexOf( this.upToken + this.hereToken + this.upToken ) === -1 ); + _.assert( !_.strEnds( result, this.upToken + this.hereToken ) ); + + if( Config.debug ) + { + let i = result.lastIndexOf( this.upToken + this.downToken + this.upToken ); + _.assert( i === -1 || !/\w/.test( result.substring( 0, i ) ) ); + } + + return result; +} + +// + + + _.path.canonize = function canonize( src ) +{ + let result = this._normalize({ src, tolerant : false, detrailing : true, undoting : true }); + + _.assert( _.strIs( src ), 'Expects string' ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( result === this.upToken || _.strEnds( result, this.upToken + this.upToken ) || !_.strEnds( result, this.upToken ) ); + _.assert( result.lastIndexOf( this.upToken + this.hereToken + this.upToken ) === -1 ); + _.assert( !_.strEnds( result, this.upToken + this.hereToken ) ); + + if( Config.debug ) + { + let i = result.lastIndexOf( this.upToken + this.downToken + this.upToken ); + _.assert( i === -1 || !/\w/.test( result.substring( 0, i ) ) ); + } + + return result; +} + +// + + + _.path.canonizeTolerant = function canonizeTolerant( src ) +{ + _.assert( _.strIs( src ), 'Expects string' ); + + let result = this._normalize({ src, tolerant : true, detrailing : true, undoting : true }); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( result === this.upToken || _.strEnds( result, this.upToken ) || !_.strEnds( result, this.upToken + this.upToken ) ); + _.assert( result.lastIndexOf( this.upToken + this.hereToken + this.upToken ) === -1 ); + _.assert( !_.strEnds( result, this.upToken + this.hereToken ) ); + + if( Config.debug ) + { + _.assert( !this._delUpDupRegexp.test( result ) ); + } + + return result; +} + +// + + + _.path._unescape = function _unescape( filePath ) +{ + let self = this; + // let splits = self.split( filePath ); + /* + cant use routine self.split because it normalizes path + */ + let splits = filePath.split( self.upToken ); + + let result = Object.create( null ); + result.wasEscaped = false; + + splits = splits.map( ( split ) => + { + + { + let i = 0; + while( split[ i ] === '"' ) + i += 1; + if( i > 0 ) + { + let c = i; + if( c % 2 === 1 ) + result.wasEscaped = true; + let c2 = Math.floor( ( c + 1 ) / 2 ); + split = split.substring( c2, split.length ); + } + } + + { + let i = split.length-1; + while( split[ i ] === '"' ) + i -= 1; + if( i < split.length-1 ) + { + let c = split.length - i - 1; + if( c % 2 === 1 ) + result.wasEscaped = true; + let c2 = Math.floor( ( c + 1 ) / 2 ); + split = split.substring( 0, split.length - c2 ); + } + } + + return split; + }); + + result.unescaped = splits.join( self.upToken ); + return result; +} + +// + + + _.path.unescape = function unescape( filePath ) +{ + let self = this; + return self._unescape( filePath ).unescaped; +} + +// + + + _.path._nativizeWindows = function _nativizeWindows( filePath ) +{ + let self = this; + _.assert( _.strIs( filePath ), 'Expects string' ) ; + + let result = filePath; + + _.assert( _.routine.is( self.unescape ) ); + result = self.unescape( result ); /* xxx : remove from here */ + + result = self._nativizeMinimalWindows( result ); + + return result; +} + +// + + + _.path._nativizeMinimalWindows = function _nativizeMinimalWindows( filePath ) +{ + let self = this; + + let result = filePath; + + result = result.replace( /\//g, '\\' ); + + if( result[ 0 ] === '\\' ) + if( result.length === 2 || result[ 2 ] === ':' || result[ 2 ] === '\\' ) + result = result[ 1 ] + ':' + result.substring( 2 ); + + if( result.length === 2 && result[ 1 ] === ':' ) + result = result + '\\'; + + return result; +} + +// + + + _.path._nativizePosix = function _nativizePosix( filePath ) +{ + let self = this; + let result = filePath; + _.assert( _.strIs( filePath ), 'Expects string' ); + _.assert( _.routine.is( self.unescape ) ); + result = self.unescape( result ); /* xxx : remove from here */ + return result; +} + +// + + + _.path.isGlob = function isGlob( src ) /* qqq2 : extend and implement perfect coverage taking into account escaping */ +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ) ); + + if( self.fileProvider && !self.fileProvider.globing ) + { + return false; + } + + if( !self._pathIsGlobRegexp ) + _setup(); + + return self._pathIsGlobRegexp.test( src ); + + function _setup() + { + let _pathIsGlobRegexpStr = ''; + _pathIsGlobRegexpStr += '(?:[?*]+)'; /* asterix, question mark */ + _pathIsGlobRegexpStr += '|(?:([!?*@+]*)\\((.*?(?:\\|(.*?))*)\\))'; /* parentheses */ + _pathIsGlobRegexpStr += '|(?:\\[(.+?)\\])'; /* square brackets */ + _pathIsGlobRegexpStr += '|(?:\\{(.*)\\})'; /* curly brackets */ + _pathIsGlobRegexpStr += '|(?:\0)'; /* zero */ + self._pathIsGlobRegexp = new RegExp( _pathIsGlobRegexpStr ); + } + +} + +// + + + _.path.isRelative = function isRelative( filePath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), 'Expects string {-filePath-}, but got', _.entity.strType( filePath ) ); + return !this.isAbsolute( filePath ); +} + +// + + + _.path.isAbsolute = function isAbsolute( filePath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), 'Expects string {-filePath-}, but got', _.entity.strType( filePath ) ); + filePath = this.refine( filePath ); + return _.strBegins( filePath, this.upToken ); +} + +// + + + _.path.ext = function ext( path ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( path ), 'Expects string {-path-}, but got', _.entity.strType( path ) ); + + let index = path.lastIndexOf( '/' ); + if( index >= 0 ) + path = path.substr( index+1, path.length-index-1 ); + + index = path.lastIndexOf( '.' ); + if( index === -1 || index === 0 ) + return ''; + + index += 1; + + return path.substr( index, path.length-index ).toLowerCase(); +} + +// + + + _.path.isGlobal = function isGlobal( filePath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), 'Expects string' ); + return _.strHas( filePath, '://' ); +} + +// + + + _.path.rootToken = `/`; + +// + + _.path.upToken = `/`; + +// + + _.path.hereToken = `.`; + +// + + _.path.downToken = `..`; + +// + + _.path.hereUpToken = `./`; + +// + + _.path.downUpToken = `../`; + +// + + _.path._delHereRegexp = /\/\.(\/|$)/; + +// + + _.path._delDownRegexp = /((?:.|^))(?:(?:\/\/)|(((?:^|\/))(?!\.\.(?:\/|$))(?:(?!\/).)+\/))\.\.((?:\/|$))/; + +// + + _.path._delUpDupRegexp = /\/{2,}/g; + +// + + _.path._pathIsGlobRegexp = /(?:[?*]+)|(?:([!?*@+]*)\((.*?(?:\|(.*?))*)\))|(?:\[(.+?)\])|(?:\{(.*)\})|(?:)/; + +// + + + + _.long.is = ( function is_functor() +{ + let result; + const TypedArray = Object.getPrototypeOf( Int8Array ); + //const iteratorSymbol = Symbol.iterator; + + if( _global_.BufferNode ) + result = isNjs; + else + result = isBrowser; + result.functor = is_functor; + return result; + + function isNjs( src ) + { + if( Array.isArray( src ) ) + return true + + if( src instanceof TypedArray ) + { + if( src instanceof BufferNode ) + return false; + return true; + } + isNjs.functor = is_functor; + + // if( arguments[ iteratorSymbol ] === undefined ) + // return false; + if( Object.prototype.toString.call( src ) === '[object Arguments]' ) + return true; + + return false; + } + + function isBrowser( src ) + { + if( Array.isArray( src ) ) + return true + + if( src instanceof TypedArray ) + return true; + + // if( arguments[ iteratorSymbol ] === undefined ) + // return false; + if( Object.prototype.toString.call( src ) === '[object Arguments]' ) + return true; + + return false; + } + isBrowser.functor = is_functor; + +} )(); + +// + + + _.long.like = function like( src ) /* qqq : cover */ +{ + if( _.primitive.is( src ) ) + return false; + return _.long.is( src ); +} + +// + + + _.long._make = function _make( src, length ) +{ + if( arguments.length === 2 ) + { + let data = length; + if( _.number.is( length ) ) + { + data = src; + } + else + { + if( _.number.is( length.length ) ) + { + length = length.length; + } + else + { + data = [ ... length ]; + length = data.length; + } + } + if( _.argumentsArray.is( src ) ) + return fill( _.argumentsArray._make( length ), data ); + if( _.unroll.is( src ) ) + return fill( _.unroll._make( length ), data ); + if( src === null ) + return fill( this.tools.long.default._make( length ), data ); + let result; + if( _.routine.is( src ) ) + result = fill( new src( length ), data ) + else if( src.constructor ) + result = fill( new src.constructor( length ), data ); + _.assert( _.long.is( result ), 'Not clear how to make such long' ); + return result; + } + else if( src !== undefined && src !== null ) + { + if( _.number.is( src ) ) + return this.tools.long.default._make( src ); + if( _.unroll.is( src ) ) + return _.unroll._make( src ); + if( _.argumentsArray.is( src ) ) + return _.argumentsArray._make( src ); + if( src.constructor === Array ) + return [ ... src ]; + if( _.buffer.typedIs( src ) ) + return new src.constructor( src ); + if( _.countable.is( src ) ) + return this.tools.long.default._make( src ); + if( _.routine.is( src ) ) + { + let result = new src(); + _.assert( this.is( result ), 'Expects long as returned instance' ); + return result; + } + } + + return this.tools.long.default.make(); + + /* */ + + function fill( dst, data ) + { + if( data === null || data === undefined ) + return dst; + let l = Math.min( length, data.length ); + for( let i = 0 ; i < l ; i++ ) + dst[ i ] = data[ i ]; + return dst; + } +} + +// + + + _.long.make = function make( src, length ) +{ + _.assert( arguments.length <= 2 ); + if( arguments.length === 2 ) + { + _.assert( src === null || _.long.is( src ) || _.routine.is( src ) ); + _.assert( _.number.is( length ) || _.countable.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( src === null || _.number.is( src ) || _.long.is( src ) || _.countable.is( src ) || _.routine.is( src ) ); + } + return this._make( ... arguments ); +} + +// + + + _.long._makeUndefined = function _makeUndefined( src, length ) +{ + if( arguments.length === 2 ) + { + if( !_.number.is( length ) ) + { + if( _.number.is( length.length ) ) + length = length.length; + else + length = [ ... length ].length; + } + + if( src === null ) + return this.tools.long.default._makeUndefined( length ); + if( _.argumentsArray.is( src ) ) + return _.argumentsArray._makeUndefined( src, length ); + if( _.unroll.is( src ) ) + return _.unroll._makeUndefined( src, length ); + if( _.routine.is( src ) ) + { + let result = new src( length ); + _.assert( _.long.is( result ) ); + return result; + } + return new src.constructor( length ); + } + else if( arguments.length === 1 ) + { + let constructor; + if( this.like( src ) ) + { + if( _.argumentsArray.is( src ) ) + return _.argumentsArray._makeUndefined( src ); + if( _.unroll.is( src ) ) + return _.unroll._makeUndefined( src ); + constructor = src.constructor; + length = src.length; + } + else + { + return this.tools.long.default._makeUndefined( src ); + } + return new constructor( length ); + } + + return this.tools.long.default._makeUndefined(); +} + +// + + + _.long.makeUndefined = function makeUndefined( src, length ) +{ + // _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + _.assert( 0 <= arguments.length && arguments.length <= 2 ); + if( arguments.length === 2 ) + { + _.assert( src === null || _.long.is( src ) || _.routine.is( src ) ); + _.assert( _.number.is( length ) || _.countable.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( src === null || _.number.is( src ) || this.like( src ) || _.countable.is( src ) || _.routine.is( src ) ); + } + return this._makeUndefined( ... arguments ); +} + +// + + + _.long._lengthOf = function _lengthOf( src ) +{ + return src.length; +} + +// + + + _.long.lengthOf = function lengthOf( src ) +{ + _.assert( arguments.length === 1 ); + _.assert( this.like( src ) ); + return this._lengthOf( src ); +} + +// + + + _.long._exportStringDiagnosticShallow = function _exportStringDiagnosticShallow( src ) +{ + if( _.unroll.is( src ) ) + return `{- ${_.entity.strType( src )}.unroll with ${this._lengthOf( src )} elements -}`; + return `{- ${_.entity.strType( src )} with ${this._lengthOf( src )} elements -}`; +} + +// + + + _.long.exportStringDiagnosticShallow = function exportStringDiagnosticShallow( src, o ) +{ + _.assert( this.like( src ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( o === undefined || _.object.isBasic( o ) ); + return this._exportStringDiagnosticShallow( ... arguments ); +} + +// + + + _.longIs = _.long.is.bind( _.long ) + _.longLike = _.long.like.bind( _.long ) + + /* _.longIs = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.longLike = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.argumentsArray.is = function is( src ) +{ + return Object.prototype.toString.call( src ) === '[object Arguments]'; +} + +// + + + _.argumentsArray.like = function like( src ) +{ + if( Array.isArray( src ) ) + return true; + if( Object.prototype.toString.call( src ) === '[object Arguments]' ) + return true; + return false; +} + +// + + + _.argumentsArrayIs = _.argumentsArray.is.bind( _.argumentsArray ) + /* _.argumentsArrayIs = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.array.is = function is( src ) +{ + return Array.isArray( src ); + // return Object.prototype.toString.call( src ) === '[object Array]'; +} + +// + + + _.array.like = function like( src ) /* qqq : cover */ +{ + return this.is( src ); +} + +// + + + _.array.isEmpty = function isEmpty( src ) +{ + if( !_.array.is( src ) ) + return false; + return src.length === 0; +} + +// + + + _.array.likeResizable = function likeResizable( src ) +{ + return _.array.is( src ); +} + +// + + + _.array._make = function _make( src, length ) +{ + if( arguments.length === 2 ) + { + let data = length; + if( _.number.is( length ) ) + { + data = src; + } + else if( length.length ) + { + length = length.length; + } + if( _.countable.is( length ) ) + { + data = [ ... length ]; + length = data.length; + } + + return fill( new Array( length ), data ); + } + else if( arguments.length === 1 ) + { + if( _.number.is( src ) ) + return new Array( src ); + if( _.countable.is( src ) ) + return [ ... src ]; + } + return []; + + /* */ + + function fill( dst, data ) + { + if( data === null || data === undefined ) + return dst; + let l = Math.min( length, data.length ); + for( let i = 0 ; i < l ; i++ ) + dst[ i ] = data[ i ]; + return dst; + } + +} + +// + + + _.array.make = function make( src, length ) +{ + // if( !( arguments.length === 0 || src === null || _.countable.is( src ) || _.numberIs( src ) ) ) + // debugger; + _.assert( arguments.length === 0 || src === null || _.countable.is( src ) || _.numberIs( src ) ); + _.assert( length === undefined || !_.number.is( src ) || !_.number.is( length ) ); + _.assert( arguments.length < 2 || _.number.is( length ) || _.countable.is( length ) ); + _.assert( arguments.length <= 2 ); + return this._make( ... arguments ); +} + +// + + + _.array.as = function as( src ) +{ + _.assert( arguments.length === 1 ); + _.assert( src !== undefined ); + + //src === undefined check below conflicts with above assert + // if( src === null || src === undefined ) + if( src === null ) + return []; + else if( _.array.is( src ) ) + return src; + else if( _.countable.like( src ) ) + return [ ... src ]; + else + return [ src ]; + +} + +// + + + _.arrayIs = _.array.is.bind( _.array ) + _.arrayLike = _.array.like.bind( _.array ) + _.arrayIsEmpty = _.array.isEmpty.bind( _.array ) + _.arrayLikeResizable = _.array.likeResizable.bind( _.array ) + /* _.arrayIs = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.arrayLike = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.arrayIsEmpty = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.arrayLikeResizable = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.unroll.is = function is( src ) +{ + if( !_.arrayIs( src ) ) + return false; + return !!src[ unrollSymbol ]; +} + +// + + + _.unroll.from = function from( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + if( this.is( src ) ) + return src; + return this.make( src ); +} + +// + + + _.unroll._make = function _make( src, length ) +{ + let result = _.array._make( ... arguments ); + result[ unrollSymbol ] = true; + if + ( + ( src !== null && src !== undefined && !_.unroll.is( src ) ) + || ( src !== null && src !== undefined && !_.unroll.is( src ) ) + ) + result = _.unroll.normalize( result ); + return result; + + // let result; + // result = _.array._make( ... arguments ); + // result[ unrollSymbol ] = true; + // if( src !== null && src !== undefined && !_.unroll.is( src ) ) + // result = _.unroll.normalize( result ); + // return result; +} + +// + + + _.unroll.make = function make( src, length ) +{ + // if( !( arguments.length === 0 || src === null || _.countable.is( src ) || _.numberIs( src ) ) ) + // debugger; + _.assert( arguments.length === 0 || src === null || _.countable.is( src ) || _.numberIs( src ) ); + _.assert( length === undefined || !_.number.is( src ) || !_.number.is( length ) ); + _.assert( arguments.length < 2 || _.number.is( length ) || _.countable.is( length ) ); + _.assert( arguments.length <= 2 ); + return this._make( ... arguments ); +} + +// + + + _.unroll.normalize = function normalize( dstArray ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + + for( let a = 0 ; a < dstArray.length ; a++ ) + { + if( _.unrollIs( dstArray[ a ] ) ) + { + let args = [ a, 1 ]; + args.push.apply( args, dstArray[ a ] ); + dstArray.splice.apply( dstArray, args ); + a += args.length - 3; + /* no normalization of ready unrolls, them should be normal */ + } + else if( _.arrayIs( dstArray[ a ] ) ) + { + _.unroll.normalize( dstArray[ a ] ); + } + } + + return dstArray; +} + +// + + + _.unroll.append = function append( dstArray ) +{ + _.assert( arguments.length >= 1 ); + _.assert( _.longIs( dstArray ) || dstArray === null, 'Expects long or unroll' ); + + dstArray = dstArray || []; + + _append( dstArray, Array.prototype.slice.call( arguments, 1 ) ); + + return dstArray; + + function _append( dstArray, srcArray ) + { + _.assert( arguments.length === 2 ); + + for( let a = 0, len = srcArray.length ; a < len; a++ ) + { + if( _.unrollIs( srcArray[ a ] ) ) + { + _append( dstArray, srcArray[ a ] ); + } + else + { + if( _.arrayIs( srcArray[ a ] ) ) + _.unroll.normalize( srcArray[ a ] ) + dstArray.push( srcArray[ a ] ); + } + } + + return dstArray; + } + +} + +// + + + _.unrollAppend = _.unroll.append.bind( _.unroll ) + _.unrollIs = _.unroll.is.bind( _.unroll ) + /* _.unrollIs = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.bufferRaw.is = function rawIs( src ) +{ + let type = Object.prototype.toString.call( src ); + // let result = type === '[object ArrayBuffer]'; + // return result; + if( type === '[object ArrayBuffer]' || type === '[object SharedArrayBuffer]' ) + return true; + return false; +} + +// + + + _.bufferRawIs = _.bufferRaw.is.bind( _.bufferRaw ) + /* _.bufferRawIs = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.bufferTyped.is = function is( src ) +{ + if( !( src instanceof Object.getPrototypeOf( Int8Array ) ) ) + return false; + if( _.buffer.nodeIs( src ) ) + return false; + return true; +} + +// + + + _.bufferTypedIs = _.bufferTyped.is.bind( _.bufferTyped ) + /* _.bufferTypedIs = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.bufferNode.is = function nodeIs( src ) +{ + // if( typeof BufferNode !== 'undefined' ) + if( _global_.BufferNode ) + return src instanceof BufferNode; + return false; +} + +// + + + _.bufferNodeIs = _.bufferNode.is.bind( _.bufferNode ) + _.bufferNode.nodeIs = function nodeIs( src ) +{ + // if( typeof BufferNode !== 'undefined' ) + if( _global_.BufferNode ) + return src instanceof BufferNode; + return false; +} + +// + + + /* _.bufferNodeIs = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + + _.buffer.like = function anyIs( src ) +{ + if( src instanceof ArrayBuffer ) + return true; + if( _global.BufferRawShared && src instanceof SharedArrayBuffer ) + return true; + if( ArrayBuffer.isView( src ) ) + return true; + return false; +} + +// + + + _.buffer.nodeIs = _.bufferNode.nodeIs.bind( _.bufferNode ) + + _.vector.is = function is( src ) +{ + + if( _.arrayIs( src ) ) + return true; + if( _.primitive.is( src ) ) + return false; + + if( _.class.methodIteratorOf( src ) ) + if( _.number.is( src.length ) ) /* yyy */ + if( !_.mapIs( src ) ) + return true; + + return false; +} + +// + + + _.vector.like = function like( src ) +{ + return _.vector.is( src ); +} + +// + + + _.vectorIs = _.vector.is.bind( _.vector ) + _.vectorLike = _.vector.like.bind( _.vector ) + /* _.vectorIs = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.vectorLike = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.primitive._is = ( function _primitiveIs_functor() +{ + const is = new Set(); + is.add( '[object Symbol]' ); + is.add( '[object Number]' ); + is.add( '[object BigInt]' ); + is.add( '[object Boolean]' ); + is.add( '[object String]' ); + return _primitiveIs; + + function _primitiveIs( src, typeStr ) + { + return is.has( typeStr ); + } + +} )(); + +// + + + _.primitive.is = function is( src ) +{ + if( !src ) + return true; + let t = Object.prototype.toString.call( src ); + return _.primitive._is( src, t ); +} + +// + + + _._primitiveIs = _.primitive._is.bind( _.primitive ) + _.primitiveIs = _.primitive.is.bind( _.primitive ) + /* _._primitiveIs = undefined; + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.primitiveIs = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.number.is = function is( src ) +{ + return typeof src === 'number'; + return Object.prototype.toString.call( src ) === '[object Number]'; +} + +// + + + _.number.isFinite = function numberIsFinite( src ) +{ + if( !_.number.is( src ) ) + return false; + return isFinite( src ); +} + +// + + + _.number.defined = function numberIsFinite( src ) +{ + if( !_.number.is( src ) ) + return false; + return isFinite( src ); +} + +// + + + _.number.fromStrMaybe = function fromStrMaybe( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ) || _.number.is( src ) ); + + if( _.number.is( src ) ) + return src; + if( !src ) /* qqq : cover */ + return src; + + // let parsed = !src ? NaN : Number( src ); /* Dmytro : it is strange code, the previous branch checks this condition */ + // if( !isNaN( parsed ) ) + // return parsed; + // return src; + + let parsed = src ? Number( src ) : NaN; + if( !isNaN( parsed ) ) + return parsed; + return src; +} + +// + + + _.number.s = { + "areAll" : function areAll( src ) +{ + _.assert( arguments.length === 1 ); + + if( _.bufferTypedIs( src ) ) + return true; + + if( _.argumentsArray.like( src ) && !_.arrayIsEmpty( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( !_.number.is( src[ s ] ) ) + return false; + + return true; + } + + return false; +}, + "areFinite" : function areFinite( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + + if( !_.number.s.areAll( src ) ) + return false; + + if( _.longIs( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( !_.number.isFinite( src[ s ] ) ) + return false; + } + + return true; +}, + "arePositive" : function arePositive( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + + if( !_.number.s.areAll( src ) ) + return false; + + if( _.longIs( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( src[ s ] < 0 || !_.number.isNotNan( src[ s ] ) ) + return false; + } + + return true; +}, + "areInt" : function areInt( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + + if( !_.number.s.areAll( src ) ) + return false; + + if( _.longIs( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( !_.intIs( src[ s ] ) ) + return false; + } + + return true; +}, + "total" : function numbersTotal( numbers ) +{ + let result = 0; + _.assert( _.longIs( numbers ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + for( let n = 0 ; n < numbers.length ; n++ ) + { + let number = numbers[ n ]; + _.assert( _.number.is( number ) ) + result += number; + } + return result; +}, + "from" : function numbersFrom( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.strIs( src ) ) + return _.number.from( src ); + + if( _.number.is( src ) ) + return src; + + let result; + + if( _.longIs( src ) ) + { + result = []; + for( let s = 0 ; s < src.length ; s++ ) + result[ s ] = _.number.from( src[ s ] ); + } + else if( _.object.isBasic( src ) ) + { + result = Object.create( null ); + for( let s in src ) + result[ s ] = _.number.from( src[ s ] ); + } + else + { + result = _.number.from( src ); + } + + return result; +}, + "slice" : function numbersSlice( src, f, l ) +{ + if( _.argumentsArray.like( src ) ) + _.assert( _.number.s.areAll( src ) ) + + if( _.number.is( src ) ) + return src; + return _.longSlice( src, f, l ); +}, + "make" : function numbersMake( src, length ) +{ + let result; + + if( _.vector.adapterIs( src ) ) + src = _.vectorAdapter.slice( src ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.number.is( src ) || _.argumentsArray.like( src ) ); + + if( _.argumentsArray.like( src ) ) + { + _.assert( src.length === length ); + result = _.long.makeUndefined( length ); + for( let i = 0 ; i < length ; i++ ) + result[ i ] = src[ i ]; + } + else + { + result = _.long.makeUndefined( length ); + for( let i = 0 ; i < length ; i++ ) + result[ i ] = src; + } + + return result; +}, + "fromNumber" : function numbersFromNumber( src, length ) +{ + + if( _.vector.adapterIs( src ) ) + src = _.vectorAdapter.slice( src ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.number.is( src ) || _.argumentsArray.like( src ) ); + + if( _.argumentsArray.like( src ) ) + { + _.assert( src.length === length ); + return src; + } + + // debugger; /* xxx2 : test */ + let result = _.long.makeUndefined( length ); + for( let i = 0 ; i < length ; i++ ) + result[ i ] = src; + + return result; +}, + "fromInt" : function numbersFromInt( dst, length ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.intIs( dst ) || _.arrayIs( dst ), 'Expects array of number as argument' ); + _.assert( length >= 0 ); + + if( _.number.is( dst ) ) + { + debugger; + // dst = _.longFillTimes( [], length , dst ); + dst = _.longFill( [], dst, length ); + } + else + { + for( let i = 0 ; i < dst.length ; i++ ) + _.assert( _.intIs( dst[ i ] ), 'Expects integer, but got', dst[ i ] ); + _.assert( dst.length === length, 'Expects array of length', length, 'but got', dst ); + } + + return dst; +}, + "make_functor" : function numbersMake_functor( length ) +{ + // let _ = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.number.is( length ) ); + + function numbersMake( src ) + { + return _.number.s.make( src, length ); + } + + return numbersMake; +}, + "from_functor" : function numbersFrom_functor( length ) +{ + // let _ = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.number.is( length ) ); + + function numbersFromNumber( src ) + { + return _.number.s.fromNumber( src, length ); + } + + return numbersFromNumber; +} +}; + +// + + + + _.aux.is = function is( src ) +{ + + if( !src ) + return false; + + let proto = Object.getPrototypeOf( src ); + + if( proto === null ) + return true; + + if( proto === Object.prototype ) + { + if( src[ Symbol.iterator ] ) + return Object.prototype.toString.call( src ) !== '[object Arguments]'; + return true; + } + + if( _.routineIs( proto[ Symbol.iterator ] ) ) + return false; + + if( !_.primitive.is( proto ) ) + if( !Reflect.has( proto, 'constructor' ) || proto.constructor === Object.prototype.constructor ) + return true; + + return false; +} + +// + + + _.aux.isPure = function isPure( src ) +{ + + if( !src ) + return false; + + let proto = Object.getPrototypeOf( src ); + + if( proto === null ) + return true; + + if( proto.constructor === Object ) + return false; + + if( _.routineIs( proto[ Symbol.iterator ] ) ) + return false; + + if( !_.primitive.is( proto ) ) + if( !Reflect.has( proto, 'constructor' ) ) + return true; + + return false; +} + +// + + + _.aux.isPolluted = function isPolluted( src ) +{ + + if( !src ) + return false; + + let proto = Object.getPrototypeOf( src ); + + if( proto === null ) + return false; + + if( proto === Object.prototype ) + { + if( src[ Symbol.iterator ] ) + return Object.prototype.toString.call( src ) !== '[object Arguments]'; + return true; + } + + if( _.routineIs( proto[ Symbol.iterator ] ) ) + return false; + + if( proto.constructor === Object ) + return true; + + return false; +} + +// + + + _.aux.isPrototyped = function isPrototyped( src ) +{ + + if( !src ) + return false; + + let proto = Object.getPrototypeOf( src ); + + if( proto === null ) + return false; + + if( proto === Object.prototype ) + return false; + + if( _.routineIs( proto[ Symbol.iterator ] ) ) + return false; + + if( !_.primitive.is( proto ) ) + if( !Reflect.has( proto, 'constructor' ) || proto.constructor === Object.prototype.constructor ) + return true; + + return false; +} + +// + + + _.aux.like = function like( src ) +{ + return _.aux.is( src ); +} + +// + + + _.aux._make = function _make( src ) +{ + if( src ) + { + if( this.like( src ) ) + return this._cloneShallow( src ); + else + return this.extendUniversal( Object.create( null ), src ); + } + return Object.create( null ); +} + +// + + + _.aux.make = function make( src, length ) +{ + _.assert( arguments.length === 0 || src === null || !_.primitive.is( src ) ); + _.assert( length === undefined || length === 0 ); + _.assert( arguments.length <= 2 ); + return this._make( ... arguments ); +} + +// + + + _.aux._makeUndefined = function _makeUndefined( src, length ) +{ + let result = Object.create( null ); + return result; +} + +// + + + _.aux.makeUndefined = function makeUndefined( src, length ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + + if( arguments.length === 2 ) + { + _.assert( this.like( src ) ); + _.assert( _.number.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( _.number.is( src ) || this.like( src ) ); + } + + return this._makeUndefined( src ); +} + +// + + + _.aux._keys = function _keys( o ) +{ + let result = []; + + _.routine.options( _keys, o ); + + let srcMap = o.srcMap; + let selectFilter = o.selectFilter; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( this.like( srcMap ) ); + _.assert( selectFilter === null || _.routine.is( selectFilter ) ); + + /* */ + + if( o.onlyEnumerable ) + { + let result1 = []; + + if( o.onlyOwn ) + { + for( let k in srcMap ) + if( Object.hasOwnProperty.call( srcMap, k ) ) + result1.push( k ); + } + else + { + for( let k in srcMap ) + result1.push( k ); + } + + filter( srcMap, result1 ); + + } + else + { + + if( o.onlyOwn ) + { + filter( srcMap, Object.getOwnPropertyNames( srcMap ) ); + } + else + { + let proto = srcMap; + result = []; + do + { + filter( proto, Object.getOwnPropertyNames( proto ) ); + proto = Object.getPrototypeOf( proto ); + } + while( proto ); + } + + } + + return result; + + /* */ + + function filter( srcMap, keys ) + { + + if( !selectFilter ) + { + /* qqq : for junior : rewrite without arrayAppend and without duplicating array */ + arrayAppendArrayOnce( result, keys ); + } + else for( let k = 0 ; k < keys.length ; k++ ) + { + let e = selectFilter( srcMap, keys[ k ] ); + if( e !== undefined ) + arrayAppendOnce( result, e ); + /* qqq : for junior : rewrite without arrayAppend and without duplicating array */ + } + + } + + /* */ + + function arrayAppendOnce( dst, element ) + { + let i = dst.indexOf( element ); + if( i === -1 ) + dst.push( element ); + return dst; + } + + /* */ + + function arrayAppendArrayOnce( dst, src ) + { + src.forEach( ( element ) => + { + let i = dst.indexOf( element ); + if( i === -1 ) + dst.push( element ); + }); + return dst; + } + + /* */ + +} +_.aux._keys.defaults = +{ + "srcMap" : null, + "onlyOwn" : 0, + "onlyEnumerable" : 1, + "selectFilter" : null +} + +// + + + _.aux.keys = function keys( srcMap, o ) +{ + let result; + + // _.assert( this === _.object ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( keys, o || null ); + // _.assert( !_.primitive.is( srcMap ) ); + + o.srcMap = srcMap; + + result = this._keys( o ); + + return result; +} +_.aux.keys.defaults = +{ "onlyOwn" : 0, "onlyEnumerable" : 1 } + +// + + + _.aux.namespaceOf = function namespaceOf( src ) +{ + + if( _.map.is( src ) ) + return _.map; + if( _.aux.is( src ) ) + return _.aux; + + return null; +} + +// + + + _.aux._lengthOf = function _lengthOf( src ) +{ + return this.keys( src ).length; +} + +// + + + _.aux.lengthOf = function lengthOf( src ) +{ + _.assert( arguments.length === 1 ); + _.assert( this.like( src ) ); + return this._lengthOf( src ); +} + +// + + + _.aux.supplement = function supplement( dstMap, srcMap ) +{ + if( dstMap === null && arguments.length === 2 ) + return Object.assign( Object.create( null ), srcMap ); + if( dstMap === null ) + dstMap = Object.create( null ); + + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + _.assert( this.like( dstMap ), () => `Expects dstMap::${this.NamespaceName} as the first argument` ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + srcMap = arguments[ a ]; + this._supplementWithProps( dstMap, srcMap ); + } + + return dstMap +} + +// + + + _.aux._exportStringDiagnosticShallow = function _exportStringDiagnosticShallow( src, o ) +{ + return `{- ${_.entity.strType( src )} with ${this._lengthOf( src )} elements -}`; +} + +// + + + _.aux.exportStringDiagnosticShallow = function exportStringDiagnosticShallow( src, o ) +{ + _.assert( this.like( src ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( o === undefined || _.object.isBasic( o ) ); + return this._exportStringDiagnosticShallow( ... arguments ); +} + +// + + + _.constructible.is = function is( src ) /* xxx qqq : optimize */ +{ + if( _.primitive.is( src ) ) + return false; + + let proto = Object.getPrototypeOf( src ); + if( proto === null ) + return false; + + if( !Reflect.has( proto, 'constructor' ) ) + return false; + if( proto.constructor === Object ) + return false; + + if( _.aux.is( src ) ) /* xxx : remove? */ + return false; + if( _.vector.is( src ) ) + return false; + if( _.set.is( src ) ) + return false; + if( _.hashMap.is( src ) ) + return false; + + return true; +} + +// + + + _.constructibleIs = function is( src ) /* xxx qqq : optimize */ +{ + if( _.primitive.is( src ) ) + return false; + + let proto = Object.getPrototypeOf( src ); + if( proto === null ) + return false; + + if( !Reflect.has( proto, 'constructor' ) ) + return false; + if( proto.constructor === Object ) + return false; + + if( _.aux.is( src ) ) /* xxx : remove? */ + return false; + if( _.vector.is( src ) ) + return false; + if( _.set.is( src ) ) + return false; + if( _.hashMap.is( src ) ) + return false; + + return true; +} + +// + + + + _.container._functor_functor = function _functor_functor( methodName, typer, which ) +{ + _.assert( !!( methodName ) ); + if( !typer ) + typer = 'namespaceOf'; + if( !which ) + which = 0; + if( which === 0 ) + return end( _functor0 ); + if( which === 1 ) + return end( _functor1 ); + _.assert( 0 ); + + function _functor0( container ) + { + _.assert( arguments.length === 1 ); + _.assert( _.routine.is( this[ typer ] ), () => `No routine::${typer} in the namesapce::${this.NamespaceName}` ); + const namespace = this[ typer ]( container ); + _.assert( _.routine.is( namespace[ methodName ] ), `No routine::${methodName} in the namesapce::${namespace.NamespaceName}` ); + return namespace[ methodName ].bind( namespace, container ); + } + + function _functor1( container ) + { + _.assert( arguments.length === 1 ); + _.assert( _.routine.is( this[ typer ] ), () => `No routine::${typer} in the namesapce::${this.NamespaceName}` ); + const namespace = this[ typer ]( container ); + _.assert( _.routine.is( namespace[ methodName ] ), `No routine::${methodName} in the namesapce::${namespace.NamespaceName}` ); + const routine0 = namespace[ methodName ]; + return routine1.bind( namespace ); + function routine1( arg1, ... args ) + { + return routine0.call( this, arg1, container, ... args ); + } + } + + function end( result ) + { + result.functor = new Function( `return _.long._functor_functor( '${methodName}', '${typer}', ${which} )` ); + return result; + } + +} + +// + + + + _.object.is = function is( src ) /* xxx : qqq : for junior : optimize */ +{ + + if( Object.prototype.toString.call( src ) === '[object Object]' ) + return true; + + if( _.primitive.is( src ) ) + return false; + + // if( _.vector.is( src ) ) + // return false; + + if( _.long.is( src ) ) + return false; + + if( _.set.is( src ) ) + return false; + + if( _.hashMap.is( src ) ) + return false; + + if( _.routine.isTrivial( src ) ) + return false; + + return true; +} + +// + + + _.object.like = function like( src ) /* xxx : qqq : for junior : optimize */ +{ + return _.object.is( src ); + // if( _.object.isBasic( src ) ) + // return true; + // + // if( _.primitive.is( src ) ) + // return false; + // + // if( _.vector.is( src ) ) + // return false; + // + // if( _.routine.isTrivial( src ) ) + // return false; + // + // if( _.set.is( src ) ) + // return false; + // + // if( _.hashMap.is( src ) ) + // return false; + // + // return true; +} + +// + + + _.objectLike = _.object.like.bind( _.object ) + /* _.objectLike = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.set.is = function is( src ) +{ + if( !src ) + return false; + return src instanceof Set || src instanceof WeakSet; +} + +// + + + _.set.like = function like( src ) +{ + return _.set.is( src ); +} + +// + + + _.setIs = _.set.is.bind( _.set ) + _.setLike = _.set.like.bind( _.set ) + /* _.setIs = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.setLike = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.map.is = function is( src ) +{ + + if( !src ) + return false; + + let proto = Object.getPrototypeOf( src ); + + if( proto === null ) + return true; + + if( proto === Object.prototype ) + { + if( src[ Symbol.iterator ] ) + return Object.prototype.toString.call( src ) !== '[object Arguments]'; + return true; + } + + return false; +} + +// + + + _.map.isPure = function isPure( src ) +{ + if( !src ) + return false; + + if( Object.getPrototypeOf( src ) === null ) + return true; + + return false; +} + +// + + + _.map.isPolluted = function isPolluted( src ) +{ + + if( !src ) + return false; + + let proto = Object.getPrototypeOf( src ); + + if( proto === null ) + return false; + + if( proto === Object.prototype ) + { + if( src[ Symbol.iterator ] ) + return Object.prototype.toString.call( src ) !== '[object Arguments]'; + return true; + } + + return false; +} + +// + + + _.map.sureHasAll = function sureHasAll( srcMap, all, msg ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4, 'Expects two, three or four arguments' ); + + let but = Object.keys( _.mapBut_( null, all, srcMap ) ); + + if( but.length > 0 ) + { + let err; + if( arguments.length === 2 ) + { + err = _._err + ({ + args : [ `${ _.entity.strType( srcMap ) } should have fields :`, _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + else + { + let arr = []; + for( let i = 2; i < arguments.length; i++ ) + { + if( _.routine.is( arguments[ i ] ) ) + arguments[ i ] = ( arguments[ i ] )(); + arr.push( arguments[ i ] ); + } + err = _._err + ({ + args : [ arr.join( ' ' ), _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + debugger; /* eslint-disable-line no-debugger */ + throw err; + return false; + } + + return true; +} + +// + + + _.map.sureHasOnly = function sureHasOnly( srcMap, screenMaps, msg ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4, 'Expects two, three or four arguments' ); + + /* qqq : for Dmytro : bad ! */ + // let but = Object.keys( _.mapBut_( null, srcMap, screenMaps ) ); + let but = Object.keys( _.mapButOld( srcMap, screenMaps ) ); + + if( but.length > 0 ) + { + let err; + if( arguments.length === 2 ) + err = _._err + ({ + args : [ `${ _.entity.strType( srcMap ) } should have no fields :`, _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + else + { + let arr = []; + for( let i = 2; i < arguments.length; i++ ) + { + if( _.routine.is( arguments[ i ] ) ) + arguments[ i ] = ( arguments[ i ] )(); + arr.push( arguments[ i ] ); + } + err = _._err + ({ + args : [ arr.join( ' ' ), _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + debugger; /* eslint-disable-line no-debugger */ + throw err; + return false; + } + + return true; +} + +// + + + _.map.sureHasNoUndefine = function sureHasNoUndefine( srcMap, msg ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 || arguments.length === 3, 'Expects one, two or three arguments' ) + + let but = []; + + for( let s in srcMap ) + if( srcMap[ s ] === undefined ) + but.push( s ); + + if( but.length > 0 ) + { + let err; + if( arguments.length === 1 ) + { + err = _._err + ({ + args : [ `${ _.entity.strType( srcMap ) } should have no undefines, but has :`, _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + else + { + let arr = []; + for( let i = 1; i < arguments.length; i++ ) + { + if( _.routine.is( arguments[ i ] ) ) + arguments[ i ] = ( arguments[ i ] )(); + arr.push( arguments[ i ] ); + } + err = _._err + ({ + args : [ arr.join( ' ' ), _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + debugger; /* eslint-disable-line no-debugger */ + throw err; + return false; + } + + return true; +} + +// + + + _.map.assertHasOnly = function assertHasOnly( srcMap, screenMaps, msg ) +{ + if( Config.debug === false ) + return true; + return _.map.sureHasOnly.apply( this, arguments ); + + /* */ + + // _.assert( 2 <= arguments.length && arguments.length <= 4, 'Expects two, three or four arguments' ); + // + // let but = mapButKeys( srcMap, screenMaps ); + // + // if( but.length > 0 ) + // { + // let err; + // let msgKeys = _.strQuote( but ).join( ', ' ); + // if( arguments.length === 2 ) + // err = errFromArgs([ `${ _.entity.strType( srcMap ) } should have no fields : ${ msgKeys }` ]); + // else + // err = errFromArgs([ msgMake( arguments ), msgKeys ]); + // throw err; + // } + // + // return true; + // + // /* */ + // + // function mapButKeys( srcMap, butMap ) + // { + // let result = []; + // _.assert( !_.primitive.is( srcMap ), 'Expects map {-srcMap-}' ); + // + // /* aaa : allow and cover vector */ /* Dmytro : this inlining is not needed, that was mistake */ + // if( _.vector.is( butMap ) ) + // { + // /* aaa : for Dmytro : bad */ /* Dmytro : this inlining is not needed, that was mistake */ + // for( let s in srcMap ) + // { + // let m; + // for( m = 0 ; m < butMap.length ; m++ ) + // { + // /* aaa : for Dmytro : was bad implementation. cover */ /* Dmytro : this inlining is not needed, that was mistake */ + // if( _.primitive.is( butMap[ m ] ) ) + // { + // if( s === butMap[ m ] ) + // break; + // } + // else + // { + // if( s in butMap[ m ] ) + // break; + // } + // } + // + // if( m === butMap.length ) + // result.push( s ); + // } + // } + // else if( !_.primitive.is( butMap ) ) + // { + // for( let s in srcMap ) + // { + // if( !( s in butMap ) ) + // result.push( s ); + // } + // } + // else + // { + // _.assert( 0, 'Expects object-like or long-like {-butMap-}' ); + // } + // + // return result; + // } + // + // /* */ + // + // function errFromArgs( args ) + // { + // return _._err + // ({ + // args, + // level : 2, + // }); + // } + // + // /* */ + // + // function msgMake( args ) + // { + // let arr = []; + // for( let i = 2; i < args.length; i++ ) + // { + // if( _.routineIs( args[ i ] ) ) + // args[ i ] = args[ i ](); + // arr.push( args[ i ] ); + // } + // return arr.join( ' ' ); + // } +} + +// + + + _.map.assertHasNoUndefine = function assertHasNoUndefine( srcMap, msg ) +{ + if( Config.debug === false ) + return true; + + /* */ + + _.assert( 1 <= arguments.length && arguments.length <= 3, 'Expects one, two or three arguments' ) + _.assert( !_.primitive.is( srcMap ) ); + + let but = []; + + for( let s in srcMap ) + if( srcMap[ s ] === undefined ) + but.push( s ); + + if( but.length > 0 ) + { + let msgKeys = _.strQuote( but ).join( ', ' ); + if( arguments.length === 1 ) + throw errFromArgs([ `${ _.entity.strType( srcMap ) } should have no undefines, but has : ${ msgKeys }` ]); + else + throw errFromArgs([ msgMake( arguments ), msgKeys ]) + } + + return true; + + /* */ + + function errFromArgs( args ) + { + return _._err + ({ + args, + level : 2, + }); + } + + /* */ + + function msgMake( args ) + { + let arr = []; + for( let i = 1 ; i < args.length ; i++ ) + { + if( _.routine.is( args[ i ] ) ) + args[ i ] = args[ i ](); + arr.push( args[ i ] ); + } + return arr.join( ' ' ); + } +} + +// + + + _.map.extend = function extend( dstMap, srcMap ) +{ + + if( dstMap === null ) + dstMap = Object.create( null ); + + if( arguments.length === 2 ) + { + let srcProto = Object.getPrototypeOf( srcMap ); + if( srcProto === null || srcProto === Object.prototype ) + return Object.assign( dstMap, srcMap ); + } + + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + _.assert( this.like( dstMap ), () => `Expects dstMap::${this.NamespaceName} as the first argument` ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + let srcMap = arguments[ a ]; + + _.assert( !_.primitive.is( srcMap ), 'Expects non-primitive' ); + + let srcProto = Object.getPrototypeOf( srcMap ); + if( srcProto === null || srcProto === Object.prototype ) + Object.assign( dstMap, srcMap ); + else + this._extendWithProps( dstMap, srcMap ); + + } + + return dstMap; +} + +// + + + _.map.supplement = function supplement( dstMap, srcMap ) +{ + if( dstMap === null && arguments.length === 2 ) + return Object.assign( Object.create( null ), srcMap ); + if( dstMap === null ) + dstMap = Object.create( null ); + + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + _.assert( this.like( dstMap ), () => `Expects dstMap::${this.NamespaceName} as the first argument` ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + srcMap = arguments[ a ]; + this._supplementWithProps( dstMap, srcMap ); + } + + return dstMap +} + +// + + + _.mapIs = _.map.is.bind( _.map ) + _.mapIsPure = _.map.isPure.bind( _.map ) + _.mapIsPolluted = _.map.isPolluted.bind( _.map ) + _.mapExtend = _.map.extend.bind( _.map ) + _.mapSupplement = _.map.supplement.bind( _.map ) + /* _.mapIs = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.mapExtend = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.mapSupplement = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.hashMap.is = function is( src ) +{ + if( !src ) + return false; + return src instanceof HashMap || src instanceof HashMapWeak; +} + +// + + + _.hashMap.like = function like( src ) +{ + return _.hashMap.is( src ); +} + +// + + + _.hashMapIs = _.hashMap.is.bind( _.hashMap ) + _.hashMapLike = _.hashMap.like.bind( _.hashMap ) + /* _.hashMapIs = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.hashMapLike = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.countable.is = function is( src ) +{ + + if( _.arrayIs( src ) ) + return true; + + if( _.primitive.is( src ) ) + return false; + + // if( _.routine.like( _.class.methodIteratorOf( src ) ) ) + // if( !_.mapIs( src ) ) + if( _.class.methodIteratorOf( src ) !== undefined ) /* qqq : for Junior : cover please */ + return true; + + return false; +} + +// + + + _.countable.like = function like( src ) +{ + return _.countable.is( src ); +} + +// + + + _.countableIs = _.countable.is.bind( _.countable ) + /* _.countableIs = function () { [native code] } + +// + + */ + + _.symbol.is = function is( src ) +{ + let result = Object.prototype.toString.call( src ) === '[object Symbol]'; + return result; +} + +// + + + + _.routine._is = function _is( src, typeStr ) +{ + return typeStr === '[object Function]' || typeStr === '[object AsyncFunction]'; +} + +// + + + _.routine.is = function is( src ) +{ + let typeStr = Object.prototype.toString.call( src ); + return _.routine._is( src, typeStr ); +} + +// + + + _.routine._like = function _like( src, typeStr ) +{ + return typeStr === '[object Function]' || typeStr === '[object AsyncFunction]' || typeStr === '[object GeneratorFunction]' || typeStr === '[object AsyncGeneratorFunction]'; +} + +// + + + _.routine.like = function like( src ) +{ + let typeStr = Object.prototype.toString.call( src ); + return _.routine._like( src, typeStr ); +} + +// + + + var __mapButKeys = function __mapButKeys( srcMap, butMap ) +{ + let result = []; + + for( let s in srcMap ) + if( !( s in butMap ) ) + result.push( s ); + + return result; +} + +// + +var __mapUndefinedKeys = function __mapUndefinedKeys( srcMap ) +{ + let result = []; + + for( let s in srcMap ) + if( srcMap[ s ] === undefined ) + result.push( s ); + + return result; +} + +// + +var __keysQuote = function __keysQuote( keys ) +{ + let result = `"${ keys[ 0 ] }"`; + for( let i = 1 ; i < keys.length ; i++ ) + result += `, "${ keys[ i ] }"`; + return result.trim(); +} + +// + +var __primitiveLike = function __primitiveLike( src ) +{ + if( _.primitive.is( src ) ) + return true; + if( _.regexpIs( src ) ) + return true; + if( _.routineIs( src ) ) + return true; + return false; +} + +// + +var __strType = function __strType( src ) +{ + if( _.strType ) + return _.strType( src ); + return String( src ); +} + +// + +var __mapSupplementWithoutUndefined = function __mapSupplementWithoutUndefined( dstMap, srcMap ) +{ + for( let k in srcMap ) + { + if( Config.debug ) + _.assert + ( + __primitiveLike( srcMap[ k ] ), + () => `Defaults map should have only primitive elements, but option::${ k } is ${ __strType( srcMap[ k ] ) }` + ); + if( dstMap[ k ] !== undefined ) + continue; + dstMap[ k ] = srcMap[ k ]; + } +} + +// + +_.routine.optionsWithoutUndefined = function optionsWithoutUndefined( routine, options ) +{ + + if( _.argumentsArray.like( options ) ) + { + _.assert + ( + options.length === 0 || options.length === 1, + `Expects single options map, but got ${options.length} arguments` + ); + if( options.length === 0 ) + options = Object.create( null ) + else + options = options[ 0 ]; + } + + if( Config.debug ) + { + _.assert( arguments.length === 2, 'Expects exactly 2 arguments' ); + _.assert( _.routineIs( routine ) || _.aux.is( routine ) || routine === null, 'Expects an object with options' ); + _.assert( _.object.isBasic( options ) || options === null, 'Expects an object with options' ); + } + + if( options === null || options === undefined ) + options = Object.create( null ); + + let name = routine.name || ''; + let defaults = routine.defaults; + _.assert( _.aux.is( defaults ), `Expects map of defaults, but got ${_.strType( defaults )}` ); + + // if( options === undefined ) /* qqq : for Dmytro : bad : should be error */ + // options = Object.create( null ); + // if( defaults === null ) + // defaults = Object.create( null ); + + // let name = _.routineIs( defaults ) ? defaults.name : ''; + // defaults = ( _.routineIs( defaults ) && defaults.defaults ) ? defaults.defaults : defaults; + // _.assert( _.aux.is( defaults ), 'Expects defined defaults' ); + + /* */ + + if( Config.debug ) + { + let extraKeys = __mapButKeys( options, defaults ); + _.assert( extraKeys.length === 0, () => `Routine "${ name }" does not expect options: ${ __keysQuote( extraKeys ) }` ); + } + + __mapSupplementWithoutUndefined( options, defaults ); + + if( Config.debug ) + { + let undefineKeys = __mapUndefinedKeys( options ); + _.assert + ( + undefineKeys.length === 0, + () => `Options map for routine "${ name }" should have no undefined fields, but it does have ${ __keysQuote( undefineKeys ) }` + ); + } + + return options; +} + +// + + + _.routine.isTrivial = ( function routineIsTrivial_functor() +{ + + const syncPrototype = Object.getPrototypeOf( Function ); + const asyncPrototype = Object.getPrototypeOf( _async ); + return routineIsTrivial; + + function routineIsTrivial( src ) + { + if( !src ) + return false; + let prototype = Object.getPrototypeOf( src ); + if( prototype === syncPrototype ) + return true; + if( prototype === asyncPrototype ) + return true; + return false; + } + + async function _async() + { + } + +} )(); + +// + + + _.routine.extend = function extendCloning( dst, ... srcs ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 || arguments.length === 3 ); + return _.routine._amend + ({ + dst, + srcs : [ ... srcs ], + strategy : 'cloning', + amending : 'extending', + }); + +} + +// + + + _.routine.__mapButKeys = undefined; + +// + + + _.routine.__mapUndefinedKeys = undefined; + +// + + + _.routine.__mapSupplementWithoutUndefined = undefined; + +// + + + _.routine.__mapSupplementWithUndefined = undefined; + +// + + + _.routine.__keysQuote = undefined; + +// + + + _.routine.__strType = undefined; + +// + + + _.routine.__primitiveLike = undefined; + +// + + + _._routineIs = _.routine._is.bind( _.routine ) + _.routineIs = _.routine.is.bind( _.routine ) + _._routineLike = _.routine._like.bind( _.routine ) + _.routineLike = _.routine.like.bind( _.routine ) + _.routineIsTrivial = _.routine.isTrivial.bind( _.routine ) + _.routineExtend = _.routine.extend.bind( _.routine ) + /* _._routineIs = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.routineIs = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _._routineLike = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.routineLike = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.routineIsTrivial = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.routineExtend = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.regexp.is = function is( src ) +{ + return Object.prototype.toString.call( src ) === '[object RegExp]'; +} + +// + + + _.regexp.like = function like( src ) +{ + if( src instanceof RegExp || Object.prototype.toString.call( src ) === '[object String]' ) + return true; + return false; +} + +// + + + + _.props.is = function is( src ) +{ + if( src === null ) + return false; + if( src === undefined ) + return false; + return true; +} + +// + + + _.props.like = function like( src ) +{ + return _.props.is( src ); +} + +// + + + _.props._ofAct = function _ofAct( o ) +{ + let result = Object.create( null ); + + _.routine.options( _ofAct, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( this === _.props ); + _.assert( this.like( o.srcMap ) ); + + let keys = this._keys( o ); + + for( let k = 0 ; k < keys.length ; k++ ) + { + result[ keys[ k ] ] = o.srcMap[ keys[ k ] ]; + } + + return result; +} +_.props._ofAct.defaults = +{ + "srcMap" : null, + "onlyOwn" : 0, + "onlyEnumerable" : 1, + "selectFilter" : null +} + +// + + + _.props.fields = function fields( srcMap, o ) +{ + + _.assert( this === _.props ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( fields, o || null ); + + o.srcMap = srcMap; + o.selectFilter = function selectRoutine( srcMap, k ) + { + if( !_.routine.is( srcMap[ k ] ) ) + return k; + } + + let result = _.props._ofAct( o ); + return result; +} +_.props.fields.defaults = +{ "onlyOwn" : 0, "onlyEnumerable" : 1 } + +// + + + _.props._keys = function _keys( o ) +{ + let result = []; + + _.routine.options( _keys, o ); + + let srcMap = o.srcMap; + let selectFilter = o.selectFilter; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( this.like( srcMap ) ); + _.assert( selectFilter === null || _.routine.is( selectFilter ) ); + + /* */ + + if( o.onlyEnumerable ) + { + let result1 = []; + + if( o.onlyOwn ) + { + for( let k in srcMap ) + if( Object.hasOwnProperty.call( srcMap, k ) ) + result1.push( k ); + } + else + { + for( let k in srcMap ) + result1.push( k ); + } + + filter( srcMap, result1 ); + + } + else + { + + if( o.onlyOwn ) + { + filter( srcMap, Object.getOwnPropertyNames( srcMap ) ); + } + else + { + let proto = srcMap; + result = []; + do + { + filter( proto, Object.getOwnPropertyNames( proto ) ); + proto = Object.getPrototypeOf( proto ); + } + while( proto ); + } + + } + + return result; + + /* */ + + function filter( srcMap, keys ) + { + + if( !selectFilter ) + { + /* qqq : for junior : rewrite without arrayAppend and without duplicating array */ + arrayAppendArrayOnce( result, keys ); + } + else for( let k = 0 ; k < keys.length ; k++ ) + { + let e = selectFilter( srcMap, keys[ k ] ); + if( e !== undefined ) + arrayAppendOnce( result, e ); + /* qqq : for junior : rewrite without arrayAppend and without duplicating array */ + } + + } + + /* */ + + function arrayAppendOnce( dst, element ) + { + let i = dst.indexOf( element ); + if( i === -1 ) + dst.push( element ); + return dst; + } + + /* */ + + function arrayAppendArrayOnce( dst, src ) + { + src.forEach( ( element ) => + { + let i = dst.indexOf( element ); + if( i === -1 ) + dst.push( element ); + }); + return dst; + } + + /* */ + +} +_.props._keys.defaults = +{ + "srcMap" : null, + "onlyOwn" : 0, + "onlyEnumerable" : 1, + "selectFilter" : null +} + +// + + + _.props.keys = function keys( srcMap, o ) +{ + let result; + + // _.assert( this === _.object ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( keys, o || null ); + // _.assert( !_.primitive.is( srcMap ) ); + + o.srcMap = srcMap; + + result = this._keys( o ); + + return result; +} +_.props.keys.defaults = +{ "onlyOwn" : 0, "onlyEnumerable" : 1 } + +// + + + _.props.own = function own( src, key ) +{ + // if( src === null ) + // return false; + // if( src === undefined ) + // return false; + if( _.primitive.is( src ) ) + return false; + return Object.hasOwnProperty.call( src, key ); +} + +// + + + _.props.onlyOwnKeys = function onlyOwnKeys( srcMap, o ) +{ + let result; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( onlyOwnKeys, o || null ); + _.assert( this.like( srcMap ) ); + + o.srcMap = srcMap; + o.onlyOwn = 1; + + result = this._keys( o ); + + if( !o.onlyEnumerable ) + debugger; + + return result; +} +_.props.onlyOwnKeys.defaults = +{ "onlyEnumerable" : 1 } + +// + + + _.props._extendWithProps = function _extendWithProps( dstMap, src ) +{ + for( let k in src ) + dstMap[ k ] = src[ k ]; + return dstMap; +} + +// + + + _.props.extend = function extend( dstMap, srcMap ) +{ + + if( dstMap === null ) + dstMap = Object.create( null ); + + if( arguments.length === 2 ) + { + let srcProto = Object.getPrototypeOf( srcMap ); + if( srcProto === null || srcProto === Object.prototype ) + return Object.assign( dstMap, srcMap ); + } + + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + _.assert( this.like( dstMap ), () => `Expects dstMap::${this.NamespaceName} as the first argument` ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + let srcMap = arguments[ a ]; + + _.assert( !_.primitive.is( srcMap ), 'Expects non-primitive' ); + + let srcProto = Object.getPrototypeOf( srcMap ); + if( srcProto === null || srcProto === Object.prototype ) + Object.assign( dstMap, srcMap ); + else + this._extendWithProps( dstMap, srcMap ); + + } + + return dstMap; +} + +// + + + _.props._supplementWithProps = function _supplementWithProps( dstMap, src ) +{ + for( let k in src ) + if( !( k in dstMap ) ) + dstMap[ k ] = src[ k ]; + return dstMap; +} + +// + + + _.props.supplement = function supplement( dstMap, srcMap ) +{ + if( dstMap === null && arguments.length === 2 ) + return Object.assign( Object.create( null ), srcMap ); + if( dstMap === null ) + dstMap = Object.create( null ); + + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + _.assert( this.like( dstMap ), () => `Expects dstMap::${this.NamespaceName} as the first argument` ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + srcMap = arguments[ a ]; + this._supplementWithProps( dstMap, srcMap ); + } + + return dstMap +} + +// + + + + _.strIs = function is( src ) +{ + let result = Object.prototype.toString.call( src ) === '[object String]'; + return result; +} + +// + + + _.strDefined = function defined( src ) +{ + if( !src ) + return false; + let result = Object.prototype.toString.call( src ) === '[object String]'; + return result; +} + +// + + + _._strBeginOf = function _beginOf( src, begin ) +{ + + // _.assert( _.strIs( src ), 'Expects string' ); + // _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.strIs( begin ) ) + { + if( src.lastIndexOf( begin, 0 ) === 0 ) + return begin; + } + else if( _.regexpIs( begin ) ) + { + let matched = begin.exec( src ); + if( matched && matched.index === 0 ) + return matched[ 0 ]; + } + else _.assert( 0, 'Expects string-like ( string or regexp )' ); + + return undefined; +} + +// + + + _._strEndOf = function _endOf( src, end ) +{ + + // _.assert( _.strIs( src ), 'Expects string' ); + // _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.strIs( end ) ) + { + if( src.indexOf( end, src.length - end.length ) !== -1 ) + return end; + } + else if( _.regexpIs( end ) ) + { + // let matched = end.exec( src ); + let newEnd = RegExp( end.toString().slice(1, -1) + '$' ); + let matched = newEnd.exec( src ); + + //if( matched && matched.index === 0 ) + if( matched && matched.index + matched[ 0 ].length === src.length ) + return matched[ 0 ]; + } + else _.assert( 0, 'Expects string-like ( string or regexp )' ); + + return undefined; +} + +// + + + _._strRemovedBegin = function _removedBegin( src, begin ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + + let result = src; + let beginOf = _._strBeginOf( result, begin ); + if( beginOf !== undefined ) + result = result.substr( beginOf.length, result.length ); + + return result; +} + +// + + + _._strRemovedEnd = function _removedEnd( src, end ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + + let result = src; + let endOf = _._strEndOf( result, end ); + if( endOf !== undefined ) + result = result.substr( 0, result.length - endOf.length ); + + return result; +} + +// + + + _.strBegins = function begins( src, begin ) +{ + + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( _.strIs( begin ) || _.regexpIs( begin ) || _.longIs( begin ), 'Expects string/regexp or array of strings/regexps {-begin-}' ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !_.longIs( begin ) ) + { + let result = _._strBeginOf( src, begin ); + return !( result === undefined ); + // return result === undefined ? false : true; + } + + for( let b = 0, blen = begin.length ; b < blen; b++ ) + { + let result = _._strBeginOf( src, begin[ b ] ); + if( result !== undefined ) + return true; + } + + return false; +} + +// + + + _.strEnds = function ends( src, end ) +{ + + _.assert( _.strIs( src ), () => `Expects argument::src of type::string, but got ${_.entity.strType( src )}` ); + _.assert( _.strIs( end ) || _.regexpIs( end ) || _.longIs( end ), 'Expects string/regexp or array of strings/regexps {-end-}' ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !_.longIs( end ) ) + { + let result = _._strEndOf( src, end ); + return !( result === undefined ); + } + + for( let b = 0, blen = end.length ; b < blen; b++ ) + { + let result = _._strEndOf( src, end[ b ] ); + if( result !== undefined ) + return true; + } + + return false; +} + +// + + + _.strRemoveBegin = function removeBegin( src, begin ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.longIs( src ) || _.strIs( src ), 'Expects string or array of strings {-src-}' ); + _.assert( _.longIs( begin ) || _.strIs( begin ) || _.regexpIs( begin ), 'Expects string/regexp or array of strings/regexps {-begin-}' ); + + let result = []; + let srcIsArray = _.longIs( src ); + + if( _.strIs( src ) && !_.longIs( begin ) ) + return _._strRemovedBegin( src, begin ); + + src = _.array.as( src ); + begin = _.array.as( begin ); + for( let s = 0, slen = src.length ; s < slen ; s++ ) + { + let beginOf = undefined; + let src1 = src[ s ] + for( let b = 0, blen = begin.length ; b < blen ; b++ ) + { + beginOf = _._strBeginOf( src1, begin[ b ] ); + if( beginOf !== undefined ) + break; + } + if( beginOf !== undefined ) + src1 = src1.substr( beginOf.length, src1.length ); + result[ s ] = src1; + } + + if( !srcIsArray ) + return result[ 0 ]; + + return result; +} + +// + + + _.strRemoveEnd = function removeEnd( src, end ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.longIs( src ) || _.strIs( src ), 'Expects string or array of strings {-src-}' ); + _.assert( _.longIs( end ) || _.strIs( end ) || _.regexpIs( end ), 'Expects string/regexp or array of strings/regexps {-end-}' ); + + let result = []; + let srcIsArray = _.longIs( src ); + + if( _.strIs( src ) && !_.longIs( end ) ) + return _._strRemovedEnd( src, end ); + + src = _.array.as( src ); + end = _.array.as( end ); + + for( let s = 0, slen = src.length ; s < slen ; s++ ) + { + let endOf = undefined; + let src1 = src[ s ] + for( let b = 0, blen = end.length ; b < blen ; b++ ) + { + endOf = _._strEndOf( src1, end[ b ] ); + if( endOf !== undefined ) + break; + } + if( endOf !== undefined ) + src1 = src1.substr( 0, src1.length - endOf.length ); + result[ s ] = src1; + } + + if( !srcIsArray ) + return result[ 0 ]; + + return result; +} + +// + + + _.regexpIs = function is( src ) +{ + return Object.prototype.toString.call( src ) === '[object RegExp]'; +} + +// + + + _.symbolIs = function is( src ) +{ + let result = Object.prototype.toString.call( src ) === '[object Symbol]'; + return result; +} + +// + + + _.strBegins = function begins( src, begin ) +{ + + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( _.strIs( begin ) || _.regexpIs( begin ) || _.longIs( begin ), 'Expects string/regexp or array of strings/regexps {-begin-}' ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !_.longIs( begin ) ) + { + let result = _._strBeginOf( src, begin ); + return !( result === undefined ); + // return result === undefined ? false : true; + } + + for( let b = 0, blen = begin.length ; b < blen; b++ ) + { + let result = _._strBeginOf( src, begin[ b ] ); + if( result !== undefined ) + return true; + } + + return false; +} + +// + + + _.object.isBasic = function isBasic( src ) +{ + return Object.prototype.toString.call( src ) === '[object Object]'; +} + +// + + + _.boolLike = function like( src ) +{ + return src === true || src === false || src === 0 || src === 1; + // let type = Object.prototype.toString.call( src ); + // return type === '[object Boolean]' || src === 0 || src === 1; +} + +// + + + _.bool.like = function like( src ) +{ + return src === true || src === false || src === 0 || src === 1; + // let type = Object.prototype.toString.call( src ); + // return type === '[object Boolean]' || src === 0 || src === 1; +} + +// + + + _.boolLikeTrue = function likeTrue( src ) +{ + if( !_.bool.like( src ) ) + return false; + return !!src; +} + +// + + + _.bool.likeTrue = function likeTrue( src ) +{ + if( !_.bool.like( src ) ) + return false; + return !!src; +} + +// + + + _.numberIsFinite = function numberIsFinite( src ) +{ + if( !_.number.is( src ) ) + return false; + return isFinite( src ); +} + +// + + + _.numberIs = function is( src ) +{ + return typeof src === 'number'; + return Object.prototype.toString.call( src ) === '[object Number]'; +} + +// + + + _.intIs = function intIs( src ) +{ + + if( !_.number.is( src ) || !_.number.isFinite( src ) ) + return false; + + return Math.floor( src ) === src; +} + +// + + + _.sure = function sure( condition, ... args ) +{ + + if( !condition || !__boolLike( condition ) ) + { + _sureDebugger( condition ); + if( !_._err ) + throw Error( ... args ); + if( arguments.length === 1 ) + throw _._err + ({ + args : [ 'Assertion fails' ], + level : 2, + }); + else if( arguments.length === 2 ) + throw _._err + ({ + args : [ arguments[ 1 ] ], + level : 2, + }); + else + throw _._err + ({ + args : Array.prototype.slice.call( arguments, 1 ), + level : 2, + }); + } + + return; +} + +// + + + _.mapBut_ = function mapBut_( dstMap, srcMap, butMap ) +{ + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + if( dstMap === null ) + dstMap = arguments[ 0 ] = arguments[ 0 ] || Object.create( null ); + + _.assert( arguments.length === 3, 'Not clear how to construct {-dstMap-}. Please, specify exactly 3 arguments' ); + // if( arguments.length === 2 ) + // { + // butMap = arguments[ 1 ]; + // srcMap = arguments[ 0 ]; + // } + + /* */ + + let o = + { + dstMap, + srcMap, + butMap, + }; + + o = _._mapBut_VerifyMapFields( o ); + + let mapsAreIdentical = o.dstMap === o.srcMap ? 1 : 0; + let butMapsIsCountable = _.countable.is( o.butMap ) ? 2 : 0; + let filterRoutines = + [ + filterNotIdenticalWithAuxScreenMap, + filterIdenticalWithAuxScreenMap, + filterNotIdenticalWithVectorScreenMap, + filterIdenticalWithVectorScreenMap + ]; + let key = mapsAreIdentical + butMapsIsCountable; + let filterRoutine = filterRoutines[ key ]; + let searchingRoutine; + if( butMapsIsCountable ) + searchingRoutine = _screenMapSearchingRoutineFunctor( o.butMap ); + + for( let key in o.srcMap ) + filterRoutine( key ); + + return o.dstMap; + + /* */ + + function filterNotIdenticalWithAuxScreenMap( key ) + { + if( !( key in o.butMap ) ) + o.dstMap[ key ] = o.srcMap[ key ]; + } + + /* */ + + function filterIdenticalWithAuxScreenMap( key ) + { + if( key in o.butMap ) + delete o.dstMap[ key ]; + } + + /* */ + + function filterNotIdenticalWithVectorScreenMap( key ) + { + let butKey = searchingRoutine( o.butMap, key ); + if( butKey !== undefined ) + return; + + o.dstMap[ key ] = o.srcMap[ key ]; + } + + /* */ + + function filterIdenticalWithVectorScreenMap( key ) + { + let butKey = searchingRoutine( o.butMap, key ); + if( butKey !== undefined ) + delete o.dstMap[ key ]; + } + + // let filter = _.props.conditionFrom( filterBut ); + // + // return _._mapBut_ + // ({ + // filter, + // dstMap, + // srcMap, + // butMap, + // }); + // + // /* */ + // + // /* qqq : for Dmytro : bad : not optimal */ + // function filterBut( butMap, srcMap, key ) + // { + // if( _.aux.is( butMap ) ) + // { + // if( !( key in butMap ) ) + // return key; + // } + // else if( _.primitive.is( butMap ) ) + // { + // if( key !== butMap ) + // return key; + // } + // } + // filterBut.identity = { propertyCondition : true, propertyTransformer : true }; + // + // _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + // _.assert( !_.primitive.is( dstMap ), 'Expects map like destination map {-dstMap-}' ); + // _.assert( !_.primitive.is( srcMap ) || _.longIs( srcMap ), 'Expects long or map {-srcMap-}' ); + // _.assert( !_.primitive.is( butMap ) || _.longIs( butMap ) || _.routineIs( butMap ), 'Expects object like {-butMap-}' ); + // + // if( dstMap === srcMap ) + // { + // + // /* aaa : allow and cover vector */ /* Dmytro : implemented, covered */ + // if( _.vector.is( butMap ) ) + // { + // /* aaa : for Dmytro : bad */ /* Dmytro : for butMap types implemented two cyles. Types of elements is checked in filters */ + // for( let s in srcMap ) + // { + // for( let m = 0 ; m < butMap.length ; m++ ) + // { + // /* aaa : for Dmytro : write GOOD coverage */ /* Dmytro : coverage extended */ + // if( _.aux.is( butMap[ m ] ) ) + // { + // if( s in butMap[ m ] ) + // delete dstMap[ s ]; + // } + // else + // { + // if( s === butMap[ m ] ) + // delete dstMap[ s ]; + // } + // } + // } + // } + // else + // { + // for( let s in srcMap ) + // { + // if( s in butMap ) + // delete dstMap[ s ]; + // } + // } + // + // } + // else + // { + // + // /* aaa : allow and cover vector */ /* Dmytro : implemented, covered */ + // if( _.vector.is( butMap ) ) + // { + // /* aaa : for Dmytro : bad */ /* Dmytro : for butMap types implemented two cyles. Types of elements is checked in filters */ + // for( let s in srcMap ) + // { + // let m; + // for( m = 0 ; m < butMap.length ; m++ ) + // { + // /* aaa : for Dmytro : was bad implementation. cover */ /* Dmytro : improved, implemented, covered */ + // if( _.primitiveIs( butMap[ m ] ) ) + // { + // if( s === butMap[ m ] ) + // break; + // } + // else + // { + // if( s in butMap[ m ] ) + // break; + // } + // } + // + // if( m === butMap.length ) + // dstMap[ s ] = srcMap[ s ]; + // } + // } + // else + // { + // for( let s in srcMap ) + // { + // if( !( s in butMap ) ) + // dstMap[ s ] = srcMap[ s ]; + // } + // } + // + // } + // + // return dstMap; +} + +// + + + _.mapButOld = function mapButOld( srcMap, butMap ) +{ + let result = Object.create( null ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( !_.primitive.is( srcMap ), 'Expects map {-srcMap-}' ); + + /* aaa : allow and cover vector */ /* Dmytro : implemented, covered */ + if( _.countable.is( butMap ) ) + { + let filterRoutines = [ filterWithVectorButMap, filterWithArrayLikeButMap ]; + let arrayLikeIs = _.argumentsArray.like( butMap ) ? 1 : 0; + for( let s in srcMap ) + { + let butKey = filterRoutines[ arrayLikeIs ]( s ); + if( butKey === undefined ) + result[ s ] = srcMap[ s ]; + } + + // /* aaa : for Dmytro : bad */ /* Dmytro : improved, used checks with types */ + // for( let s in srcMap ) + // { + // let m; + // for( m = 0 ; m < butMap.length ; m++ ) + // { + // /* aaa : for Dmytro : write GOOD coverage */ /* Dmytro : coverage extended */ + // if( _.primitive.is( butMap[ m ] ) ) + // { + // if( s === butMap[ m ] ) + // break; + // } + // else + // { + // if( s in butMap[ m ] ) + // break; + // } + // // + // // if( s === butMap[ m ] ) + // // break; + // // if( _.aux.is( butMap[ m ] ) ) + // // if( s in butMap[ m ] ) + // // break; + // } + // + // if( m === butMap.length ) + // result[ s ] = srcMap[ s ]; + // } + } + else if( !_.primitive.is( butMap ) ) + { + for( let s in srcMap ) + { + if( !( s in butMap ) ) + result[ s ] = srcMap[ s ]; + } + } + else + { + _.assert( 0, 'Expects object-like or long-like {-butMap-}' ); /* xxx */ + } + + return result; + + /* */ + + function filterWithVectorButMap( s ) + { + for( let but of butMap ) + { + if( _.primitive.is( but ) ) + { + if( s === but ) + return s; + } + else if( _.aux.is( but ) ) + { + if( s in but ) + return s; + } + else + { + _.assert( 0, 'Unexpected type of element' ); + } + } + } + + /* */ + + function filterWithArrayLikeButMap( s ) + { + for( let m = 0 ; m < butMap.length ; m++ ) + { + if( _.primitive.is( butMap[ m ] ) ) + { + if( s === butMap[ m ] ) + return s; + } + else if( _.aux.is( butMap[ m ] ) ) + { + if( s in butMap[ m ] ) + return s; + } + else + { + _.assert( 0, 'Unexpected type of element' ); + } + } + } +} + +// + + // xxx : remove + _.mapOwn = function mapOwnKey( srcMap, key ) +{ + // if( srcMap === null ) + // return false; + // if( srcMap === undefined ) + // return false; + if( _.primitive.is( srcMap ) ) + return false; + return Object.hasOwnProperty.call( srcMap, key ); +} + +// + + + _.mapOnly_ = function mapOnly_( dstMap, srcMaps, screenMaps ) +{ + + + if( arguments.length === 1 ) + return _.mapsExtend( null, dstMap ); + + _.assert( arguments.length === 3, 'Not clear how to construct {-dstMap-}. Please, specify exactly 3 arguments' ); + + // else if( arguments.length === 2 ) + // { + // + // // return _.mapOnlyOld( srcMaps, screenMaps ); + // + // // aaa : for Dmytro : bad! /* Dmytro : this condition allow modify srcMaps if passed only 2 arguments */ + // if( dstMap === null ) + // return Object.create( null ); + // screenMaps = arguments[ 1 ]; + // srcMaps = arguments[ 0 ]; + // } + // else if( arguments.length !== 3 ) + // { + // _.assert( 0, 'Expects at least one argument and no more then three arguments' ); + // } + + let o = _._mapOnly_VerifyMapFields + ({ + srcMaps, + screenMaps, + dstMap : dstMap || Object.create( null ), + }); + + let mapsAreIdentical = o.dstMap === o.srcMaps ? 1 : 0; + let screenMapsIsCountable = _.countable.is( o.screenMaps ) ? 2 : 0; + let filterRoutines = + [ + filterNotIdenticalWithAuxScreenMap, + filterIdenticalWithAuxScreenMap, + filterNotIdenticalWithVectorScreenMap, + filterIdenticalWithVectorScreenMap + ]; + let key = mapsAreIdentical + screenMapsIsCountable; + let filterRoutine = filterRoutines[ key ]; + let searchingRoutine; + if( screenMapsIsCountable ) + searchingRoutine = _screenMapSearchingRoutineFunctor( o.screenMaps ); + + if( _.countable.is( o.srcMaps ) ) + { + for( let srcMap of o.srcMaps ) + { + _.assert( !_.primitive.is( srcMap ), 'Expects no primitive in {-o.srcMaps-}' ); + filterRoutine( srcMap ); + } + } + else + { + filterRoutine( o.srcMaps ); + } + + return o.dstMap; + + /* */ + + function filterNotIdenticalWithVectorScreenMap( srcMap ) + { + for( let key in srcMap ) + { + let screenKey = searchingRoutine( o.screenMaps, key ); + if( screenKey !== undefined ) + o.dstMap[ screenKey ] = srcMap[ screenKey ]; + } + } + + /* */ + + function filterIdenticalWithVectorScreenMap( srcMap ) + { + for( let key in srcMap ) + { + let screenKey = searchingRoutine( o.screenMaps, key ); + if( screenKey === undefined ) + delete srcMap[ key ]; + } + } + + /* */ + + function filterNotIdenticalWithAuxScreenMap( srcMap ) + { + for( let key in o.screenMaps ) + { + if( o.screenMaps[ key ] === undefined ) + continue; + + if( key in srcMap ) + o.dstMap[ key ] = srcMap[ key ]; + } + } + + + /* */ + + function filterIdenticalWithAuxScreenMap( srcMap ) + { + for( let key in srcMap ) + { + if( !( key in o.screenMaps ) ) + delete srcMap[ key ]; + } + } + + // return _.mapOnlyOld( srcMaps, screenMaps ); + // aaa : for Dmytro : bad! /* Dmytro : improved, optimized */ + + // return _._mapOnly_ + // ({ + // srcMaps, + // screenMaps, + // dstMap, + // }); + +} + +// + + + _._mapBut_VerifyMapFields = function _mapBut_VerifyMapFields( o ) +{ + _.assert( arguments.length === 1, 'Expects single options map {-o-}' ); + _.assert( !_.primitive.is( o.dstMap ), 'Expects non primitive {-o.dstMap-}' ); + _.assert( !_.primitive.is( o.srcMap ), 'Expects non primitive {-o.srcMap-}' ); + _.assert( !_.primitive.is( o.butMap ), 'Expects object like {-o.butMap-}' ); + _.assert( !_.vector.is( o.dstMap ), 'Expects aux like {-o.dstMap-}' ); + return o; +} + +// + + + _._mapOnly_VerifyMapFields = function _mapOnly_VerifyMapFields( o ) +{ + _.assert( arguments.length === 1, 'Expects single options map {-o-}' ); + _.assert( !_.primitive.is( o.dstMap ), 'Expects non primitive {-o.dstMap-}' ); + _.assert( !_.primitive.is( o.screenMaps ), 'Expects non primitive {-o.screenMaps-}' ); + _.assert( !_.primitive.is( o.srcMaps ), 'Expects non primitive {-o.srcMaps-}' ); + _.map.assertHasOnly( o, _mapOnly_VerifyMapFields.defaults ); + _.assert( !_.vector.is( o.dstMap ), 'Expects not a vector {-o.dstMap-}' ); + + return o; +} +_._mapOnly_VerifyMapFields.defaults = +{ + "dstMap" : null, + "srcMaps" : null, + "screenMaps" : null, + "filter" : null +} + +// + + + _.arrayAs = undefined; + +// + + + _.arrayAppend = function arrayAppend( dstArray, ins ) +{ + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + _.arrayAppended.apply( this, arguments ); + return dstArray; +} + +// + + + _.arrayAppendArray = function arrayAppendArray( dstArray, insArray ) +{ + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + _.arrayAppendedArray.apply( this, arguments ); + return dstArray; +} + +// + + + _.arrayAppendArrays = function arrayAppendArrays( dstArray, insArray ) +{ + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + if( dstArray === undefined ) + { + _.assert( arguments.length === 2 ); + return insArray; + } + + _.arrayAppendedArrays.apply( this, arguments ); + + return dstArray; +} + +// + + + _.arrayAppendedArray = function arrayAppendedArray( dstArray, insArray ) +{ + _.assert( arguments.length === 2 ) + _.assert( _.array.is( dstArray ), 'arrayPrependedArray :', 'Expects array' ); + _.assert( _.longLike( insArray ), 'arrayPrependedArray :', 'Expects longLike' ); + + let result = insArray.length; + dstArray.push.apply( dstArray, insArray ); + return result; +} + +// + + + _.arrayAppendedArrays = function arrayAppendedArrays( dstArray, insArray ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !_.longLike( insArray ) && insArray !== undefined ) + insArray = [ insArray ]; + + // if( !_.longLike( insArray ) ) + // { + // if( !_.array.is( dstArray ) ) + // return [ dstArray, insArray ]; + // else + // dstArray.push( insArray ); + // return 1; + // } + + // if( !_.array.is( insArray ) && insArray !== undefined ) + // insArray = [ insArray ]; + // if( !_.array.is( insArray ) && insArray !== undefined ) + // insArray = [ insArray ]; + + _.assert( _.array.is( dstArray ), 'Expects array' ); + _.assert( _.longLike( insArray ), 'Expects longLike entity' ); + + let result = 0; + + for( let a = 0, len = insArray.length; a < len; a++ ) + { + if( _.longLike( insArray[ a ] ) ) + { + dstArray.push.apply( dstArray, insArray[ a ] ); + result += insArray[ a ].length; + } + else + { + dstArray.push( insArray[ a ] ); + result += 1; + } + } + + return result; +} + +// + + + _.arrayAppended = function arrayAppended( dstArray, ins ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.array.is( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + dstArray.push( ins ); + return dstArray.length - 1; +} + +// + + + _.arrayAppendOnceStrictly = function arrayAppendOnceStrictly( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + let result; + if( Config.debug ) + { + result = _.arrayAppendedOnce.apply( this, arguments ); + _.assert( result >= 0, () => `Array should have only unique elements, but has several ${ _.entity.exportStringDiagnosticShallow( ins ) }` ); + } + else + { + result = _.arrayAppended.apply( this, [ dstArray, ins ] ); + } + return dstArray; +} + +// + + + _.arrayAppendArrayOnce = function arrayAppendArrayOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + _.arrayAppendedArrayOnce.apply( this, arguments ) + return dstArray; +} + +// + + + _.arrayAppendedArrayOnce = function arrayAppendedArrayOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( _.longLike( insArray ) ); + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + + let result = 0; + + if( dstArray === insArray ) + if( arguments.length === 2 ) + return result; + + for( let i = 0, len = insArray.length; i < len ; i++ ) + { + if( _.longLeftIndex( dstArray, insArray[ i ], evaluator1, evaluator2 ) === -1 ) + { + dstArray.push( insArray[ i ] ); + result += 1; + } + } + + return result; +} + +// + + + _.arrayAppendedArraysOnce = function arrayAppendedArraysOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + + if( dstArray === undefined ) + return insArray; + + if( !_.array.is( insArray ) && insArray !== undefined ) + insArray = [ insArray ]; + + _.assert( _.array.is( dstArray ), 'Expects array' ); + _.assert( _.longLike( insArray ), 'Expects longLike entity' ); + + let result = 0; + + if( dstArray === insArray ) + if( arguments.length === 2 ) + return result; + + for( let a = 0, len = insArray.length; a < len; a++ ) + { + if( _.longLike( insArray[ a ] ) ) + { + let array = insArray[ a ]; + for( let i = 0, alen = array.length; i < alen; i++ ) + _appendOnce( array[ i ] ); + } + else + { + _appendOnce( insArray[ a ] ); + } + } + + return result; + + function _appendOnce( argument ) + { + let index = _.longLeftIndex( dstArray, argument, evaluator1, evaluator2 ); + if( index === -1 ) + { + dstArray.push( argument ); + result += 1; + } + } + +} + +// + + + _.arrayAppendArraysOnce = function arrayAppendArraysOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + else if( dstArray === undefined ) + { + if( _.array.is( insArray ) ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + else + { + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + return insArray; + } + } + + _.arrayAppendedArraysOnce.apply( this, arguments ); + + return dstArray; +} + +// + + + _.arrayAppendedOnce = function arrayAppendedOnce( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let i = _.longLeftIndex.apply( _, arguments ); + + if( i === -1 ) + { + dstArray.push( ins ); + return dstArray.length - 1; + } + + return -1; +} + +// + + + _.arrayRemoveOnceStrictly = function arrayRemoveOnceStrictly( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.arrayRemoveElementOnceStrictly.apply( this, arguments ); + return dstArray; +} + +// + + + _.arrayRemoveElementOnceStrictly = function arrayRemoveElementOnceStrictly( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result; + if( Config.debug ) + { + let result = _.arrayRemovedElementOnce.apply( this, arguments ); + let index = _.longLeftIndex.apply( _, arguments ); + _.assert( index < 0 ); + _.assert( result >= 0, () => 'Array does not have element ' + _.entity.exportStringDiagnosticShallow( ins ) ); + } + else + { + let result = _.arrayRemovedElement.apply( this, [ dstArray, ins ] ); + } + return dstArray; +} + +// + + + _.arrayRemovedElement = function arrayRemovedElement( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let index = _.longLeftIndex.apply( this, arguments ); + let removedElements = 0; + + for( let i = 0; i < dstArray.length; i++ ) /* Dmytro : bad implementation, this cycle run routine longLeftIndex even if it not needs, better implementation commented below */ + { + if( index !== -1 ) + { + dstArray.splice( index, 1 ); + removedElements = removedElements + 1; + i = i - 1 ; + } + index = _.longLeftIndex.apply( this, arguments ); /* Dmytro : this call uses not offset, it makes routine slower */ + } + + return removedElements; + + // let removedElements = 0; + // let index = _.longLeftIndex.apply( this, arguments ); + // evaluator1 = _.number.is( evaluator1 ) ? undefined : evaluator1; + // + // while( index !== -1 ) + // { + // dstArray.splice( index, 1 ); + // removedElements = removedElements + 1; + // index = _.longLeftIndex( dstArray, ins, index, evaluator1, evaluator2 ); + // } + // + // return removedElements; +} + +// + + + _.arrayRemovedElementOnce = function arrayRemovedElementOnce( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let index = _.longLeftIndex.apply( _, arguments ); + if( index >= 0 ) + dstArray.splice( index, 1 ); + + return index; + /* "!!! : breaking" */ + /* // arrayRemovedElementOnce should return the removed element + let result; + let index = _.longLeftIndex.apply( _, arguments ); + + if( index >= 0 ) + { + result = dstArray[ index ]; + dstArray.splice( index, 1 ); + } + + return result; + */ +} + +// + + + _.longLeft = function left( /* arr, ins, fromIndex, evaluator1, evaluator2 */ ) +{ + let arr = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let fromIndex = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + let result = Object.create( null ); + let i = _.longLeftIndex( arr, ins, fromIndex, evaluator1, evaluator2 ); + + _.assert( 2 <= arguments.length && arguments.length <= 5 ); + + result.index = i; + + if( i >= 0 ) + result.element = arr[ i ]; + + return result; +} + +// + + + _.longLeftIndex = function leftIndex( /* arr, ins, evaluator1, evaluator2 */ ) +{ + let arr = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let fromIndex = 0; + + if( _.number.is( arguments[ 2 ] ) ) + { + fromIndex = arguments[ 2 ]; + evaluator1 = arguments[ 3 ]; + evaluator2 = arguments[ 4 ]; + } + + _.assert( 2 <= arguments.length && arguments.length <= 5, 'Expects 2-5 arguments: source array, element, and optional evaluator / equalizer' ); + _.assert( _.longLike( arr ), 'Expect a Long' ); + _.assert( _.number.is( fromIndex ) ); + _.assert( !evaluator1 || evaluator1.length === 1 || evaluator1.length === 2 || evaluator1.length === 3 ); + _.assert( !evaluator1 || _.routine.is( evaluator1 ) ); + _.assert( !evaluator2 || evaluator2.length === 1 ); + _.assert( !evaluator2 || _.routine.is( evaluator2 ) ); + + if( !evaluator1 ) + { + _.assert( !evaluator2 ); + return Array.prototype.indexOf.call( arr, ins, fromIndex ); + } + else if( evaluator1.length === 1 ) /* equalizer */ + { + + if( evaluator2 ) + ins = evaluator2( ins ); + else + ins = evaluator1( ins ); + + if( arr.findIndex && fromIndex === 0 ) + { + return arr.findIndex( ( val ) => evaluator1( val ) === ins ); + } + else + { + for( let a = fromIndex; a < arr.length ; a++ ) + { + if( evaluator1( arr[ a ] ) === ins ) + return a; + } + } + + } + else /* evaluator */ + { + _.assert( !evaluator2 ); + for( let a = fromIndex ; a < arr.length ; a++ ) + { + if( evaluator1( arr[ a ], ins ) ) + return a; + } + } + + return -1; +} + +// + + + _.longLeftDefined = function leftDefined( arr ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + return _.longLeft( arr, true, function( val ){ return val !== undefined; } ); +} + +// + + + _.longHas = function longHas( /* array, element, evaluator1, evaluator2 */ ) +{ + let array = arguments[ 0 ]; + let element = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + _.assert( _.argumentsArray.like( array ) ); + + if( !evaluator1 && !evaluator2 ) + { + // return _ArrayIndexOf.call( array, element ) !== -1; + return _ArrayIncludes.call( array, element ); + } + else + { + if( _.longLeftIndex( array, element, evaluator1, evaluator2 ) >= 0 ) + return true; + return false; + } + +} + +// + + + _.longGrow_ = function longGrow_( /* dst, src, cinterval, ins */ ) +{ + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + + if( arguments.length < 4 && dst !== null && dst !== src ) + { + dst = arguments[ 0 ]; + src = arguments[ 0 ]; + cinterval = arguments[ 1 ]; + ins = arguments[ 2 ]; + } + + if( cinterval === undefined ) + cinterval = [ 0, src.length - 1 ]; + if( _.number.is( cinterval ) ) + cinterval = [ 0, cinterval - 1 ]; + + _.assert( _.longIs( dst ) || dst === null, 'Expects {-dst-} of any long type or null' ); + _.assert( _.longIs( src ), 'Expects {-src-} of any long type' ); + _.assert( _.intervalIs( cinterval ), 'Expects cinterval {-cinterval-}' ); + + let first = cinterval[ 0 ] = cinterval[ 0 ] !== undefined ? cinterval[ 0 ] : 0; + let last = cinterval[ 1 ] = cinterval[ 1 ] !== undefined ? cinterval[ 1 ] : src.length - 1; + + if( first > 0 ) + first = 0; + if( last < src.length - 1 ) + last = src.length - 1; + + if( first < 0 ) + { + last -= first; + first -= first; + } + + if( last + 1 < first ) + last = first - 1; + + let first2 = Math.max( -cinterval[ 0 ], 0 ); + let last2 = Math.min( src.length - 1 + first2, last + first2 ); + + let resultLength = last - first + 1; + + let result = dst; + if( dst === null ) + { + result = _.long.makeUndefined( src, resultLength ); + } + else if( dst === src ) + { + if( dst.length === resultLength ) + { + return dst; + } + if( _.arrayLikeResizable( dst ) ) + { + _.assert( Object.isExtensible( dst ), 'Array is not extensible, cannot change array' ); + dst.splice( 0, 0, ... _.dup( ins, first2 ) ); + dst.splice( last2 + 1, 0, ... _.dup( ins, resultLength <= last2 ? 0 : resultLength - last2 - 1 ) ); + return dst; + } + else if( dst.length !== resultLength || _.argumentsArray.is( dst ) ) + { + result = _.long.makeUndefined( dst, resultLength ); + } + } + else if( dst.length !== resultLength ) + { + if( !_.arrayLikeResizable( result ) ) + result = _.bufferMakeUndefined( dst, resultLength ); + else + result.splice( resultLength ); + } + + for( let r = first2 ; r < last2 + 1 ; r++ ) + result[ r ] = src[ r - first2 ]; + + if( ins !== undefined ) + { + for( let r = 0 ; r < first2 ; r++ ) + result[ r ] = ins; + for( let r = last2 + 1 ; r < resultLength ; r++ ) + result[ r ] = ins; + } + + return result; +} + +// + + + _.vectorAdapterIs = function adapterIs( src ) +{ + return Object.prototype.toString.call( src ) === '[object VectorAdapter]'; +} + +// + + + _.dup = function dup( ins, times, result ) +{ + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.number.is( times ) || _.longIs( times ), 'dup expects times as number or array' ); + + if( _.number.is( times ) ) + { + if( !result ) + result = new Array( times ); + for( let t = 0 ; t < times ; t++ ) + result[ t ] = ins; + return result; + } + else if( _.longIs( times ) ) + { + _.assert( times.length === 2 ); + let l = times[ 1 ] - times[ 0 ]; + if( !result ) + result = new Array( times[ 1 ] ); + for( let t = 0 ; t < l ; t++ ) + result[ times[ 0 ] + t ] = ins; + return result; + } + else _.assert( 0, 'unexpected' ); + +} + +// + + + _.routine.unite = ( function() { + + const _uniteReplacing_head = function unite_head( routine, args ) + { + let o = args[ 0 ]; + + if( args[ 1 ] !== undefined ) + { + if( args.length === 3 ) + o = { head : args[ 0 ], body : args[ 1 ], tail : args[ 2 ] }; + else + o = { head : args[ 0 ], body : ( args.length > 1 ? args[ 1 ] : null ) }; + } + + _.routine.optionsWithoutUndefined( routine, o ); + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + _.assert( arguments.length === 2 ); + _.assert + ( + o.head === null || _.numberIs( o.head ) || _.routine.is( o.head ) || _.routine.s.are( o.head ) + , 'Expects either routine, routines or number of arguments {-o.head-}' + ); + _.assert( _.routine.is( o.body ), 'Expects routine {-o.body-}' ); + _.assert( o.tail === null || _.routine.is( o.tail ), () => `Expects routine {-o.tail-}, but got ${_.entity.strType( o.tail )}` ); + _.assert( o.body.defaults !== undefined, 'Body should have defaults' ); + + return o; + } + + const _uniteReplacing_body = function unite_body( o ) + { + + if( _.longIs( o.head ) ) + { + /* xxx : deprecate compose */ + /* qqq : for Dmytro : implement without compose */ + // let _head = _.routine.s.compose( o.head, function( /* args, result, op, k */ ) + // { + // let args = arguments[ 0 ]; + // let result = arguments[ 1 ]; + // let op = arguments[ 2 ]; + // let k = arguments[ 3 ]; + // _.assert( arguments.length === 4 ); + // _.assert( !_.unrollIs( result ) ); + // _.assert( _.object.isBasic( result ) ); + // return _.unrollAppend([ unitedRoutine, [ result ] ]); + // }); + let _head = _.routine.s.compose( o.head, function( /* args, result, op, k */ ) + { + let args = arguments[ 0 ]; + let result = arguments[ 1 ]; + let op = arguments[ 2 ]; + let k = arguments[ 3 ]; + _.assert( arguments.length === 4 ); + _.assert( !_.unrollIs( result ) ); + _.assert( _.object.isBasic( result ) ); + return _.unroll.from([ unitedRoutine, [ result ] ]); + }); + _.assert( _.routine.is( _head ) ); + o.head = function head() + { + let result = _head.apply( this, arguments ); + return result[ result.length-1 ]; + } + o.head.composed = _head.composed; + } + else if( _.number.is( o.head ) ) + { + o.head = headWithNargs_functor( o.head, o.body ); + } + + if( o.head === null ) + { + /* qqq : for Dmytro : cover please */ + if( o.body.defaults ) + o.head = headWithDefaults; + else + o.head = headWithoutDefaults; + } + + if( !o.name ) + { + _.assert( _.strDefined( o.body.name ), 'Body routine should have name' ); + o.name = o.body.name; + if( o.name.indexOf( '_body' ) === o.name.length-5 && o.name.length > 5 ) + o.name = o.name.substring( 0, o.name.length-5 ); + } + + /* generate body */ + + /* qqq : for Dmytro : cover in separate test routine */ + let body; + if( o.strategy === 'replacing' ) + body = o.body; + else + body = _.routine._amend + ({ + dst : null, + srcs : o.body, + strategy : o.strategy, + amending : 'extending', + }); + + /* make routine */ + + let unitedRoutine = _unite_functor( o.name, o.head, body, o.tail ); + + _.assert( _.strDefined( unitedRoutine.name ), 'Looks like your interpreter does not support dynamic naming of functions. Please use ES2015 or later interpreter.' ); + + /* qqq : for Dmytro : cover option::strategy */ + + _.routine._amend + ({ + dst : unitedRoutine, + srcs : body, + strategy : 'replacing', + amending : 'extending', + }); + + unitedRoutine.head = o.head; + unitedRoutine.body = body; + if( o.tail ) + unitedRoutine.tail = o.tail; + + _.assert + ( + unitedRoutine.defaults === body.defaults, + 'Something wrong, united routined should have same instance of defaults its body has' + ); + + return unitedRoutine; + + function headWithNargs_functor( nargs, body ) + { + _.assert( !!o.body.defaults ); + return function headWithDefaults( routine, args ) + { + _.assert( args.length <= nargs+1 ); + _.assert( arguments.length === 2 ); + let o = _.routine.options( routine, args[ nargs ] || Object.create( null ) ); + return _.unroll.from([ ... Array.prototype.slice.call( args, 0, nargs ), o ]); + } + } + + /* */ + + function headWithoutDefaults( routine, args ) + { + let o = args[ 0 ]; + _.assert( arguments.length === 2 ); + _.assert( args.length === 0 || args.length === 1, () => `Expects optional argument, but got ${args.length} arguments` ); + _.assert( args.length === 0 || o === undefined || o === null || _.auxIs( o ) ); + return o || null; + } + + /* */ + + function headWithDefaults( routine, args ) + { + let o = args[ 0 ]; + _.assert( arguments.length === 2 ); + _.assert( args.length === 0 || args.length === 1, () => `Expects optional argument, but got ${args.length} arguments` ); + _.assert( args.length === 0 || o === undefined || o === null || _.auxIs( o ) ); + return _.routine.options( routine, o || Object.create( null ) ); + } + + /* */ + + function _unite_functor() + { + const name = arguments[ 0 ]; + const head = arguments[ 1 ]; + const body = arguments[ 2 ]; + const tail = arguments[ 3 ]; + let r; + + _.assert( head === null || _.routineIs( head ) ); + _.assert( body === null || _.routineIs( body ) ); + _.assert( tail === null || _.routineIs( tail ) ); + + if( tail === null ) + r = + { + [ name ] : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + } + }; + else if( head === null ) + r = + { + [ name ] : function() + { + let result; + let o = arguments[ 0 ]; + + _.assert( arguments.length === 1, 'Expects single argument {-o-}.' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else if( _.mapIs( o ) ) + result = body.call( this, o ); + else + _.assert( 0, 'Unexpected type of {-o-}, expects options map or unroll.' ); + + result = tail.call( this, result, o ); + + return result; + } + }; + else + r = + { + [ name ] : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + debugger; + result = tail.call( this, result, o ); + + return result; + } + }; + + return r[ name ] + } + } + _uniteReplacing_body.defaults = { + "head" : null, + "body" : null, + "tail" : null, + "name" : null, + "strategy" : null + } + + const _uniteReplacing_ = function uniteReplacing() + { + let o = uniteReplacing.head.call( this, uniteReplacing, arguments ); + let result = uniteReplacing.body.call( this, o ); + return result; + } + _uniteReplacing_.head = function unite_head( routine, args ) + { + let o = args[ 0 ]; + + if( args[ 1 ] !== undefined ) + { + if( args.length === 3 ) + o = { head : args[ 0 ], body : args[ 1 ], tail : args[ 2 ] }; + else + o = { head : args[ 0 ], body : ( args.length > 1 ? args[ 1 ] : null ) }; + } + + _.routine.optionsWithoutUndefined( routine, o ); + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + _.assert( arguments.length === 2 ); + _.assert + ( + o.head === null || _.numberIs( o.head ) || _.routine.is( o.head ) || _.routine.s.are( o.head ) + , 'Expects either routine, routines or number of arguments {-o.head-}' + ); + _.assert( _.routine.is( o.body ), 'Expects routine {-o.body-}' ); + _.assert( o.tail === null || _.routine.is( o.tail ), () => `Expects routine {-o.tail-}, but got ${_.entity.strType( o.tail )}` ); + _.assert( o.body.defaults !== undefined, 'Body should have defaults' ); + + return o; + } + _uniteReplacing_.body = function unite_body( o ) + { + + if( _.longIs( o.head ) ) + { + /* xxx : deprecate compose */ + /* qqq : for Dmytro : implement without compose */ + // let _head = _.routine.s.compose( o.head, function( /* args, result, op, k */ ) + // { + // let args = arguments[ 0 ]; + // let result = arguments[ 1 ]; + // let op = arguments[ 2 ]; + // let k = arguments[ 3 ]; + // _.assert( arguments.length === 4 ); + // _.assert( !_.unrollIs( result ) ); + // _.assert( _.object.isBasic( result ) ); + // return _.unrollAppend([ unitedRoutine, [ result ] ]); + // }); + let _head = _.routine.s.compose( o.head, function( /* args, result, op, k */ ) + { + let args = arguments[ 0 ]; + let result = arguments[ 1 ]; + let op = arguments[ 2 ]; + let k = arguments[ 3 ]; + _.assert( arguments.length === 4 ); + _.assert( !_.unrollIs( result ) ); + _.assert( _.object.isBasic( result ) ); + return _.unroll.from([ unitedRoutine, [ result ] ]); + }); + _.assert( _.routine.is( _head ) ); + o.head = function head() + { + let result = _head.apply( this, arguments ); + return result[ result.length-1 ]; + } + o.head.composed = _head.composed; + } + else if( _.number.is( o.head ) ) + { + o.head = headWithNargs_functor( o.head, o.body ); + } + + if( o.head === null ) + { + /* qqq : for Dmytro : cover please */ + if( o.body.defaults ) + o.head = headWithDefaults; + else + o.head = headWithoutDefaults; + } + + if( !o.name ) + { + _.assert( _.strDefined( o.body.name ), 'Body routine should have name' ); + o.name = o.body.name; + if( o.name.indexOf( '_body' ) === o.name.length-5 && o.name.length > 5 ) + o.name = o.name.substring( 0, o.name.length-5 ); + } + + /* generate body */ + + /* qqq : for Dmytro : cover in separate test routine */ + let body; + if( o.strategy === 'replacing' ) + body = o.body; + else + body = _.routine._amend + ({ + dst : null, + srcs : o.body, + strategy : o.strategy, + amending : 'extending', + }); + + /* make routine */ + + let unitedRoutine = _unite_functor( o.name, o.head, body, o.tail ); + + _.assert( _.strDefined( unitedRoutine.name ), 'Looks like your interpreter does not support dynamic naming of functions. Please use ES2015 or later interpreter.' ); + + /* qqq : for Dmytro : cover option::strategy */ + + _.routine._amend + ({ + dst : unitedRoutine, + srcs : body, + strategy : 'replacing', + amending : 'extending', + }); + + unitedRoutine.head = o.head; + unitedRoutine.body = body; + if( o.tail ) + unitedRoutine.tail = o.tail; + + _.assert + ( + unitedRoutine.defaults === body.defaults, + 'Something wrong, united routined should have same instance of defaults its body has' + ); + + return unitedRoutine; + + function headWithNargs_functor( nargs, body ) + { + _.assert( !!o.body.defaults ); + return function headWithDefaults( routine, args ) + { + _.assert( args.length <= nargs+1 ); + _.assert( arguments.length === 2 ); + let o = _.routine.options( routine, args[ nargs ] || Object.create( null ) ); + return _.unroll.from([ ... Array.prototype.slice.call( args, 0, nargs ), o ]); + } + } + + /* */ + + function headWithoutDefaults( routine, args ) + { + let o = args[ 0 ]; + _.assert( arguments.length === 2 ); + _.assert( args.length === 0 || args.length === 1, () => `Expects optional argument, but got ${args.length} arguments` ); + _.assert( args.length === 0 || o === undefined || o === null || _.auxIs( o ) ); + return o || null; + } + + /* */ + + function headWithDefaults( routine, args ) + { + let o = args[ 0 ]; + _.assert( arguments.length === 2 ); + _.assert( args.length === 0 || args.length === 1, () => `Expects optional argument, but got ${args.length} arguments` ); + _.assert( args.length === 0 || o === undefined || o === null || _.auxIs( o ) ); + return _.routine.options( routine, o || Object.create( null ) ); + } + + /* */ + + function _unite_functor() + { + const name = arguments[ 0 ]; + const head = arguments[ 1 ]; + const body = arguments[ 2 ]; + const tail = arguments[ 3 ]; + let r; + + _.assert( head === null || _.routineIs( head ) ); + _.assert( body === null || _.routineIs( body ) ); + _.assert( tail === null || _.routineIs( tail ) ); + + if( tail === null ) + r = + { + [ name ] : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + } + }; + else if( head === null ) + r = + { + [ name ] : function() + { + let result; + let o = arguments[ 0 ]; + + _.assert( arguments.length === 1, 'Expects single argument {-o-}.' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else if( _.mapIs( o ) ) + result = body.call( this, o ); + else + _.assert( 0, 'Unexpected type of {-o-}, expects options map or unroll.' ); + + result = tail.call( this, result, o ); + + return result; + } + }; + else + r = + { + [ name ] : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + debugger; + result = tail.call( this, result, o ); + + return result; + } + }; + + return r[ name ] + } + } + _uniteReplacing_.defaults = { + "head" : null, + "body" : null, + "tail" : null, + "name" : null, + "strategy" : `replacing` + } + ; +_uniteReplacing_.head = _uniteReplacing_head; +_uniteReplacing_.body = _uniteReplacing_body; + return _uniteReplacing_; +})(); +_.routine.unite.defaults = +{ + "head" : null, + "body" : null, + "tail" : null, + "name" : null, + "strategy" : `replacing` +} + +// + + + _.routine.uniteCloning_replaceByUnite = ( function() { + + const _uniteCloning_head = function unite_head( routine, args ) + { + let o = args[ 0 ]; + + if( args[ 1 ] !== undefined ) + { + if( args.length === 3 ) + o = { head : args[ 0 ], body : args[ 1 ], tail : args[ 2 ] }; + else + o = { head : args[ 0 ], body : ( args.length > 1 ? args[ 1 ] : null ) }; + } + + _.routine.optionsWithoutUndefined( routine, o ); + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + _.assert( arguments.length === 2 ); + _.assert + ( + o.head === null || _.numberIs( o.head ) || _.routine.is( o.head ) || _.routine.s.are( o.head ) + , 'Expects either routine, routines or number of arguments {-o.head-}' + ); + _.assert( _.routine.is( o.body ), 'Expects routine {-o.body-}' ); + _.assert( o.tail === null || _.routine.is( o.tail ), () => `Expects routine {-o.tail-}, but got ${_.entity.strType( o.tail )}` ); + _.assert( o.body.defaults !== undefined, 'Body should have defaults' ); + + return o; + } + + const _uniteCloning_body = function unite_body( o ) + { + + if( _.longIs( o.head ) ) + { + /* xxx : deprecate compose */ + /* qqq : for Dmytro : implement without compose */ + // let _head = _.routine.s.compose( o.head, function( /* args, result, op, k */ ) + // { + // let args = arguments[ 0 ]; + // let result = arguments[ 1 ]; + // let op = arguments[ 2 ]; + // let k = arguments[ 3 ]; + // _.assert( arguments.length === 4 ); + // _.assert( !_.unrollIs( result ) ); + // _.assert( _.object.isBasic( result ) ); + // return _.unrollAppend([ unitedRoutine, [ result ] ]); + // }); + let _head = _.routine.s.compose( o.head, function( /* args, result, op, k */ ) + { + let args = arguments[ 0 ]; + let result = arguments[ 1 ]; + let op = arguments[ 2 ]; + let k = arguments[ 3 ]; + _.assert( arguments.length === 4 ); + _.assert( !_.unrollIs( result ) ); + _.assert( _.object.isBasic( result ) ); + return _.unroll.from([ unitedRoutine, [ result ] ]); + }); + _.assert( _.routine.is( _head ) ); + o.head = function head() + { + let result = _head.apply( this, arguments ); + return result[ result.length-1 ]; + } + o.head.composed = _head.composed; + } + else if( _.number.is( o.head ) ) + { + o.head = headWithNargs_functor( o.head, o.body ); + } + + if( o.head === null ) + { + /* qqq : for Dmytro : cover please */ + if( o.body.defaults ) + o.head = headWithDefaults; + else + o.head = headWithoutDefaults; + } + + if( !o.name ) + { + _.assert( _.strDefined( o.body.name ), 'Body routine should have name' ); + o.name = o.body.name; + if( o.name.indexOf( '_body' ) === o.name.length-5 && o.name.length > 5 ) + o.name = o.name.substring( 0, o.name.length-5 ); + } + + /* generate body */ + + /* qqq : for Dmytro : cover in separate test routine */ + let body; + if( o.strategy === 'replacing' ) + body = o.body; + else + body = _.routine._amend + ({ + dst : null, + srcs : o.body, + strategy : o.strategy, + amending : 'extending', + }); + + /* make routine */ + + let unitedRoutine = _unite_functor( o.name, o.head, body, o.tail ); + + _.assert( _.strDefined( unitedRoutine.name ), 'Looks like your interpreter does not support dynamic naming of functions. Please use ES2015 or later interpreter.' ); + + /* qqq : for Dmytro : cover option::strategy */ + + _.routine._amend + ({ + dst : unitedRoutine, + srcs : body, + strategy : 'replacing', + amending : 'extending', + }); + + unitedRoutine.head = o.head; + unitedRoutine.body = body; + if( o.tail ) + unitedRoutine.tail = o.tail; + + _.assert + ( + unitedRoutine.defaults === body.defaults, + 'Something wrong, united routined should have same instance of defaults its body has' + ); + + return unitedRoutine; + + function headWithNargs_functor( nargs, body ) + { + _.assert( !!o.body.defaults ); + return function headWithDefaults( routine, args ) + { + _.assert( args.length <= nargs+1 ); + _.assert( arguments.length === 2 ); + let o = _.routine.options( routine, args[ nargs ] || Object.create( null ) ); + return _.unroll.from([ ... Array.prototype.slice.call( args, 0, nargs ), o ]); + } + } + + /* */ + + function headWithoutDefaults( routine, args ) + { + let o = args[ 0 ]; + _.assert( arguments.length === 2 ); + _.assert( args.length === 0 || args.length === 1, () => `Expects optional argument, but got ${args.length} arguments` ); + _.assert( args.length === 0 || o === undefined || o === null || _.auxIs( o ) ); + return o || null; + } + + /* */ + + function headWithDefaults( routine, args ) + { + let o = args[ 0 ]; + _.assert( arguments.length === 2 ); + _.assert( args.length === 0 || args.length === 1, () => `Expects optional argument, but got ${args.length} arguments` ); + _.assert( args.length === 0 || o === undefined || o === null || _.auxIs( o ) ); + return _.routine.options( routine, o || Object.create( null ) ); + } + + /* */ + + function _unite_functor() + { + const name = arguments[ 0 ]; + const head = arguments[ 1 ]; + const body = arguments[ 2 ]; + const tail = arguments[ 3 ]; + let r; + + _.assert( head === null || _.routineIs( head ) ); + _.assert( body === null || _.routineIs( body ) ); + _.assert( tail === null || _.routineIs( tail ) ); + + if( tail === null ) + r = + { + [ name ] : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + } + }; + else if( head === null ) + r = + { + [ name ] : function() + { + let result; + let o = arguments[ 0 ]; + + _.assert( arguments.length === 1, 'Expects single argument {-o-}.' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else if( _.mapIs( o ) ) + result = body.call( this, o ); + else + _.assert( 0, 'Unexpected type of {-o-}, expects options map or unroll.' ); + + result = tail.call( this, result, o ); + + return result; + } + }; + else + r = + { + [ name ] : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + debugger; + result = tail.call( this, result, o ); + + return result; + } + }; + + return r[ name ] + } + } + _uniteCloning_body.defaults = { + "head" : null, + "body" : null, + "tail" : null, + "name" : null, + "strategy" : null + } + + const _uniteCloning_ = function uniteCloning() + { + let o = uniteCloning.head.call( this, uniteCloning, arguments ); + let result = uniteCloning.body.call( this, o ); + return result; + } + _uniteCloning_.head = function unite_head( routine, args ) + { + let o = args[ 0 ]; + + if( args[ 1 ] !== undefined ) + { + if( args.length === 3 ) + o = { head : args[ 0 ], body : args[ 1 ], tail : args[ 2 ] }; + else + o = { head : args[ 0 ], body : ( args.length > 1 ? args[ 1 ] : null ) }; + } + + _.routine.optionsWithoutUndefined( routine, o ); + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + _.assert( arguments.length === 2 ); + _.assert + ( + o.head === null || _.numberIs( o.head ) || _.routine.is( o.head ) || _.routine.s.are( o.head ) + , 'Expects either routine, routines or number of arguments {-o.head-}' + ); + _.assert( _.routine.is( o.body ), 'Expects routine {-o.body-}' ); + _.assert( o.tail === null || _.routine.is( o.tail ), () => `Expects routine {-o.tail-}, but got ${_.entity.strType( o.tail )}` ); + _.assert( o.body.defaults !== undefined, 'Body should have defaults' ); + + return o; + } + _uniteCloning_.body = function unite_body( o ) + { + + if( _.longIs( o.head ) ) + { + /* xxx : deprecate compose */ + /* qqq : for Dmytro : implement without compose */ + // let _head = _.routine.s.compose( o.head, function( /* args, result, op, k */ ) + // { + // let args = arguments[ 0 ]; + // let result = arguments[ 1 ]; + // let op = arguments[ 2 ]; + // let k = arguments[ 3 ]; + // _.assert( arguments.length === 4 ); + // _.assert( !_.unrollIs( result ) ); + // _.assert( _.object.isBasic( result ) ); + // return _.unrollAppend([ unitedRoutine, [ result ] ]); + // }); + let _head = _.routine.s.compose( o.head, function( /* args, result, op, k */ ) + { + let args = arguments[ 0 ]; + let result = arguments[ 1 ]; + let op = arguments[ 2 ]; + let k = arguments[ 3 ]; + _.assert( arguments.length === 4 ); + _.assert( !_.unrollIs( result ) ); + _.assert( _.object.isBasic( result ) ); + return _.unroll.from([ unitedRoutine, [ result ] ]); + }); + _.assert( _.routine.is( _head ) ); + o.head = function head() + { + let result = _head.apply( this, arguments ); + return result[ result.length-1 ]; + } + o.head.composed = _head.composed; + } + else if( _.number.is( o.head ) ) + { + o.head = headWithNargs_functor( o.head, o.body ); + } + + if( o.head === null ) + { + /* qqq : for Dmytro : cover please */ + if( o.body.defaults ) + o.head = headWithDefaults; + else + o.head = headWithoutDefaults; + } + + if( !o.name ) + { + _.assert( _.strDefined( o.body.name ), 'Body routine should have name' ); + o.name = o.body.name; + if( o.name.indexOf( '_body' ) === o.name.length-5 && o.name.length > 5 ) + o.name = o.name.substring( 0, o.name.length-5 ); + } + + /* generate body */ + + /* qqq : for Dmytro : cover in separate test routine */ + let body; + if( o.strategy === 'replacing' ) + body = o.body; + else + body = _.routine._amend + ({ + dst : null, + srcs : o.body, + strategy : o.strategy, + amending : 'extending', + }); + + /* make routine */ + + let unitedRoutine = _unite_functor( o.name, o.head, body, o.tail ); + + _.assert( _.strDefined( unitedRoutine.name ), 'Looks like your interpreter does not support dynamic naming of functions. Please use ES2015 or later interpreter.' ); + + /* qqq : for Dmytro : cover option::strategy */ + + _.routine._amend + ({ + dst : unitedRoutine, + srcs : body, + strategy : 'replacing', + amending : 'extending', + }); + + unitedRoutine.head = o.head; + unitedRoutine.body = body; + if( o.tail ) + unitedRoutine.tail = o.tail; + + _.assert + ( + unitedRoutine.defaults === body.defaults, + 'Something wrong, united routined should have same instance of defaults its body has' + ); + + return unitedRoutine; + + function headWithNargs_functor( nargs, body ) + { + _.assert( !!o.body.defaults ); + return function headWithDefaults( routine, args ) + { + _.assert( args.length <= nargs+1 ); + _.assert( arguments.length === 2 ); + let o = _.routine.options( routine, args[ nargs ] || Object.create( null ) ); + return _.unroll.from([ ... Array.prototype.slice.call( args, 0, nargs ), o ]); + } + } + + /* */ + + function headWithoutDefaults( routine, args ) + { + let o = args[ 0 ]; + _.assert( arguments.length === 2 ); + _.assert( args.length === 0 || args.length === 1, () => `Expects optional argument, but got ${args.length} arguments` ); + _.assert( args.length === 0 || o === undefined || o === null || _.auxIs( o ) ); + return o || null; + } + + /* */ + + function headWithDefaults( routine, args ) + { + let o = args[ 0 ]; + _.assert( arguments.length === 2 ); + _.assert( args.length === 0 || args.length === 1, () => `Expects optional argument, but got ${args.length} arguments` ); + _.assert( args.length === 0 || o === undefined || o === null || _.auxIs( o ) ); + return _.routine.options( routine, o || Object.create( null ) ); + } + + /* */ + + function _unite_functor() + { + const name = arguments[ 0 ]; + const head = arguments[ 1 ]; + const body = arguments[ 2 ]; + const tail = arguments[ 3 ]; + let r; + + _.assert( head === null || _.routineIs( head ) ); + _.assert( body === null || _.routineIs( body ) ); + _.assert( tail === null || _.routineIs( tail ) ); + + if( tail === null ) + r = + { + [ name ] : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + } + }; + else if( head === null ) + r = + { + [ name ] : function() + { + let result; + let o = arguments[ 0 ]; + + _.assert( arguments.length === 1, 'Expects single argument {-o-}.' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else if( _.mapIs( o ) ) + result = body.call( this, o ); + else + _.assert( 0, 'Unexpected type of {-o-}, expects options map or unroll.' ); + + result = tail.call( this, result, o ); + + return result; + } + }; + else + r = + { + [ name ] : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + debugger; + result = tail.call( this, result, o ); + + return result; + } + }; + + return r[ name ] + } + } + _uniteCloning_.defaults = { + "head" : null, + "body" : null, + "tail" : null, + "name" : null, + "strategy" : `cloning` + } + ; +_uniteCloning_.head = _uniteCloning_head; +_uniteCloning_.body = _uniteCloning_body; + return _uniteCloning_; +})(); +_.routine.uniteCloning_replaceByUnite.defaults = +{ + "head" : null, + "body" : null, + "tail" : null, + "name" : null, + "strategy" : `cloning` +} + +// + + + _.routine._amend = function _amend( o ) +{ + let dst = o.dst; + let srcs = o.srcs; + let srcIsVector = _.vector.is( srcs ); + let extended = false; + + _.assert( arguments.length === 1 ); + _.routine.assertOptions( _amend, o ); + _.assert( _.routine.is( dst ) || dst === null ); + _.assert( srcs === null || srcs === undefined || _.aux.is( srcs ) || _.routine.is( srcs ) || _.vector.is( srcs ) ); + _.assert( o.amending === 'extending', 'not implemented' ); + _.assert + ( + o.strategy === 'cloning' || o.strategy === 'replacing' || o.strategy === 'inheriting', + () => `Unknown strategy ${o.strategy}` + ); + + /* generate dst routine */ + + if( dst === null ) /* qqq : for Dmytro : good coverage required */ + dst = _dstMake( srcs ); + + /* extend dst routine */ + + let _dstAmend; + if( o.strategy === 'cloning' ) + _dstAmend = _dstAmendCloning; + else if( o.strategy === 'replacing' ) + _dstAmend = _dstAmendReplacing; + else if( o.strategy === 'inheriting' ) + _dstAmend = _dstAmendInheriting; + else _.assert( 0, 'not implemented' ); + + if( srcIsVector ) + for( let src of srcs ) + _dstAmend( dst, src ); + else + _dstAmend( dst, srcs ); + + /* qqq : for Dmytro : it should be optimal, no redundant cloning of body should happen + check and cover it by good test, please + */ + if( extended ) + if( dst.body ) + dst.body = bodyFrom( dst.body ); + + if( Config.debug ) + { + /* qqq : for Dmytro : cover, please */ + if( _.strEnds( dst.name, '_body' ) ) + { + _.assert( dst.body === undefined, 'Body of routine should not have its own body' ); + _.assert( dst.head === undefined, 'Body of routine should not have its own head' ); + _.assert( dst.tail === undefined, 'Body of routine should not have its own tail' ); + } + // xxx : uncomment? + // if( dst.defaults ) + // _.routine._verifyDefaults( dst.defaults ); + } + + return dst; + + /* */ + + function _dstMake( srcs ) + { + let dstMap = Object.create( null ); + + /* qqq : option amendment influence on it */ + if( srcIsVector ) + for( let src of srcs ) + { + if( src === null ) + continue; + _.props.extend( dstMap, src ); + } + else + { + if( srcs !== null ) + _.props.extend( dstMap, srcs ); + } + + let dstRoutine = null; + if( dstMap.body ) + { + dstRoutine = _.routine.unite + ({ + head : dstMap.head || null, + body : dstMap.body || null, + tail : dstMap.tail || null, + name : dstMap.name || null, + strategy : o.strategy, + }); + } + else + { + if( srcIsVector ) + dstRoutine = dstFrom( srcs[ 0 ] ); + else + dstRoutine = dstFrom( srcs ); + } + + _.assert( _.routine.is( dstRoutine ) ); + + return dstRoutine; + } + + /* */ + + function _dstAmendCloning( dst, src ) + { + _.assert( !!dst ); + _.assert( _.aux.is( src ) || _.routine.is( src ) ); + for( let s in src ) + { + let property = src[ s ]; + if( dst[ s ] === property ) + continue; + let d = Object.getOwnPropertyDescriptor( dst, s ); + if( d && !d.writable ) + continue; + extended = true; + if( _.object.isBasic( property ) ) + { + _.assert( !_.props.own( dst, s ) || _.object.isBasic( dst[ s ] ) ); + + if( dst[ s ] ) + _.props.extend( dst[ s ], property ); + else + dst[ s ] = property = _.props.extend( null, property ); + } + else + { + dst[ s ] = property; + } + } + } + + /* */ + + function _dstAmendInheriting( dst, src ) + { + _.assert( !!dst ); + _.assert( _.aux.is( src ) || _.routine.is( src ) ); + /* qqq : for Dmytro : on extending should inherit from the last one, on supplementing should inherit from the first one + implement, and cover in separate test + */ + for( let s in src ) + { + let property = src[ s ]; + if( dst[ s ] === property ) + continue; + let d = Object.getOwnPropertyDescriptor( dst, s ); + if( d && !d.writable ) + continue; + extended = true; + if( _.object.isBasic( property ) ) + { + property = Object.create( property ); + if( dst[ s ] ) + _.props.supplement( property, dst[ s ] ); + } + dst[ s ] = property; + } + } + + /* */ + + function _dstAmendReplacing( dst, src ) + { + _.assert( !!dst ); + _.assert( _.aux.is( src ) || _.routine.is( src ) ); + for( let s in src ) + { + let property = src[ s ]; + if( dst[ s ] === property ) + continue; + let d = Object.getOwnPropertyDescriptor( dst, s ); + if( d && !d.writable ) + continue; + extended = true; + dst[ s ] = property; + } + } + + /* */ + + function bodyFrom() + { + const body = dst.body; + let body2 = body; + _.assert( body.head === undefined, 'Body should not have own head' ); + _.assert( body.tail === undefined, 'Body should not have own tail' ); + _.assert( body.body === undefined, 'Body should not have own body' ); + { + let srcs; + if( srcIsVector ) + { + srcs = o.srcs.map( (src ) => propertiesBut( src ) ); + } + else + { + srcs = [ propertiesBut( o.srcs ) ]; + } + srcs.unshift( body ); + body2 = _.routine._amend + ({ + dst : o.strategy === 'replacing' ? body2 : null, + srcs, + strategy : o.strategy, + amending : o.amending, + }); + _.assert( body2.head === undefined, 'Body should not have own head' ); + _.assert( body2.tail === undefined, 'Body should not have own tail' ); + _.assert( body2.body === undefined, 'Body should not have own body' ); + } + return body2; + } + + /* */ + + function propertiesBut( src ) + { + if( !src ) + return src; + let result = _.props.extend( null, src ); + delete result.head; + delete result.body; + delete result.tail; + return result; + } + + /* */ + + /* xxx : make routine? */ + function routineClone( routine ) + { + _.assert( _.routine.is( routine ) ); + let name = routine.name; + // const routine2 = routine.bind(); + // _.assert( routine2 !== routine ); + const routine2 = + ({ + [ name ] : function() + { + return routine.apply( this, arguments ); + } + })[ name ]; + + let o2 = + { + value : routine, + enumerable : false, + }; + Object.defineProperty( routine2, 'originalRoutine', o2 ); /* qqq : for Dmytro : cover */ + + return routine2; + } + + /* */ + + function dstFrom( routine ) + { + return routineClone( routine ); + } +} +_.routine._amend.defaults = +{ + "dst" : null, + "srcs" : null, + "strategy" : `cloning`, + "amending" : `extending` +} + +// + + + _.routine._is = function _is( src, typeStr ) +{ + return typeStr === '[object Function]' || typeStr === '[object AsyncFunction]'; +} + +// + + + _.routine.is = function is( src ) +{ + let typeStr = Object.prototype.toString.call( src ); + return _.routine._is( src, typeStr ); +} + +// + + + var __keysQuote = function __keysQuote( keys ) +{ + let result = `"${ keys[ 0 ] }"`; + for( let i = 1 ; i < keys.length ; i++ ) + result += `, "${ keys[ i ] }"`; + return result.trim(); +} + +// + +var __primitiveLike = function __primitiveLike( src ) +{ + if( _.primitive.is( src ) ) + return true; + if( _.regexpIs( src ) ) + return true; + if( _.routineIs( src ) ) + return true; + return false; +} + +// + +var __strType = function __strType( src ) +{ + if( _.strType ) + return _.strType( src ); + return String( src ); +} + +// + +var __mapSupplementWithUndefined = function __mapSupplementWithUndefined( dstMap, srcMap ) +{ + for( let k in srcMap ) + { + if( Config.debug ) + _.assert + ( + __primitiveLike( srcMap[ k ] ), + () => `Defaults map should have only primitive elements, but option::${ k } is ${ __strType( srcMap[ k ] ) }` + ); + if( Object.hasOwnProperty.call( dstMap, k ) ) + continue; + dstMap[ k ] = srcMap[ k ]; + } +} + +// + +_.routine.options = function optionsWithUndefined( routine, options ) +{ + + if( _.argumentsArray.like( options ) ) + { + _.assert + ( + options.length === 0 || options.length === 1, + `Expects single options map, but got ${options.length} arguments` + ); + if( options.length === 0 ) + options = Object.create( null ) + else + options = options[ 0 ]; + } + + if( Config.debug ) + { + _.assert( arguments.length === 2, 'Expects exactly 2 arguments' ); + _.assert( _.routineIs( routine ) || _.aux.is( routine ) || routine === null, 'Expects an object with options' ); + _.assert( _.object.isBasic( options ) || options === null, 'Expects an object with options' ); + } + + if( options === null ) + options = Object.create( null ); + let name = routine.name || ''; + let defaults = routine.defaults; + _.assert( _.aux.is( defaults ), `Expects map of defaults, but got ${_.strType( defaults )}` ); + + /* */ + + if( Config.debug ) + { + let extraKeys = __mapButKeys( options, defaults ); + _.assert( extraKeys.length === 0, () => `Routine "${ name }" does not expect options: ${ __keysQuote( extraKeys ) }` ); + } + + __mapSupplementWithUndefined( options, defaults ); + + return options; +} + +// + + + var __keysQuote = function __keysQuote( keys ) +{ + let result = `"${ keys[ 0 ] }"`; + for( let i = 1 ; i < keys.length ; i++ ) + result += `, "${ keys[ i ] }"`; + return result.trim(); +} + +// + +var __primitiveLike = function __primitiveLike( src ) +{ + if( _.primitive.is( src ) ) + return true; + if( _.regexpIs( src ) ) + return true; + if( _.routineIs( src ) ) + return true; + return false; +} + +// + +var __strType = function __strType( src ) +{ + if( _.strType ) + return _.strType( src ); + return String( src ); +} + +// + +var __mapSupplementWithUndefined = function __mapSupplementWithUndefined( dstMap, srcMap ) +{ + for( let k in srcMap ) + { + if( Config.debug ) + _.assert + ( + __primitiveLike( srcMap[ k ] ), + () => `Defaults map should have only primitive elements, but option::${ k } is ${ __strType( srcMap[ k ] ) }` + ); + if( Object.hasOwnProperty.call( dstMap, k ) ) + continue; + dstMap[ k ] = srcMap[ k ]; + } +} + +// + +_.routine.options_ = function optionsWithUndefined( routine, options ) +{ + + if( _.argumentsArray.like( options ) ) + { + _.assert + ( + options.length === 0 || options.length === 1, + `Expects single options map, but got ${options.length} arguments` + ); + if( options.length === 0 ) + options = Object.create( null ) + else + options = options[ 0 ]; + } + + if( Config.debug ) + { + _.assert( arguments.length === 2, 'Expects exactly 2 arguments' ); + _.assert( _.routineIs( routine ) || _.aux.is( routine ) || routine === null, 'Expects an object with options' ); + _.assert( _.object.isBasic( options ) || options === null, 'Expects an object with options' ); + } + + if( options === null ) + options = Object.create( null ); + let name = routine.name || ''; + let defaults = routine.defaults; + _.assert( _.aux.is( defaults ), `Expects map of defaults, but got ${_.strType( defaults )}` ); + + /* */ + + if( Config.debug ) + { + let extraKeys = __mapButKeys( options, defaults ); + _.assert( extraKeys.length === 0, () => `Routine "${ name }" does not expect options: ${ __keysQuote( extraKeys ) }` ); + } + + __mapSupplementWithUndefined( options, defaults ); + + return options; +} + +// + + + var __keysQuote = function __keysQuote( keys ) +{ + let result = `"${ keys[ 0 ] }"`; + for( let i = 1 ; i < keys.length ; i++ ) + result += `, "${ keys[ i ] }"`; + return result.trim(); +} + +// + +var __primitiveLike = function __primitiveLike( src ) +{ + if( _.primitive.is( src ) ) + return true; + if( _.regexpIs( src ) ) + return true; + if( _.routineIs( src ) ) + return true; + return false; +} + +// + +var __strType = function __strType( src ) +{ + if( _.strType ) + return _.strType( src ); + return String( src ); +} + +// + +_.routine.assertOptions = function assertOptionsWithUndefined( routine, options ) +{ + + if( _.argumentsArray.like( options ) ) + { + _.assert + ( + options.length === 0 || options.length === 1, + `Expects single options map, but got ${options.length} arguments` + ); + options = options[ 0 ]; + } + + if( Config.debug ) + { + _.assert( arguments.length === 2, 'Expects exactly 2 arguments' ); + _.assert( _.routineIs( routine ) || _.aux.is( routine ) || routine === null, 'Expects an object with options' ); + _.assert( _.object.isBasic( options ) || options === null, 'Expects an object with options' ); + } + + let name = routine.name || ''; + let defaults = routine.defaults; + _.assert( _.aux.is( defaults ), `Expects map of defaults, but got ${_.strType( defaults )}` ); + + /* */ + + if( Config.debug ) + { + + let extraKeys = __mapButKeys( options, defaults ); + _.assert( extraKeys.length === 0, () => `Routine "${ name }" does not expect options: ${ __keysQuote( extraKeys ) }` ); + + for( let k in defaults ) + { + _.assert + ( + __primitiveLike( defaults[ k ] ), + () => `Defaults map should have only primitive elements, but option::${ k } is ${ __strType( defaults[ k ] ) }` + ); + _.assert + ( + Reflect.has( options, k ), + `Options map does not have option::${k}` + ) + } + + } + + return options; +} + +// + + + _.routine.isTrivial = ( function routineIsTrivial_functor() +{ + + const syncPrototype = Object.getPrototypeOf( Function ); + const asyncPrototype = Object.getPrototypeOf( _async ); + return routineIsTrivial; + + function routineIsTrivial( src ) + { + if( !src ) + return false; + let prototype = Object.getPrototypeOf( src ); + if( prototype === syncPrototype ) + return true; + if( prototype === asyncPrototype ) + return true; + return false; + } + + async function _async() + { + } + +} )(); + +// + + + _.routine.extend = function extendCloning( dst, ... srcs ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 || arguments.length === 3 ); + return _.routine._amend + ({ + dst, + srcs : [ ... srcs ], + strategy : 'cloning', + amending : 'extending', + }); + +} + +// + + + var __arrayFlatten = function __arrayFlatten( src ) +{ + let result = []; + if( src === null ) + return result; + if( !_.argumentsArray.like( src ) ) + result.push( src ); + else + for( let i = 0 ; i < src.length ; i++ ) + { + let e = src[ i ]; + if( _.array.is( e ) || _.argumentsArray.is( e ) ) + result.push( ... e ); + else + result.push( e ); + } + return result; +} + +// + +_.routine.s.compose = ( function() { + + const _compose_head = function _compose_head( routine, args ) + { + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { bodies : args[ 0 ] }; + if( args[ 1 ] !== undefined ) + o.chainer = args[ 1 ]; + + // if( o.bodies === null ) + // debugger; + // o.bodies = _.arrayAppendArrays( [], [ o.bodies ] ); + // o.bodies = merge( o.bodies ); + + // let bodies2 = __arrayFlatten( o.bodies ); + // if( bodies2.length && bodies2[ 0 ] === undefined ) + // debugger; + + o.bodies = __arrayFlatten( o.bodies ); + o.bodies = o.bodies.filter( ( e ) => e !== null ); + + _.routine.options( routine, o ); + _.assert( _.routine.s.are( o.bodies ) ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 || args.length === 2 ); + _.assert( args.length === 1 || !_.object.isBasic( args[ 0 ] ) ); + _.assert( _.arrayIs( o.bodies ) || _.routine.is( o.bodies ) ); + _.assert( _.routine.is( args[ 1 ] ) || args[ 1 ] === undefined || args[ 1 ] === null ); + _.assert( o.chainer === null || _.routine.is( o.chainer ) ); + _.assert( o.tail === null || _.routine.is( o.tail ) ); + + return o; + + // function merge( arrays ) + // { + // let result = []; + // if( arrays === null ) + // return result; + // for( let i = 0 ; i < arrays.length ; i++ ) + // { + // let array = arrays[ i ]; + // if( _.array.is( array ) || _.argumentsArray.is( array ) ) + // result.push( ... array ); + // else + // result.push( array ); + // } + // return result; + // } + } + _compose_head.locals = { + "__arrayFlatten" : function __arrayFlatten( src ) + { + let result = []; + if( src === null ) + return result; + if( !_.argumentsArray.like( src ) ) + result.push( src ); + else + for( let i = 0 ; i < src.length ; i++ ) + { + let e = src[ i ]; + if( _.array.is( e ) || _.argumentsArray.is( e ) ) + result.push( ... e ); + else + result.push( e ); + } + return result; + } + } + + const _compose_body = function _compose_body( o ) + { + + // if( o.chainer === null ) + // o.chainer = defaultChainer; + // o.bodies = __arrayFlatten( o.bodies ); + if( o.chainer === null ) + o.chainer = _.routine.chainer.default; + + let bodies = []; + for( let s = 0 ; s < o.bodies.length ; s++ ) + { + let body = o.bodies[ s ]; + _.assert( _.routine.is( body ) ); + if( body.composed ) + { + if( body.composed.chainer === o.chainer && body.composed.tail === o.tail ) + { + bodies.push( ... body.composed.elements ); + } + else + { + bodies.push( ... body ); + } + } + else + { + bodies.push( body ); + } + } + + o.bodies = bodies; + + let tail = o.tail; + let chainer = o.chainer; + + _.assert( _.routine.is( chainer ) ); + _.assert( tail === null || _.routine.is( tail ) ); + + /* */ + + if( bodies.length === 0 ) + o.act = compositionEmpty; + else if( bodies.length === 1 ) + o.act = compositionOfSingle; + else + o.act = composition; + + o.act.composed = o; + + if( tail ) + { + _.routine.extendReplacing( routineWithTail, o.act ); + return routineWithTail; + } + + return o.act; + + /* */ + + function compositionEmpty() + { + return []; + } + + function compositionOfSingle() + { + let result = []; + let args = _.unroll.from( arguments ); + // _.assert( _.unrollIs( args ), () => `Expects unroll, but got ${_.entity.strType( args )}` ); + let routine = bodies[ 0 ]; + let r = routine.apply( this, args ); + _.assert( !_.argumentsArray.is( r ) ); + if( r !== undefined ) + _.unrollAppend( result, r ); + return result; + } + + function composition() + { + let result = []; + let args = _.unroll.from( arguments ); + for( let k = 0 ; k < bodies.length ; k++ ) + { + // _.assert( _.unrollIs( args ), () => `Expects unroll, but got ${_.entity.strType( args )}` ); + let routine = bodies[ k ]; + let r = routine.apply( this, args ); + _.assert( !_.argumentsArray.is( r ) ); + if( r !== undefined ) + _.unrollAppend( result, r ); + args = chainer( args, r, o, k ); + if( args === _.dont ) + break; + _.assert( _.unroll.is( args ) ); + } + return result; + } + + // function defaultChainer( /* args, result, op, k */ ) + // { + // let args = arguments[ 0 ]; + // let result = arguments[ 1 ]; + // let op = arguments[ 2 ]; + // let k = arguments[ 3 ]; + // if( result === _.dont ) + // return result; + // return args; + // } + + function routineWithTail() + { + let result = tail.call( this, arguments, o ); + return result; + } + } + _compose_body.defaults = { "chainer" : null, "bodies" : null, "tail" : null } + + const _compose_ = _.routine.unite + ({ + head : _compose_head, + body : _compose_body, + }); + + return _compose_; +})(); +_.routine.s.compose.defaults = +{ "chainer" : null, "bodies" : null, "tail" : null } + +// + + + _.routine.s.are = function are( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.argumentsArray.like( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( !_.routine.is( src[ s ] ) ) + return false; + return true; + } + + return _.routine.is( src ); +} + +// + + + _.errIs = function is( src ) +{ + return src instanceof Error || Object.prototype.toString.call( src ) === '[object Error]'; +} + +// + + + _.regexpLike = function like( src ) +{ + if( src instanceof RegExp || Object.prototype.toString.call( src ) === '[object String]' ) + return true; + return false; +} + +// + + + _.intervalIs = function intervalIs( range ) +{ + _.assert( arguments.length === 1 ); + if( !_.number.s.areAll( range ) ) + return false; + if( range.length !== 2 ) + return false; + return true; +} + +// + + + _.numberDefined = function numberIsFinite( src ) +{ + if( !_.number.is( src ) ) + return false; + return isFinite( src ); +} + +// + + + _.numbersAreAll = function areAll( src ) +{ + _.assert( arguments.length === 1 ); + + if( _.bufferTypedIs( src ) ) + return true; + + if( _.argumentsArray.like( src ) && !_.arrayIsEmpty( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( !_.number.is( src[ s ] ) ) + return false; + + return true; + } + + return false; +} + +// + + + _.strConcat = function concat( srcs, o ) +{ + + o = _.routine.options( concat, o || Object.create( null ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( this.strConcat === concat ); + + if( o.onToStr === null ) + o.onToStr = onToStr; + + let defaultOptionsForToStr = + { + stringWrapper : '', + }; + + o.optionsForToStr = _.props.supplement( o.optionsForToStr, defaultOptionsForToStr ); + o.optionsForToStr.format = o.optionsForToStr.format || 'string.diagnostic'; + + if( _.routine.is( srcs ) ) + srcs = srcs(); + + if( !_.argumentsArray.like( srcs ) ) + srcs = [ srcs ]; + + let result = ''; + if( !srcs.length ) + return result; + + let concatenatePairWithLineDelimeter = o.onPairWithDelimeter ? o.onPairWithDelimeter : concatenateSimple; + + /* */ + + let a = 0; + + while( !result && a < srcs.length ) + { + result = o.onToStr( srcs[ a ], o ); + ++a; + } + + for( ; a < srcs.length ; a++ ) + { + let src = srcs[ a ]; + src = o.onToStr( src, o ); + + result = result.replace( /[^\S\n]\s*$/, '' ); + + if( _.strEnds( result, o.lineDelimter ) || _.strBegins( src, o.lineDelimter ) ) + result = concatenatePairWithLineDelimeter( result, src, o ); + else + result = `${result} ${src.replace( /^\s+/, '' )}`; + } + + /* */ + + if( o.linePrefix || o.linePostfix ) + { + result = result.split( o.lineDelimter ); + result = o.linePrefix + result.join( o.linePostfix + o.lineDelimter + o.linePrefix ) + o.linePostfix; + } + + /* */ + + return result; + + /* */ + + function onToStr( src, op ) + { + return _.entity.exportString( src, op.optionsForToStr ); + } + + /* */ + + function concatenateSimple( src1, src2 ) + { + return src1 + src2; + } +} +_.strConcat.defaults = +{ + "linePrefix" : ``, + "linePostfix" : ``, + "lineDelimter" : `\n`, + "optionsForToStr" : null, + "onToStr" : null, + "onPairWithDelimeter" : null +} + +// + + + _.strHas = function has( src, ins ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ), () => `Expects string, got ${_.entity.strType( src )}` ); + _.assert( _.regexpLike( ins ), () => `Expects string-like, got ${_.entity.strType( ins )}` ); + + if( _.strIs( ins ) ) + return src.indexOf( ins ) !== -1; + else + return ins.test( src ); + +} + +// + + + _.strHasAny = function strHasAny( src, ins ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.arrayIs( ins ) ) + { + for( let i = 0 ; i < ins.length ; i++ ) + if( _.strHas( src, ins[ i ] ) ) + return true; + return false; + } + + return _.strHas( src, ins ); +} + +// + + + _.strLinesStrip = function strip( src ) +{ + + if( arguments.length > 1 ) + { + let result = _.unroll.make( null ); + for( let a = 0 ; a < arguments.length ; a++ ) + result[ a ] = _.str.lines.strip( arguments[ a ] ); + return result; + } + + _.assert( _.strIs( src ) || _.arrayIs( src ) ); + _.assert( arguments.length === 1 ); + + let lines = _.strLinesSplit( src ); + lines = lines.map( ( line ) => line.trim() ).filter( ( line ) => line ); + + if( _.strIs( src ) ) + lines = _.str.lines.join( lines ); + return lines; +} + +// + + + _.strLinesNumber = function strLinesNumber( o ) +{ + + if( !_.object.isBasic( o ) ) + o = { src : arguments[ 0 ], zeroLine : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + + _.routine.options( strLinesNumber, o ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( o.src ) || _.strsAreAll( o.src ), 'Expects string or strings {-o.src-}' ); + + /* */ + + if( o.zeroLine === null ) + { + if( o.zeroChar === null ) + { + o.zeroLine = 1; + } + else if( _.number.is( o.zeroChar ) ) + { + let src = _.arrayIs( o.src ) ? o.src.join( '\n' ) : o.src; + o.zeroLine = _.strLinesCount( src.substring( 0, o.zeroChar+1 ) ); + } + } + + /* */ + + let lines = _.strIs( o.src ) ? _.str.lines.split( o.src ) : o.src; + + /* */ + + let maxNumberLength = String( lines.length - 1 + o.zeroLine ).length; + let zeroLineLength = String( o.zeroLine ).length; + let maxNumLength = maxNumberLength > zeroLineLength ? maxNumberLength : zeroLineLength; + + if( o.onLine ) + for( let l = 0; l < lines.length; l += 1 ) + { + let numLength = String( l + o.zeroLine ).length; + + lines[ l ] = o.onLine( [ ' '.repeat( maxNumLength - numLength ), ( l + o.zeroLine ), ' : ', lines[ l ] ], o.zeroLine + l, o ); + if( lines[ l ] === undefined ) + { + lines.splice( l, 1 ); + l -= 1; + } + _.assert( _.strIs( lines[ l ] ) ); + } + else + for( let l = 0; l < lines.length; l += 1 ) + { + let numLength = String( l + o.zeroLine ).length; + lines[ l ] = ' '.repeat( maxNumLength - numLength ) + ( l + o.zeroLine ) + ' : ' + lines[ l ]; + } + if( o.highlightingToken && o.highlighting ) + { + let results; + + _.assert( o.highlighting === null || _.number.is( o.highlighting ) || _.longIs( o.highlighting ), 'Expects number or array of numbers {-o.highlighting-}' ); + + if( !_.arrayIs( o.highlighting ) ) + { + if( o.highlighting > o.zeroLine + lines.length - 1 || o.highlighting < o.zeroLine ) + return lines.join( '\n' ); + } + + results = lines.map( ( el ) => + { + if( _.arrayIs( o.highlighting ) ) + return o.highlighting.includes( parseInt( el, 10 ) ) ? '' + o.highlightingToken + ' ' + el : '' + ' '.repeat( o.highlightingToken.length + 1 ) + el; + else + return ( '' + o.highlighting ).includes( parseInt( el, 10 ) ) ? '' + o.highlightingToken + ' ' + el : '' + ' '.repeat( o.highlightingToken.length + 1 ) + el; + } ) + + if( JSON.stringify( lines ) === JSON.stringify( results.map( ( el ) => el.trim() ) ) ) + return lines.join( '\n' ); + + return results.join( '\n' ); + + } + + return lines.join( '\n' ); +} +_.strLinesNumber.defaults = +{ + "src" : null, + "zeroLine" : null, + "zeroChar" : null, + "onLine" : null, + "highlighting" : null, + "highlightingToken" : `*` +} + +// + + + _.strLinesSplit = function split( src, eol ) +{ + if( _.arrayIs( src ) ) + return src; + _.assert( _.strIs( src ) || _.arrayIs( src ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + if( eol === undefined ) + eol = _.str.lines.Eol.default; + return src.split( eol ); +} + +// + + + _.strLinesJoin = function join( src, eol ) +{ + _.assert( _.strIs( src ) || _.arrayIs( src ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + if( eol === undefined ) + eol = _.str.lines.Eol.default; + let result = src; + if( _.arrayIs( src ) ) + result = src.join( eol ); + return result; +} + +// + + + _.strSplit = ( function() { + + const _strSplit_head = []; + var _body_0 = function strSplitFast_head( routine, args ) + { + let o = args[ 0 ]; + + if( args.length === 2 ) + o = { src : args[ 0 ], delimeter : args[ 1 ] } + else if( _.strIs( args[ 0 ] ) ) + o = { src : args[ 0 ] } + + _.routine.options( routine, o ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 || args.length === 2, 'Expects one or two arguments' ); + _.assert( _.strIs( o.src ) ); + _.assert( o.delimeter === null || _.regexp.like( o.delimeter ) || _.arrayIs( o.delimeter ) ); + _.assert( _.object.isBasic( o ) ); + + return o; + } + + // + + + _strSplit_head.push( _body_0 ); + var _body_1 = function strSplitsQuotedRejoin_head( routine, args ) + { + let o = args[ 0 ]; + + _.routine.options( routine, o ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1, 'Expects one or two arguments' ); + _.assert( _.object.isBasic( o ) ); + + if( o.quoting ) + { + + if( _.bool.like( o.quoting ) ) + { + if( !o.quotingPrefixes ) + o.quotingPrefixes = [ '"' ]; + if( !o.quotingPostfixes ) + o.quotingPostfixes = [ '"' ]; + } + else if( _.strIs( o.quoting ) || _.regexpIs( o.quoting ) || _.arrayIs( o.quoting ) ) + { + _.assert( !o.quotingPrefixes ); + _.assert( !o.quotingPostfixes ); + o.quoting = _.array.as( o.quoting ); + o.quotingPrefixes = o.quoting.map( ( q ) => _.arrayIs( q ) ? q[ 0 ] : q ); + o.quotingPostfixes = o.quoting.map( ( q ) => _.arrayIs( q ) ? q[ 0 ] : q ); + o.quoting = true; + } + else _.assert( 0, 'unexpected type of {-o.quoting-}' ); + + _.assert + ( + !o.pairing || o.quotingPrefixes.length === o.quotingPostfixes.length, + `If option::o.paring is true then the length of o.quotingPrefixes should be equal to the length of o.quotingPostfixes` + ); + + if( Config.debug ) + { + _.assert( o.quotingPrefixes.length === o.quotingPostfixes.length ); + _.assert( _.bool.like( o.quoting ) ); + o.quotingPrefixes.forEach( ( q ) => _.assert( _.strIs( q ) ) ); + o.quotingPostfixes.forEach( ( q ) => _.assert( _.strIs( q ) ) ); + } + + } + + return o; + } + + // + + + _strSplit_head.push( _body_1 ); + var _body_2 = function strSplitsDropDelimeters_head( routine, args ) + { + let o = args[ 0 ]; + + _.routine.options( routine, o ); + + if( _.strIs( o.delimeter ) ) + o.delimeter = [ o.delimeter ]; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 ); + _.assert( _.object.isBasic( o ) ); + + return o; + } + + // + + + _strSplit_head.push( _body_2 ); + var _body_3 = function strSplitsStrip_head( routine, args ) + { + let o = args[ 0 ]; + + _.routine.options( routine, o ); + + if( o.stripping && _.bool.like( o.stripping ) ) + o.stripping = _.strStrip.defaults.stripper; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 ); + _.assert( _.object.isBasic( o ) ); + _.assert( !o.stripping || _.strIs( o.stripping ) || _.regexpIs( o.stripping ) ); + + return o; + } + + // + + + _strSplit_head.push( _body_3 ); + var _body_4 = function strSplitsDropEmpty_head( routine, args ) + { + let o = args[ 0 ]; + + _.routine.options( routine, o ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 ); + _.assert( _.object.isBasic( o ) ); + + return o; + } + + // + + + _strSplit_head.push( _body_4 ); + + const _strSplit_body = function strSplit_body( o ) + { + + o.delimeter = _.array.as( o.delimeter ); + + if( !o.stripping && !o.quoting && !o.onDelimeter ) + { + return _.strSplitFast.body( _.mapOnly_( null, o, _.strSplitFast.defaults ) ); + } + + /* */ + + _.assert( arguments.length === 1 ); + + /* */ + + let result = []; + let fastOptions = _.mapOnly_( null, o, _.strSplitFast.defaults ); + fastOptions.preservingEmpty = 1; + fastOptions.preservingDelimeters = 1; + + if( o.quoting ) + fastOptions.delimeter = _.arrayAppendArraysOnce( [], [ o.quotingPrefixes, o.quotingPostfixes, fastOptions.delimeter ] ); + + o.splits = _.strSplitFast.body( fastOptions ); + + if( o.quoting && o.onQuote ) + { + let quotes = _.arrayAppendArraysOnce( null, [ o.quotingPrefixes, o.quotingPostfixes ] ); + for( let i = 0 ; i < o.splits.length ; i++ ) + { + let index = _.longLeftIndex( quotes, o.splits[ i ], equalizeStrings ); + if( index !== -1 ) + o.splits[ i ] = o.onQuote( o.splits[ i ], index, quotes ); + } + } + if( o.onDelimeter ) + { + let delimeter = _.filter_( null, o.delimeter, function( pattern ) + { + if( _.regexpIs( pattern ) ) + return pattern.test( o.src ) ? pattern : null; + return pattern; + }); + for( let i = 0 ; i < o.splits.length ; i++ ) + { + let index = _.longLeftIndex( delimeter, o.splits[ i ], equalizeStrings ); + if( index !== -1 ) + o.splits[ i ] = o.onDelimeter( o.splits[ i ], index, o.delimeter ); + } + } + + if( o.quoting ) + _.strSplitsQuotedRejoin.body( o ); + + if( !o.preservingDelimeters ) + _.strSplitsDropDelimeters.body( o ); + + if( o.stripping ) + _.strSplitsStrip.body( o ); + + if( !o.preservingEmpty ) + _.strSplitsDropEmpty.body( o ); + + /* */ + + return o.splits; + + /* */ + + function equalizeStrings( pattern, el ) + { + if( _.strIs( pattern ) ) + return pattern === el; + if( pattern !== null ) + return pattern.test( el ); + return false; + } + + } + _strSplit_body.defaults = { + "preservingEmpty" : 1, + "preservingDelimeters" : 1, + "preservingQuoting" : 1, + "inliningQuoting" : 1, + "stripping" : 1, + "quoting" : 1, + "quotingPrefixes" : null, + "quotingPostfixes" : null, + "onDelimeter" : null, + "onQuote" : null + } + + const _strSplit_ = _.routine.unite + ({ + head : _strSplit_head, + body : _strSplit_body, + }); + + return _strSplit_; +})(); +_.strSplit.defaults = +{ + "preservingEmpty" : 1, + "preservingDelimeters" : 1, + "preservingQuoting" : 1, + "inliningQuoting" : 1, + "stripping" : 1, + "quoting" : 1, + "quotingPrefixes" : null, + "quotingPostfixes" : null, + "onDelimeter" : null, + "onQuote" : null, + "src" : null, + "delimeter" : ` ` +} + +// + + + _.strSplitFast = ( function() { + + const _strSplitFast_head = function strSplitFast_head( routine, args ) + { + let o = args[ 0 ]; + + if( args.length === 2 ) + o = { src : args[ 0 ], delimeter : args[ 1 ] } + else if( _.strIs( args[ 0 ] ) ) + o = { src : args[ 0 ] } + + _.routine.options( routine, o ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 || args.length === 2, 'Expects one or two arguments' ); + _.assert( _.strIs( o.src ) ); + _.assert( o.delimeter === null || _.regexp.like( o.delimeter ) || _.arrayIs( o.delimeter ) ); + _.assert( _.object.isBasic( o ) ); + + return o; + } + + const _strSplitFast_body = function strSplitFast_body( o ) + { + let result, closests, position, closestPosition, closestIndex, hasEmptyDelimeter, delimeter + + o.delimeter = _.array.as( o.delimeter ); + + let foundDelimeters = o.delimeter.slice(); + + _.assert( arguments.length === 1 ); + _.assert( _.arrayIs( o.delimeter ) ); + _.assert( _.bool.like( o.preservingDelimeters ) ); + + /* */ + + if( !o.preservingDelimeters && o.delimeter.length === 1 ) + { + + result = o.src.split( o.delimeter[ 0 ] ); + + if( !o.preservingEmpty ) + result = result.filter( ( e ) => e ? e : false ); + + } + else + { + + if( !o.delimeter.length ) + { + result = [ o.src ]; + return result; + } + + result = []; + closests = []; + position = 0; + closestPosition = 0; + closestIndex = -1; + hasEmptyDelimeter = false; + + for( let d = 0 ; d < o.delimeter.length ; d++ ) + { + let delimeter = o.delimeter[ d ]; + if( _.regexpIs( delimeter ) ) + { + _.assert( !delimeter.sticky ); + if( delimeter.source === '' || delimeter.source === '()' || delimeter.source === '(?:)' ) + hasEmptyDelimeter = true; + } + else + { + if( delimeter.length === 0 ) + hasEmptyDelimeter = true; + } + closests[ d ] = delimeterNext( d, position ); + } + + do + { + closestWhich(); + + if( closestPosition === o.src.length ) + break; + + if( !delimeter.length ) + position += 1; + + ordinaryAdd( o.src.substring( position, closestPosition ) ); + + if( delimeter.length > 0 || position < o.src.length ) + delimeterAdd( delimeter ); + + position = closests[ closestIndex ] + ( delimeter.length ? delimeter.length : 1 ); + + for( let d = 0 ; d < o.delimeter.length ; d++ ) + if( closests[ d ] < position ) + closests[ d ] = delimeterNext( d, position ); + + } + while( position < o.src.length ); + + if( delimeter || !hasEmptyDelimeter ) + ordinaryAdd( o.src.substring( position, o.src.length ) ); + + } + + return result; + + /* */ + + function delimeterAdd( delimeter ) + { + + if( o.preservingDelimeters ) + if( o.preservingEmpty || delimeter ) + { + result.push( delimeter ); + // if( _.regexpIs( delimeter ) ) + // result.push( delimeter ); + // o.src.substring( position, closestPosition ) + // else + // result.push( delimeter ); + } + + } + + /* */ + + function ordinaryAdd( ordinary ) + { + if( o.preservingEmpty || ordinary ) + result.push( ordinary ); + } + + /* */ + + function closestWhich() + { + + closestPosition = o.src.length; + closestIndex = -1; + for( let d = 0 ; d < o.delimeter.length ; d++ ) + { + if( closests[ d ] < o.src.length && closests[ d ] < closestPosition ) + { + closestPosition = closests[ d ]; + closestIndex = d; + } + } + + delimeter = foundDelimeters[ closestIndex ]; + + } + + /* */ + + function delimeterNext( d, position ) + { + _.assert( position <= o.src.length ); + let delimeter = o.delimeter[ d ]; + let result; + + if( _.strIs( delimeter ) ) + { + result = o.src.indexOf( delimeter, position ); + } + else + { + let execed = delimeter.exec( o.src.substring( position ) ); + if( execed ) + { + result = execed.index + position; + foundDelimeters[ d ] = execed[ 0 ]; + } + } + + if( result === -1 ) + return o.src.length; + return result; + } + + } + _strSplitFast_body.defaults = { + "src" : null, + "delimeter" : ` `, + "preservingEmpty" : 1, + "preservingDelimeters" : 1 + } + + const _strSplitFast_ = _.routine.unite + ({ + head : _strSplitFast_head, + body : _strSplitFast_body, + }); + + return _strSplitFast_; +})(); +_.strSplitFast.defaults = +{ + "src" : null, + "delimeter" : ` `, + "preservingEmpty" : 1, + "preservingDelimeters" : 1 +} + +// + + + _.strSplitsQuotedRejoin = ( function() { + + const _strSplitsQuotedRejoin_head = function strSplitsQuotedRejoin_head( routine, args ) + { + let o = args[ 0 ]; + + _.routine.options( routine, o ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1, 'Expects one or two arguments' ); + _.assert( _.object.isBasic( o ) ); + + if( o.quoting ) + { + + if( _.bool.like( o.quoting ) ) + { + if( !o.quotingPrefixes ) + o.quotingPrefixes = [ '"' ]; + if( !o.quotingPostfixes ) + o.quotingPostfixes = [ '"' ]; + } + else if( _.strIs( o.quoting ) || _.regexpIs( o.quoting ) || _.arrayIs( o.quoting ) ) + { + _.assert( !o.quotingPrefixes ); + _.assert( !o.quotingPostfixes ); + o.quoting = _.array.as( o.quoting ); + o.quotingPrefixes = o.quoting.map( ( q ) => _.arrayIs( q ) ? q[ 0 ] : q ); + o.quotingPostfixes = o.quoting.map( ( q ) => _.arrayIs( q ) ? q[ 0 ] : q ); + o.quoting = true; + } + else _.assert( 0, 'unexpected type of {-o.quoting-}' ); + + _.assert + ( + !o.pairing || o.quotingPrefixes.length === o.quotingPostfixes.length, + `If option::o.paring is true then the length of o.quotingPrefixes should be equal to the length of o.quotingPostfixes` + ); + + if( Config.debug ) + { + _.assert( o.quotingPrefixes.length === o.quotingPostfixes.length ); + _.assert( _.bool.like( o.quoting ) ); + o.quotingPrefixes.forEach( ( q ) => _.assert( _.strIs( q ) ) ); + o.quotingPostfixes.forEach( ( q ) => _.assert( _.strIs( q ) ) ); + } + + } + + return o; + } + + const _strSplitsQuotedRejoin_body = function strSplitsQuotedRejoin_body( o ) + { + + _.assert( arguments.length === 1 ); + _.assert( _.arrayIs( o.splits ) ); + + /* quoting */ + + // let s = 1; // why was it 1?? + let s = 0; + if( o.quoting ) + { + for( s ; s < o.splits.length ; s += 1 ) + splitsQuote( o.splits[ s ], s ); + } + + return o.splits; + + function splitsQuote( split, i ) + { + let s2; + let q = o.quotingPrefixes.indexOf( split ); + + if( q >= 0 ) + { + let postfix = o.quotingPostfixes[ q ]; + for( s2 = i+2 ; s2 < o.splits.length ; s2 += 1 ) + { + let split2 = o.splits[ s2 ]; + if( split2 === postfix ) + { + if( o.pairing ) + if( o.quotingPrefixes.indexOf( o.splits[ s ] ) !== o.quotingPostfixes.indexOf( o.splits[ s2 ] ) ) + break; + let bextra = 0; + let eextra = 0; + if( o.inliningQuoting ) + { + s -= 1; + bextra += 1; + s2 += 1; + eextra += 1; + } + let splitNew = o.splits.splice( s, s2-s+1, null ); + if( !o.preservingQuoting ) + { + splitNew.splice( bextra, 1 ); + splitNew.splice( splitNew.length-1-eextra, 1 ); + } + splitNew = splitNew.join( '' ); + if( o.onQuoting ) + o.splits[ s ] = o.onQuoting( splitNew, o ); + else + o.splits[ s ] = splitNew; + s2 = s; + break; + } + } + } + + /* if complementing postfix not found */ + + if( s2 >= o.splits.length ) + { + if( !_.longHas( o.delimeter, split ) ) + { + let splitNew = o.splits.splice( s, 2 ).join( '' ); + o.splits[ s-1 ] = o.splits[ s-1 ] + splitNew; + } + else + { + } + } + } + } + _strSplitsQuotedRejoin_body.defaults = { + "quoting" : 1, + "quotingPrefixes" : null, + "quotingPostfixes" : null, + "preservingQuoting" : 1, + "inliningQuoting" : 1, + "splits" : null, + "delimeter" : null, + "onQuoting" : null, + "pairing" : 0 + } + + const _strSplitsQuotedRejoin_ = _.routine.unite + ({ + head : _strSplitsQuotedRejoin_head, + body : _strSplitsQuotedRejoin_body, + }); + + return _strSplitsQuotedRejoin_; +})(); +_.strSplitsQuotedRejoin.defaults = +{ + "quoting" : 1, + "quotingPrefixes" : null, + "quotingPostfixes" : null, + "preservingQuoting" : 1, + "inliningQuoting" : 1, + "splits" : null, + "delimeter" : null, + "onQuoting" : null, + "pairing" : 0 +} + +// + + + _.strSplitsDropDelimeters = ( function() { + + const _strSplitsDropDelimeters_head = function strSplitsDropDelimeters_head( routine, args ) + { + let o = args[ 0 ]; + + _.routine.options( routine, o ); + + if( _.strIs( o.delimeter ) ) + o.delimeter = [ o.delimeter ]; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 ); + _.assert( _.object.isBasic( o ) ); + + return o; + } + + const _strSplitsDropDelimeters_body = function strSplitsDropDelimeters_body( o ) + { + + _.assert( arguments.length === 1 ); + _.assert( _.arrayIs( o.splits ) ); + + /* stripping */ + + // if( o.delimeter.some( ( d ) => _.regexpIs( d ) ) ) + // debugger; + + for( let s = o.splits.length-1 ; s >= 0 ; s-- ) + { + let split = o.splits[ s ]; + + if( _.regexpsTestAny( o.delimeter, split ) ) /* xxx qqq : ? */ + o.splits.splice( s, 1 ); + + // if( _.longHas( o.delimeter, split ) ) + // o.splits.splice( s, 1 ); + // + // if( s % 2 === 1 ) + // o.splits.splice( s, 1 ); + + } + + return o.splits; + } + _strSplitsDropDelimeters_body.defaults = { "splits" : null, "delimeter" : null } + + const _strSplitsDropDelimeters_ = _.routine.unite + ({ + head : _strSplitsDropDelimeters_head, + body : _strSplitsDropDelimeters_body, + }); + + return _strSplitsDropDelimeters_; +})(); +_.strSplitsDropDelimeters.defaults = +{ "splits" : null, "delimeter" : null } + +// + + + _.strSplitsStrip = ( function() { + + const _strSplitsStrip_head = function strSplitsStrip_head( routine, args ) + { + let o = args[ 0 ]; + + _.routine.options( routine, o ); + + if( o.stripping && _.bool.like( o.stripping ) ) + o.stripping = _.strStrip.defaults.stripper; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 ); + _.assert( _.object.isBasic( o ) ); + _.assert( !o.stripping || _.strIs( o.stripping ) || _.regexpIs( o.stripping ) ); + + return o; + } + + const _strSplitsStrip_body = function strSplitsStrip_body( o ) + { + + _.assert( arguments.length === 1 ); + _.assert( _.arrayIs( o.splits ) ); + + if( !o.stripping ) + return o.splits; + + /* stripping */ + + for( let s = 0 ; s < o.splits.length ; s++ ) + { + let split = o.splits[ s ]; + + if( _.strIs( split ) ) + split = _.strStrip({ src : split, stripper : o.stripping }); + + o.splits[ s ] = split; + } + + return o.splits; + } + _strSplitsStrip_body.defaults = { "stripping" : 1, "splits" : null } + + const _strSplitsStrip_ = _.routine.unite + ({ + head : _strSplitsStrip_head, + body : _strSplitsStrip_body, + }); + + return _strSplitsStrip_; +})(); +_.strSplitsStrip.defaults = +{ "stripping" : 1, "splits" : null } + +// + + + _.strSplitsDropEmpty = ( function() { + + const _strSplitsDropEmpty_head = function strSplitsDropEmpty_head( routine, args ) + { + let o = args[ 0 ]; + + _.routine.options( routine, o ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 ); + _.assert( _.object.isBasic( o ) ); + + return o; + } + + const _strSplitsDropEmpty_body = function strSplitsDropEmpty_body( o ) + { + + _.assert( arguments.length === 1 ); + _.assert( _.arrayIs( o.splits ) ); + + /* stripping */ + + for( let s = 0 ; s < o.splits.length ; s++ ) + { + let split = o.splits[ s ]; + + if( !split ) + { + o.splits.splice( s, 1 ); + s -= 1; + } + + } + + return o.splits; + } + _strSplitsDropEmpty_body.defaults = { "splits" : null } + + const _strSplitsDropEmpty_ = _.routine.unite + ({ + head : _strSplitsDropEmpty_head, + body : _strSplitsDropEmpty_body, + }); + + return _strSplitsDropEmpty_; +})(); +_.strSplitsDropEmpty.defaults = +{ "splits" : null } + +// + + + _.strStrip = function strip( o ) +{ + + if( _.strIs( o ) || _.arrayIs( o ) ) + o = { src : o }; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options( strip, o ); + + o.stripper = stripperNormalize(); + let stripRoutine = _.regexpIs( o.stripper ) ? singleStripByRegexp : singleStripByArrayOfStrings; + + if( _.arrayIs( o.src ) ) + { + _.assert( _.strsAreAll( o.src ), 'Expects strings {-o.srs-}' ); + + let result = []; + for( let i = 0 ; i < o.src.length ; i++ ) + result[ i ] = stripRoutine( o.src[ i ] ); + return result; + } + + _.assert( _.strIs( o.src ) ); + return stripRoutine( o.src ); + + /* */ + + function stripperNormalize() + { + let stripper = o.stripper; + if( _.bool.likeTrue( o.stripper ) ) + { + stripper = strip.defaults.stripper; + } + else if( _.arrayIs( o.stripper ) ) + { + _.assert( _.strsAreAll( o.stripper ), 'Expects characters in container {-o.stripper-}' ); + } + else if( _.strIs( o.stripper ) ) + { + stripper = _.regexpEscape( o.stripper ); + stripper = new RegExp( stripper, 'g' ); + } + else if( !_.regexpIs( o.stripper ) ) + { + _.assert( 0, 'Unexpected type of {-o.stripper-}. Expects either a String, an Array or a Regexp {-o.stripper-}' ); + } + return stripper; + } + + /* */ + + function singleStripByRegexp( src ) + { + return src.replace( o.stripper, '' ); + } + + /* */ + + function singleStripByArrayOfStrings( src ) + { + let begin = 0; + for( ; begin < src.length ; begin++ ) + if( o.stripper.indexOf( src[ begin ] ) === -1 ) + break; + + let end = src.length-1; + for( ; end >= 0 ; end-- ) + if( o.stripper.indexOf( src[ end ] ) === -1 ) + break; + + if( begin >= end ) + return ''; + + return src.substring( begin, end + 1 ); + } + +} +_.strStrip.defaults = +{ "src" : null, "stripper" : /^(\s|\n|\0)+|(\s|\n|\0)+$/g } + +// + + + _.strLinesSelect = function strLinesSelect( o ) +{ + + if( arguments.length === 2 ) + { + + if( _.arrayIs( arguments[ 1 ] ) ) + o = { src : arguments[ 0 ], range : arguments[ 1 ] }; + else if( _.number.is( arguments[ 1 ] ) ) + o = { src : arguments[ 0 ], range : [ arguments[ 1 ], arguments[ 1 ]+1 ] }; + else _.assert( 0, 'unexpected argument', _.entity.strType( range ) ); + + } + else if( arguments.length === 3 ) + { + o = { src : arguments[ 0 ], range : [ arguments[ 1 ], arguments[ 2 ] ] }; + } + + _.routine.options( strLinesSelect, o ); + _.assert( arguments.length <= 3 ); + _.assert( _.strIs( o.src ) ); + _.assert( _.bool.like( o.highlighting ) || _.longHas( [ '*' ], o.highlighting ) ); + + if( _.bool.like( o.highlighting ) && o.highlighting ) + o.highlighting = '*'; + + /* range */ + + if( !o.range ) + { + if( o.line === null ) + { + o.range = [ 0, _.strCount( o.src, o.delimteter )+1 ]; + } + else + { + if( o.selectMode === 'center' ) + o.range = [ o.line - Math.ceil( ( o.nearestLines + 1 ) / 2 ) + 1, o.line + Math.floor( ( o.nearestLines - 1 ) / 2 ) + 1 ]; + else if( o.selectMode === 'begin' ) + o.range = [ o.line, o.line + o.nearestLines ]; + else if( o.selectMode === 'end' ) + o.range = [ o.line - o.nearestLines+1, o.line+1 ]; + } + // if( o.line !== null ) + // { + // if( o.selectMode === 'center' ) + // o.range = [ o.line - Math.ceil( ( o.nearestLines + 1 ) / 2 ) + 1, o.line + Math.floor( ( o.nearestLines - 1 ) / 2 ) + 1 ]; + // else if( o.selectMode === 'begin' ) + // o.range = [ o.line, o.line + o.nearestLines ]; + // else if( o.selectMode === 'end' ) + // o.range = [ o.line - o.nearestLines+1, o.line+1 ]; + // } + // else + // { + // o.range = [ 0, _.strCount( o.src, o.delimteter )+1 ]; + // } + } + + if( o.line === null ) + { + if( o.selectMode === 'center' ) + o.line = Math.floor( ( o.range[ 0 ] + o.range[ 1 ] ) / 2 ); + else if( o.selectMode === 'begin' ) + o.line = o.range[ 0 ]; + else if( o.selectMode === 'end' ) + o.line = o.range[ 1 ] - 1; + + o.line = o.line > 0 ? o.line : 1; + } + + _.assert( _.longIs( o.range ) ); + _.assert( _.intIs( o.line ) && o.line >= 0, 'Expects positive integer {-o.line-}.' ); + + /* */ + + let f = 0; + let counter = o.zeroLine; + while( counter < o.range[ 0 ] ) + { + f = o.src.indexOf( o.delimteter, f ); + if( f === -1 ) + return ''; + f += o.delimteter.length; + counter += 1; + } + + /* */ + + let l = f-1; + while( counter < o.range[ 1 ] ) + { + l += 1; + l = o.src.indexOf( o.delimteter, l ); + if( l === -1 ) + { + l = o.src.length; + break; + } + counter += 1; + } + + /* */ + + let result = f < l ? o.src.substring( f, l ) : ''; + + /* numbering */ + + let zeroLine = o.range[ 0 ] <= 0 ? o.zeroLine : o.range[ 0 ]; + + if( o.numbering && result.length ) + result = _.strLinesNumber + ({ + src : result, + zeroLine, + onLine : lineHighlight, + }); + + return result; + + /* */ + + function lineHighlight( line, l ) + { + if( !o.highlighting ) + return line.join( '' ); + if( l === o.line ) + line[ 0 ] = '* ' + line[ 0 ]; + else + line[ 0 ] = ' ' + line[ 0 ]; + // line[ 1 ] = _.strBut( line[ 1 ], 0, '*' ); + return line.join( '' ); + } + + /* */ + +} +_.strLinesSelect.defaults = +{ + "src" : null, + "range" : null, + "line" : null, + "nearestLines" : 3, + "selectMode" : `center`, + "highlighting" : `*`, + "numbering" : 0, + "zeroLine" : 1, + "delimteter" : `\n` +} + +// + + + _._strLeftSingle_ = function _leftSingle_( src, ins, cinterval ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( _.strIs( src ) ); + + if( _.number.is( cinterval ) ) + cinterval = [ cinterval, src.length - 1 ]; + else if( cinterval === undefined ) + cinterval = [ 0, src.length - 1 ]; + + cinterval[ 0 ] = cinterval[ 0 ] === undefined ? 0 : cinterval[ 0 ]; + cinterval[ 1 ] = cinterval[ 1 ] === undefined ? src.length - 1 : cinterval[ 1 ]; + + if( cinterval[ 0 ] < 0 ) + cinterval[ 0 ] = src.length + cinterval[ 0 ]; + if( cinterval[ 1 ] < -1 ) + cinterval[ 1 ] = src.length + cinterval[ 1 ]; + + _.assert( _.intervalIs( cinterval ) ); + _.assert( 0 <= cinterval[ 0 ] && cinterval[ 0 ] <= src.length ); + _.assert( -1 <= cinterval[ 1 ] && cinterval[ 1 ] <= src.length - 1 ); + + let result = Object.create( null ); + result.index = src.length; + result.instanceIndex = -1; + result.entry = undefined; + + let src1 = src.substring( cinterval[ 0 ], cinterval[ 1 ] + 1 ); + + ins = _.array.as( ins ); + + for( let k = 0 ; k < ins.length ; k++ ) + { + let entry = ins[ k ]; + if( _.strIs( entry ) ) + { + let found = src1.indexOf( entry ); + if( found >= 0 && ( found < result.index || result.entry === undefined ) ) + { + result.instanceIndex = k; + result.index = found; + result.entry = entry; + } + } + else if( _.regexpIs( entry ) ) + { + let found = src1.match( entry ); + if( found && ( found.index < result.index || result.entry === undefined ) ) + { + result.instanceIndex = k; + result.index = found.index; + result.entry = found[ 0 ]; + } + } + else _.assert( 0, 'Expects string-like ( string or regexp )' ); + } + + if( cinterval[ 0 ] !== 0 && result.index !== src.length ) + result.index += cinterval[ 0 ]; + + return result; +} + +// + + + _._strRightSingle_ = function _rightSingle_( src, ins, cinterval ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( _.strIs( src ) ); + + if( _.number.is( cinterval ) ) + cinterval = [ cinterval, src.length - 1 ]; + else if( cinterval === undefined ) + cinterval = [ 0, src.length - 1 ]; + + cinterval[ 0 ] = cinterval[ 0 ] === undefined ? 0 : cinterval[ 0 ]; + cinterval[ 1 ] = cinterval[ 1 ] === undefined ? src.length - 1 : cinterval[ 1 ]; + + if( cinterval[ 0 ] < 0 ) + cinterval[ 0 ] = src.length + cinterval[ 0 ]; + if( cinterval[ 1 ] < -1 ) + cinterval[ 1 ] = src.length + cinterval[ 1 ]; + + _.assert( _.intervalIs( cinterval ) ); + _.assert( 0 <= cinterval[ 0 ] && cinterval[ 0 ] <= src.length ); + _.assert( -1 <= cinterval[ 1 ] && cinterval[ 1 ] <= src.length - 1 ); + + let olength = src.length; + + let result = Object.create( null ); + result.index = -1; + result.instanceIndex = -1; + result.entry = undefined; + + let src1 = src.substring( cinterval[ 0 ], cinterval[ 1 ] + 1 ); + + ins = _.array.as( ins ); + + for( let k = 0, len = ins.length ; k < len ; k++ ) + { + let entry = ins[ k ]; + if( _.strIs( entry ) ) + { + let found = src1.lastIndexOf( entry ); + if( found >= 0 && found > result.index ) + { + result.instanceIndex = k; + result.index = found; + result.entry = entry; + } + } + else if( _.regexpIs( entry ) ) + { + + let regexp1 = _.regexpsJoin([ '.*', '(', entry, ')' ]); + let match1 = src1.match( regexp1 ); + if( !match1 ) + continue; + + let regexp2 = _.regexpsJoin([ entry, '(?!(?=.).*', entry, ')' ]); + let match2 = src1.match( regexp2 ); + _.assert( !!match2 ); + + let found; + let found1 = match1[ 1 ]; + let found2 = match2[ 0 ]; + let index; + let index1 = match1.index + match1[ 0 ].length; + let index2 = match2.index + match2[ 0 ].length; + + if( index1 === index2 ) + { + if( found1.length < found2.length ) + { + found = found2; + index = index2 - found.length; + } + else + { + found = found1; + index = index1 - found.length; + } + } + else if( index1 < index2 ) + { + found = found2; + index = index2 - found.length; + } + else + { + found = found1; + index = index1 - found.length; + } + + if( index > result.index ) + { + result.instanceIndex = k; + result.index = index; + result.entry = found; + } + + } + else _.assert( 0, 'Expects string-like ( string or regexp )' ); + } + + if( cinterval[ 0 ] !== 0 && result.index !== -1 ) + result.index += cinterval[ 0 ]; + + return result; +} + +// + + + _.strIsolate = ( function() { + + const _strIsolate_head = function strIsolate_head( routine, args ) + { + let o; + + if( args.length > 1 ) + { + if( args.length === 3 ) + o = { src : args[ 0 ], delimeter : args[ 1 ], times : args[ 2 ] }; + else if( args.length === 2 ) + o = { src : args[ 0 ], delimeter : args[ 1 ] }; + else + o = { src : args[ 0 ] }; + } + else + { + o = args[ 0 ]; + _.assert( args.length === 1, 'Expects single argument' ); + } + + _.routine.options( routine, o ); + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( o.src ) ); + _.assert( _.regexpsLikeAll( o.delimeter ) ) + _.assert( _.number.is( o.times ) ); + + return o; + } + + const _strIsolate_body = function strIsolate_body( o ) + { + let result = []; + let times = o.times; + let delimeter + let index = o.left ? 0 : o.src.length; + let more = o.left ? strLeft : strRight; + let delta = ( o.left ? +1 : -1 ); + + _.routine.assertOptions( strIsolate_body, arguments ); + + /* */ + + if( _.arrayIs( o.delimeter ) && o.delimeter.length === 1 ) + o.delimeter = o.delimeter[ 0 ]; + + let quote; + if( o.quote ) + quote = _.strQuoteAnalyze({ src : o.src, quote : o.quote }); + + /* */ + + while( times > 0 ) + { + let found = more( index ); + + if( found.entry === undefined ) + break; + + times -= 1; + + if( o.left ) + index = found.index + delta; + else + index = found.index + found.entry.length + delta; + + if( times === 0 ) + { + result.push( o.src.substring( 0, found.index ) ); + result.push( found.entry ); + result.push( o.src.substring( found.index + found.entry.length ) ); + return result; + } + + /* */ + + if( o.left ) + { + if( index >= o.src.length ) + break; + } + else + { + if( index <= 0 ) + break; + } + + } + + /* */ + + if( !result.length ) + { + + if( o.times === 0 ) + return everything( !o.left ); + else if( times === o.times ) + return everything( o.left ^ o.none ); + else + return everything( o.left ); + + } + + return result; + + /* */ + + function everything( side ) + { + return ( side ) ? [ o.src, undefined, '' ] : [ '', undefined, o.src ]; + } + + /* */ + + function strLeft( index ) + { + // let r = _._strLeftSingle( o.src, o.delimeter, [ index, undefined ] ); + let r = _._strLeftSingle_( o.src, o.delimeter, [ index, undefined ] ); + if( quote ) + if( r.entry !== undefined ) + { + let range = inQuoteRange( r.index ); + if( range ) + return strLeft( range[ 1 ]+1 ); + } + return r; + } + + /* */ + + function strRight( index ) + { + // let r = _._strRightSingle( o.src, o.delimeter, [ undefined, index ] ); + let r = _._strRightSingle_( o.src, o.delimeter, [ undefined, index-1 ] ); + if( quote ) + if( r.entry !== undefined ) + { + let range = inQuoteRange( r.index ); + if( range ) + return strRight( range[ 0 ] ); + } + return r; + } + + /* */ + + function inQuoteRange( offset ) + { + let i = _.sorted.searchFirstIndex( quote.ranges, offset ); + if( i % 2 ) + { + i -= 1; + } + if( i < 0 || i >= quote.ranges.length ) + return false; + let b = quote.ranges[ i ]; + let e = quote.ranges[ i+1 ]; + if( !( b <= offset && offset <= e ) ) + return false; + return [ b, e ]; + } + + /* */ + + // function binSearch( val ) + // { + // let l = 0; + // let r = quote.ranges.length; + // let m; + // if( quote.ranges.length ) + // debugger; + // do + // { + // m = Math.floor( ( l + r ) / 2 ); + // if( quote.ranges[ m ] < val ) + // l = m+1; + // else if( quote.ranges[ m ] > val ) + // r = m; + // else + // return m; + // } + // while( l < r ); + // if( quote.ranges[ m ] < val ) + // return m+1; + // return m; + // } + + /* */ + + // let quotedRanges = []; + // + // function quoteRangesSetup( index ) + // { + // let quotes = []; + // for( let i = 0 ; i < o.src.length ; i++ ) + // { + // if( _.arrayHas( o.quote, ) ) + // } + // } + // + // function quoteRange( index ) + // { + // for( let i = 0 ; i < x ; i++ ) + // + // } + + } + _strIsolate_body.defaults = { + "src" : null, + "delimeter" : ` `, + "quote" : 0, + "left" : 1, + "times" : 1, + "none" : 1 + } + + const _strIsolate_ = _.routine.unite + ({ + head : _strIsolate_head, + body : _strIsolate_body, + }); + + return _strIsolate_; +})(); +_.strIsolate.defaults = +{ + "src" : null, + "delimeter" : ` `, + "quote" : 0, + "left" : 1, + "times" : 1, + "none" : 1 +} + +// + + + _.strIsolateLeftOrNone = ( function() { + + const _strIsolateLeftOrNone_head = function strIsolate_head( routine, args ) + { + let o; + + if( args.length > 1 ) + { + if( args.length === 3 ) + o = { src : args[ 0 ], delimeter : args[ 1 ], times : args[ 2 ] }; + else if( args.length === 2 ) + o = { src : args[ 0 ], delimeter : args[ 1 ] }; + else + o = { src : args[ 0 ] }; + } + else + { + o = args[ 0 ]; + _.assert( args.length === 1, 'Expects single argument' ); + } + + _.routine.options( routine, o ); + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( o.src ) ); + _.assert( _.regexpsLikeAll( o.delimeter ) ) + _.assert( _.number.is( o.times ) ); + + return o; + } + + const _strIsolateLeftOrNone_body = function strIsolateLeftOrNone_body( o ) + { + o.left = 1; + o.none = 1; + let result = _.strIsolate.body( o ); + return result; + } + _strIsolateLeftOrNone_body.defaults = { + "src" : null, + "delimeter" : ` `, + "times" : 1, + "quote" : null + } + + const _strIsolateLeftOrNone_ = _.routine.unite + ({ + head : _strIsolateLeftOrNone_head, + body : _strIsolateLeftOrNone_body, + }); + + return _strIsolateLeftOrNone_; +})(); +_.strIsolateLeftOrNone.defaults = +{ + "src" : null, + "delimeter" : ` `, + "times" : 1, + "quote" : null +} + +// + + + _.strIsolateRightOrNone = ( function() { + + const _strIsolateRightOrNone_head = function strIsolate_head( routine, args ) + { + let o; + + if( args.length > 1 ) + { + if( args.length === 3 ) + o = { src : args[ 0 ], delimeter : args[ 1 ], times : args[ 2 ] }; + else if( args.length === 2 ) + o = { src : args[ 0 ], delimeter : args[ 1 ] }; + else + o = { src : args[ 0 ] }; + } + else + { + o = args[ 0 ]; + _.assert( args.length === 1, 'Expects single argument' ); + } + + _.routine.options( routine, o ); + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( o.src ) ); + _.assert( _.regexpsLikeAll( o.delimeter ) ) + _.assert( _.number.is( o.times ) ); + + return o; + } + + const _strIsolateRightOrNone_body = function strIsolateRightOrNone_body( o ) + { + o.left = 0; + o.none = 1; + let result = _.strIsolate.body( o ); + return result; + } + _strIsolateRightOrNone_body.defaults = { + "src" : null, + "delimeter" : ` `, + "times" : 1, + "quote" : null + } + + const _strIsolateRightOrNone_ = _.routine.unite + ({ + head : _strIsolateRightOrNone_head, + body : _strIsolateRightOrNone_body, + }); + + return _strIsolateRightOrNone_; +})(); +_.strIsolateRightOrNone.defaults = +{ + "src" : null, + "delimeter" : ` `, + "times" : 1, + "quote" : null +} + +// + + + _.strIsolateLeftOrAll = ( function() { + + const _strIsolateLeftOrAll_head = function strIsolate_head( routine, args ) + { + let o; + + if( args.length > 1 ) + { + if( args.length === 3 ) + o = { src : args[ 0 ], delimeter : args[ 1 ], times : args[ 2 ] }; + else if( args.length === 2 ) + o = { src : args[ 0 ], delimeter : args[ 1 ] }; + else + o = { src : args[ 0 ] }; + } + else + { + o = args[ 0 ]; + _.assert( args.length === 1, 'Expects single argument' ); + } + + _.routine.options( routine, o ); + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( o.src ) ); + _.assert( _.regexpsLikeAll( o.delimeter ) ) + _.assert( _.number.is( o.times ) ); + + return o; + } + + const _strIsolateLeftOrAll_body = function strIsolateLeftOrAll_body( o ) + { + o.left = 1; + o.none = 0; + let result = _.strIsolate.body( o ); + return result; + } + _strIsolateLeftOrAll_body.defaults = { + "src" : null, + "delimeter" : ` `, + "times" : 1, + "quote" : null + } + + const _strIsolateLeftOrAll_ = _.routine.unite + ({ + head : _strIsolateLeftOrAll_head, + body : _strIsolateLeftOrAll_body, + }); + + return _strIsolateLeftOrAll_; +})(); +_.strIsolateLeftOrAll.defaults = +{ + "src" : null, + "delimeter" : ` `, + "times" : 1, + "quote" : null +} + +// + + + _.strIsolateRightOrAll = ( function() { + + const _strIsolateRightOrAll_head = function strIsolate_head( routine, args ) + { + let o; + + if( args.length > 1 ) + { + if( args.length === 3 ) + o = { src : args[ 0 ], delimeter : args[ 1 ], times : args[ 2 ] }; + else if( args.length === 2 ) + o = { src : args[ 0 ], delimeter : args[ 1 ] }; + else + o = { src : args[ 0 ] }; + } + else + { + o = args[ 0 ]; + _.assert( args.length === 1, 'Expects single argument' ); + } + + _.routine.options( routine, o ); + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( o.src ) ); + _.assert( _.regexpsLikeAll( o.delimeter ) ) + _.assert( _.number.is( o.times ) ); + + return o; + } + + const _strIsolateRightOrAll_body = function strIsolateRightOrAll_body( o ) + { + o.left = 0; + o.none = 0; + let result = _.strIsolate.body( o ); + return result; + } + _strIsolateRightOrAll_body.defaults = { + "src" : null, + "delimeter" : ` `, + "times" : 1, + "quote" : null + } + + const _strIsolateRightOrAll_ = _.routine.unite + ({ + head : _strIsolateRightOrAll_head, + body : _strIsolateRightOrAll_body, + }); + + return _strIsolateRightOrAll_; +})(); +_.strIsolateRightOrAll.defaults = +{ + "src" : null, + "delimeter" : ` `, + "times" : 1, + "quote" : null +} + +// + + + _.strLinesIndentation = function strLinesIndentation( src, tab, every ) +{ + + if( every === undefined ) + every = true; + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( _.strIs( src ) || _.arrayIs( src ), 'Expects src as string or array' ); + _.assert( _.strIs( tab ) || _.number.is( tab ), 'Expects tab as string or number' ); + _.assert( every === undefined || _.bool.like( every ) ); + + if( _.number.is( tab ) ) + tab = _.strDup( ' ', tab ); + + if( _.strIs( src ) ) + { + if( src.indexOf( '\n' ) === -1 ) + return src; + src = _.str.lines.split( src ); + } + + /* + should be no tab in prolog + */ + + if( every === true ) + { + let result = src.join( '\n' + tab ); + return result; + } + else + { + let result = ''; + src.forEach( ( e, c ) => + { + if( c > 0 ) + result += '\n'; + result += e.length > 0 && c > 0 ? tab + e : e; + }); + return result; + } +} + +// + + + _.strEscape = function strEscape( o ) +{ + + // 007f : '' + // . . . + // 009f : 'Ÿ' + + // 00ad : '­' + + // \' single quote byte 0x27 in ASCII encoding + // \' double quote byte 0x22 in ASCII encoding + // \\ backslash byte 0x5c in ASCII encoding + // \b backspace byte 0x08 in ASCII encoding + // \f form feed - new page byte 0x0c in ASCII encoding + // \n line feed - new line byte 0x0a in ASCII encoding + // \r carriage return byte 0x0d in ASCII encoding + // \t horizontal tab byte 0x09 in ASCII encoding + // \v vertical tab byte 0x0b in ASCII encoding + // source : http://en.cppreference.com/w/cpp/language/escape + + if( _.strIs( o ) ) + o = { src : o } + + _.assert( _.strIs( o.src ), 'Expects string {-o.src-}, but got', _.entity.strType( o.src ) ); + _.routine.options( strEscape, o ); + + let result = ''; + let stringWrapperCode = o.stringWrapper.charCodeAt( 0 ); + for( let s = 0 ; s < o.src.length ; s++ ) + { + let code = o.src.charCodeAt( s ); + + if( o.stringWrapper === '`' && code === 0x24 /* $ */ ) + { + result += '\\$'; + } + else if( o.stringWrapper && code === stringWrapperCode ) + { + result += '\\' + o.stringWrapper; + } + else if( 0x007f <= code && code <= 0x009f || code === 0x00ad /*|| code >= 65533*/ ) + { + result += _.strCodeUnicodeEscape( code ); + } + else switch( code ) + { + + case 0x5c /* '\\' */ : + result += '\\\\'; + break; + + case 0x08 /* '\b' */ : + result += '\\b'; + break; + + case 0x0c /* '\f' */ : + result += '\\f'; + break; + + case 0x0a /* '\n' */ : + result += '\\n'; + break; + + case 0x0d /* '\r' */ : + result += '\\r'; + break; + + case 0x09 /* '\t' */ : + result += '\\t'; + break; + + // /* xxx : extend coverage of routine _.strEscape. don't forget this test case */ + // case 0x0b /* '\v' */ : + // result += '\\v'; + // break; + + default : + if( code < 32 ) + { + result += _.strCodeUnicodeEscape( code ); + } + else + { + result += String.fromCharCode( code ); + } + + } + + } + + return result; +} +_.strEscape.defaults = +{ "src" : null, "stringWrapper" : `'`, "charsToEscape" : null } + +// + + + _.strShort_ = function short_( o ) /* version with binary search cutting */ +{ + + if( arguments.length === 2 ) + o = { src : arguments[ 0 ], widthLimit : arguments[ 1 ] }; + else if( arguments.length === 1 ) + if( _.strIs( o ) ) + o = { src : arguments[ 0 ] }; + + _.routine.options( short_, o ); + + _.assert( _.strIs( o.src ) ); + _.assert( _.number.is( o.widthLimit ) ); + _.assert( o.widthLimit >= 0, 'Option::o.widthLimit must be greater or equal to zero' ); + _.assert + ( + _.number.is( o.heightLimit ) && o.heightLimit >= 0, + 'If provided option::o.heightLimit must be greater or equal to zero' + ); + _.assert( o.delimeter === null || _.strIs( o.delimeter ) || _.bool.likeTrue( o.delimeter )); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( !o.delimeter ) + o.delimeter = ''; + if( !o.heightDelimeter ) + o.heightDelimeter = ''; + if( o.widthLimit === 0 ) + o.widthLimit = Infinity; + if( o.heightLimit === 0 ) + o.heightLimit = Infinity; + + if( _.bool.likeTrue( o.delimeter ) ) + o.delimeter = '...'; + + if( !o.onLength ) + o.onLength = ( src ) => src.length; + + let src = o.src; + + let isOneLine = o.src.indexOf( '\n' ) === -1; + + if( isOneLine && o.onLength( o.src ) < o.widthLimit ) + { + o.changed = false; + o.result = o.src; + + return o; + } + + let options = Object.create( null ); /* width cutting options */ + options.limit = o.widthLimit; + options.delimeter = o.delimeter; + options.onLength = o.onLength; + options.cutting = o.cutting; + + if( isOneLine ) + { + options.src = src; + _.strShortWidth( options ); + + o.result = options.result; + o.changed = options.changed; + + return o; + } + else + { + let splitted = o.src.split( '\n' ); + + let options2 = Object.create( null ); /* height cutting */ + options2.src = splitted; + options2.limit = o.heightLimit; + options2.delimeter = o.heightDelimeter; + options2.cutting = o.heightCutting; + _._strShortHeight( options2 ); + + options.src = options2.result; + + _._strShortWidth( options ); + + let result = options.result.join( '\n' ); + + if( result === o.src ) + o.changed = false; + else if( result !== o.src ) + o.changed = true; + + o.result = result; + + return o; + } +} +_.strShort_.defaults = +{ + "src" : null, + "widthLimit" : 40, + "heightLimit" : 0, + "delimeter" : null, + "heightDelimeter" : null, + "onLength" : null, + "cutting" : `center`, + "heightCutting" : `center` +} + +// + + + _.numberFromStrMaybe = function fromStrMaybe( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ) || _.number.is( src ) ); + + if( _.number.is( src ) ) + return src; + if( !src ) /* qqq : cover */ + return src; + + // let parsed = !src ? NaN : Number( src ); /* Dmytro : it is strange code, the previous branch checks this condition */ + // if( !isNaN( parsed ) ) + // return parsed; + // return src; + + let parsed = src ? Number( src ) : NaN; + if( !isNaN( parsed ) ) + return parsed; + return src; +} + +// + + + + _.path.name = ( function() { + + const _name_head = function name_head( routine, args ) + { + let o = args[ 0 ]; + if( _.strIs( o ) ) + o = { path : o }; + + _.routine.options_( routine, o ); + _.assert( args.length === 1 ); + _.assert( arguments.length === 2 ); + _.assert( _.strIs( o.path ), 'Expects string {-o.path-}' ); + + return o; + } + + const _name_body = function name_body( o ) + { + + if( _.strIs( o ) ) + o = { path : o }; + + _.routine.assertOptions( name_body, arguments ); + + o.path = this.canonize( o.path ); + + let i = o.path.lastIndexOf( '/' ); + if( i !== -1 ) + o.path = o.path.substr( i+1 ); + + if( !o.full ) + { + let i = o.path.lastIndexOf( '.' ); + if( i !== -1 ) o.path = o.path.substr( 0, i ); + } + + return o.path; + } + _name_body.defaults = { "path" : null, "full" : 0 } + + const _name_ = _.routine.unite + ({ + head : _name_head, + body : _name_body, + }); + + return _name_; +})(); +_.path.name.defaults = +{ "path" : null, "full" : 0 } + +// + + + _.path.fullName = ( function() { + + const _name_head = function name_head( routine, args ) + { + let o = args[ 0 ]; + if( _.strIs( o ) ) + o = { path : o }; + + _.routine.options_( routine, o ); + _.assert( args.length === 1 ); + _.assert( arguments.length === 2 ); + _.assert( _.strIs( o.path ), 'Expects string {-o.path-}' ); + + return o; + } + + const _name_body = function name_body( o ) + { + + if( _.strIs( o ) ) + o = { path : o }; + + _.routine.assertOptions( name_body, arguments ); + + o.path = this.canonize( o.path ); + + let i = o.path.lastIndexOf( '/' ); + if( i !== -1 ) + o.path = o.path.substr( i+1 ); + + if( !o.full ) + { + let i = o.path.lastIndexOf( '.' ); + if( i !== -1 ) o.path = o.path.substr( 0, i ); + } + + return o.path; + } + _name_body.defaults = { "path" : null, "full" : 0 } + + const _name_ = _.routine.unite + ({ + head : _name_head, + body : _name_body, + }); + + return _name_; +})(); +_.path.fullName.defaults = +{ "path" : null, "full" : 1 } + +// + + + + _.str = { + "lines" : + { + "Eol" : + { + "any" : [ `\r\n`, `\n\r`, `\n` ], + "posix" : `\n`, + "windows" : `\r\n`, + "mac" : `\n\r`, + "default" : `\n` + }, + "split" : function split( src, eol ) +{ + if( _.arrayIs( src ) ) + return src; + _.assert( _.strIs( src ) || _.arrayIs( src ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + if( eol === undefined ) + eol = _.str.lines.Eol.default; + return src.split( eol ); +}, + "join" : function join( src, eol ) +{ + _.assert( _.strIs( src ) || _.arrayIs( src ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + if( eol === undefined ) + eol = _.str.lines.Eol.default; + let result = src; + if( _.arrayIs( src ) ) + result = src.join( eol ); + return result; +}, + "strip" : function strip( src ) +{ + + if( arguments.length > 1 ) + { + let result = _.unroll.make( null ); + for( let a = 0 ; a < arguments.length ; a++ ) + result[ a ] = _.str.lines.strip( arguments[ a ] ); + return result; + } + + _.assert( _.strIs( src ) || _.arrayIs( src ) ); + _.assert( arguments.length === 1 ); + + let lines = _.strLinesSplit( src ); + lines = lines.map( ( line ) => line.trim() ).filter( ( line ) => line ); + + if( _.strIs( src ) ) + lines = _.str.lines.join( lines ); + return lines; +}, + "atLeft" : function atLeft( src, index, eol ) +{ + let result; + + _.assert( _.number.is( index ) ); + + if( index < 0 ) + { + result = Object.create( null ); + result.src = src; + result.lineIndex = index; + result.charInterval = [ 0, -1 ]; + return result; + } + + let o2 = Object.create( null ); + o2.src = src; + o2.eol = eol; + o2.onEach = onEach; + o2.interval = [ index, index ]; + o2.withLine = false; + this.eachLeft( o2 ); + + if( !result ) + { + result = Object.create( null ); + result.src = src; + result.lineIndex = index; + result.charInterval = [ src.length, src.length-1 ]; + } + + delete result.eol; + delete result.onEach; + delete result.interval; + delete result.withLine; + + return result; + + function onEach( it ) + { + result = it; + result.line = src.slice( it.charInterval[ 0 ], it.charInterval[ 1 ]-it.nl.length+1 ); + } + +}, + "atRight" : function atRight( src, index, eol ) +{ + let result; + + _.assert( _.number.is( index ) ); + + if( index < 0 ) + { + result = Object.create( null ); + result.src = src; + result.lineIndex = index; + result.charInterval = [ src.length, src.length-1 ]; + return result; + } + + let o2 = Object.create( null ); + o2.src = src; + o2.eol = eol; + o2.onEach = onEach; + o2.interval = [ index, index ]; + o2.withLine = false; + + this.eachRight( o2 ); + + if( !result ) + { + result = Object.create( null ); + result.src = src; + result.lineIndex = index; + result.charInterval = [ 0, -1 ]; + } + + delete result.eol; + delete result.onEach; + delete result.interval; + delete result.withLine; + + return result; + + function onEach( it ) + { + result = it; + result.line = src.slice( it.charInterval[ 0 ], it.charInterval[ 1 ]-it.nl.length+1 ); + } + +}, + "at" : function atLeft( src, index, eol ) +{ + let result; + + _.assert( _.number.is( index ) ); + + if( index < 0 ) + { + result = Object.create( null ); + result.src = src; + result.lineIndex = index; + result.charInterval = [ 0, -1 ]; + return result; + } + + let o2 = Object.create( null ); + o2.src = src; + o2.eol = eol; + o2.onEach = onEach; + o2.interval = [ index, index ]; + o2.withLine = false; + this.eachLeft( o2 ); + + if( !result ) + { + result = Object.create( null ); + result.src = src; + result.lineIndex = index; + result.charInterval = [ src.length, src.length-1 ]; + } + + delete result.eol; + delete result.onEach; + delete result.interval; + delete result.withLine; + + return result; + + function onEach( it ) + { + result = it; + result.line = src.slice( it.charInterval[ 0 ], it.charInterval[ 1 ]-it.nl.length+1 ); + } + +}, + "_eachLeft" : function _eachLeft( o ) +{ + + if( o.eol === undefined ) + o.eol = _.str.lines.Eol.default; + else if( !_.str.is( o.eol ) ) + o.eol = [ ... o.eol ]; + + const lastIndex = o.interval ? o.interval[ 1 ] : Infinity; + const src = o.src; + let foundTokenIndex; + let foundOffset; + let handleEach; + + o.charInterval = [ -1, -1 ]; + o.lineIndex = -1; + + if( o.interval && o.interval[ 1 ] < 0 ) + { + o.charInterval[ 0 ] = 0; + return o; + } + + o.nl = ''; + + if( o.interval ) + { + if( o.withLine ) + handleEach = handleWithIntervalWithLine; + else + handleEach = handleWithIntervalWithoutLine; + } + else + { + if( o.withLine ) + handleEach = handleWithoutIntervalWithLine; + else + handleEach = handleWithoutIntervalWithoutLine; + } + + if( _.str.is( o.eol ) ) + single(); + else + multiple(); + + if( !o.interval || o.lineIndex < o.interval[ 1 ] ) + { + o.lineIndex += 1; + o.charInterval[ 0 ] = src.length; + _.assert( o.charInterval[ 1 ] === src.length - 1 ); + if( o.withLine ) + o.line = ''; + } + + return o; + + /* */ + + function single() + { + + o.nl = o.eol; + while( o.lineIndex !== lastIndex ) + { + o.charInterval[ 0 ] = Math.max( o.charInterval[ 0 ], o.charInterval[ 1 ] ) + 1; + o.charInterval[ 1 ] = src.indexOf( o.eol, o.charInterval[ 0 ] ); + o.lineIndex += 1; + + if( o.charInterval[ 1 ] === -1 ) + { + o.charInterval[ 1 ] = src.length - 1; + o.nl = ''; + handleEach(); + break; + } + else + { + o.charInterval[ 1 ] += o.nl.length - 1; + handleEach(); + } + + } + + } + + /* */ + + function multiple() + { + + foundTokenIndex = -1; + foundOffset = src.length; + + let first = indexInit(); + + if( first.length === 1 ) + { + o.eol = o.eol[ foundTokenIndex ]; + return single(); + } + + if( first.length === 0 ) + { + + o.lineIndex = 0; + o.charInterval[ 0 ] = 0; + o.charInterval[ 1 ] = src.length-1; + handleEach(); + + return; + } + + while( o.lineIndex !== lastIndex ) + { + o.charInterval[ 0 ] = Math.max( o.charInterval[ 0 ], o.charInterval[ 1 ] ) + 1; + o.charInterval[ 1 ] = indexOf( first ); + o.lineIndex += 1; + + if( o.charInterval[ 1 ] === o.src.length ) + { + o.charInterval[ 1 ] = src.length - 1; + o.nl = ''; + handleEach(); + break; + } + else + { + o.nl = o.eol[ foundTokenIndex ]; + o.charInterval[ 1 ] += o.nl.length - 1; + handleEach(); + } + + } + + } + + /* */ + + function indexInit() + { + let first = []; + for( let i = o.eol.length - 1 ; i >= 0 ; i-- ) + { + let offset = src.indexOf( o.eol[ i ] ); + if( offset !== -1 ) + { + first.unshift( offset ); + if( foundOffset >= offset ) + { + foundOffset = offset; + foundTokenIndex = i; + } + } + else + { + o.eol.splice( i, 1 ); + foundTokenIndex -= 1; + } + } + return first; + } + + /* */ + + function indexOf( first ) + { + if( first[ foundTokenIndex ] >= o.charInterval[ 0 ] ) + return first[ foundTokenIndex ]; + foundOffset = src.length; + for( let i = first.length - 1; i >= 0 ; i-- ) + { + let offset = first[ i ]; + if( offset < o.charInterval[ 0 ] ) + { + offset = src.indexOf( o.eol[ i ], first[ i ]+1 ); + if( offset === -1 ) + { + tokenDelete( first, i ); + if( first.length === 0 ) + return src.length; + } + else + { + first[ i ] = offset; + if( foundOffset >= offset ) + { + foundOffset = offset; + foundTokenIndex = i; + } + } + } + else + { + if( foundOffset >= offset ) + { + foundOffset = offset; + foundTokenIndex = i; + } + } + } + return first[ foundTokenIndex ]; + } + + /* */ + + function tokenDelete( first, i ) + { + o.eol.splice( i, 1 ); + first.splice( i, 1 ); + if( foundTokenIndex > i ) + foundTokenIndex -= 1; + } + + /* */ + + function handleWithoutIntervalWithoutLine() + { + o.onEach( o ); + } + + /* */ + + function handleWithIntervalWithoutLine() + { + if( o.interval && o.interval[ 0 ] > o.lineIndex ) + return; + o.onEach( o ); + } + + /* */ + + function handleWithoutIntervalWithLine() + { + o.line = src.slice( o.charInterval[ 0 ], o.charInterval[ 1 ] - o.nl.length + 1 ); + o.onEach( o ); + } + + /* */ + + function handleWithIntervalWithLine() + { + if( o.interval && o.interval[ 0 ] > o.lineIndex ) + return; + o.line = src.slice( o.charInterval[ 0 ], o.charInterval[ 1 ] - o.nl.length + 1 ); + o.onEach( o ); + } + + /* */ + +}, + "eachLeft" : function eachLeft( o ) +{ + + if( !_.map.is( o ) ) + { + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( arguments.length === 3 ) + o = { src : arguments[ 0 ], interval : arguments[ 1 ], onEach : arguments[ 2 ] }; + else + o = { src : arguments[ 0 ], onEach : arguments[ 1 ] }; + } + else + { + _.assert( arguments.length === 1 ); + } + + if( o.withLine === undefined ) + o.withLine = true; + + _.assert( _.routine.is( o.onEach ) ); + _.assert( _.str.is( o.src ) ); + + return this._eachLeft( o ); +}, + "_eachRight" : function _eachRight( o ) +{ + + if( o.eol === undefined ) + o.eol = _.str.lines.Eol.default; + else if( !_.str.is( o.eol ) ) + o.eol = [ ... o.eol ]; + + const lastIndex = o.interval ? o.interval[ 1 ] : Infinity; + const src = o.src; + let foundTokenIndex; + let foundOffset; + let nnl = ''; + let handleEach; + + if( o.interval ) + { + if( o.withLine ) + handleEach = handleWithIntervalWithLine; + else + handleEach = handleWithIntervalWithoutLine; + } + else + { + if( o.withLine ) + handleEach = handleWithoutIntervalWithLine; + else + handleEach = handleWithoutIntervalWithoutLine; + } + + o.charInterval = [ o.src.length, o.src.length ]; + o.lineIndex = -1; + + if( o.interval && o.interval[ 1 ] < 0 ) + { + o.charInterval[ 1 ] = o.src.length-1; + return o; + } + + o.nl = ''; + + if( _.str.is( o.eol ) ) + single(); + else + multiple(); + + if( !o.interval || o.lineIndex < o.interval[ 1 ] ) + { + o.lineIndex += 1; + o.charInterval[ 1 ] = -1; + _.assert( o.charInterval[ 0 ] === 0 ); + if( o.withLine ) + o.line = ''; + } + + return o; + + /* */ + + function single() + { + + while( o.lineIndex !== lastIndex ) + { + + o.lineIndex += 1; + o.nl = nnl; + + o.charInterval[ 1 ] = o.charInterval[ 0 ] - 1; + let right = o.charInterval[ 1 ] - o.nl.length; + if( right >= 0 || o.lineIndex === 0 ) + o.charInterval[ 0 ] = src.lastIndexOf( o.eol, right ); + else + o.charInterval[ 0 ] = -1; + + if( o.charInterval[ 0 ] === -1 ) + { + o.charInterval[ 0 ] = 0; + handleEach(); + break; + } + else + { + nnl = o.eol; + o.charInterval[ 0 ] += nnl.length; + handleEach(); + } + + } + + } + + /* */ + + function multiple() + { + + foundTokenIndex = -1; + foundOffset = 0; + + let first = indexInit(); + + if( first.length === 1 ) + { + o.eol = o.eol[ foundTokenIndex ]; + return single(); + } + + if( first.length === 0 ) + { + o.lineIndex = 0; + o.charInterval[ 0 ] = 0; + o.charInterval[ 1 ] = src.length-1; + handleEach(); + return; + } + + while( o.lineIndex !== lastIndex ) + { + + o.lineIndex += 1; + o.nl = nnl; + + o.charInterval[ 1 ] = o.charInterval[ 0 ] - 1; + o.charInterval[ 0 ] = indexOf( first ); + + if( o.charInterval[ 0 ] === -1 ) + { + o.charInterval[ 0 ] = 0; + handleEach(); + break; + } + else + { + nnl = o.eol[ foundTokenIndex ]; + handleEach(); + } + + } + + } + + /* */ + + function indexInit() + { + let first = []; + for( let i = o.eol.length - 1 ; i >= 0 ; i-- ) + { + let offset = src.lastIndexOf( o.eol[ i ] ); + if( offset !== -1 ) + { + offset += o.eol[ i ].length; + first.unshift( offset ); + if( foundOffset <= offset ) + { + foundOffset = offset; + foundTokenIndex = i; + } + } + else + { + o.eol.splice( i, 1 ); + foundTokenIndex -= 1; + } + } + return first; + } + + /* */ + + function indexOf( first ) + { + let left = o.charInterval[ 0 ] - nnl.length - 1; + if( first[ foundTokenIndex ] <= left ) + return first[ foundTokenIndex ]; + foundOffset = -1; + for( let i = first.length - 1; i >= 0 ; i-- ) + { + let offset = first[ i ]; + if( offset > left ) + { + if( left >= 0 ) + offset = src.lastIndexOf( o.eol[ i ], left ); + else + offset = -1; + if( offset === -1 ) + { + tokenDelete( first, i ); + if( first.length === 0 ) + return -1; + } + else + { + offset += o.eol[ i ].length; + first[ i ] = offset; + if( foundOffset <= offset ) + { + foundOffset = offset; + foundTokenIndex = i; + } + } + } + else + { + if( foundOffset <= offset ) + { + foundOffset = offset; + foundTokenIndex = i; + } + } + } + return first[ foundTokenIndex ]; + } + + /* */ + + function tokenDelete( first, i ) + { + o.eol.splice( i, 1 ); + first.splice( i, 1 ); + if( foundTokenIndex > i ) + foundTokenIndex -= 1; + } + + /* */ + + function handleWithoutIntervalWithoutLine() + { + o.onEach( o ); + } + + /* */ + + function handleWithIntervalWithoutLine() + { + if( o.interval && o.interval[ 0 ] > o.lineIndex ) + return; + o.onEach( o ); + } + + /* */ + + function handleWithoutIntervalWithLine() + { + o.line = src.slice( o.charInterval[ 0 ], o.charInterval[ 1 ] - o.nl.length + 1 ); + o.onEach( o ); + } + + /* */ + + function handleWithIntervalWithLine() + { + if( o.interval && o.interval[ 0 ] > o.lineIndex ) + return; + o.line = src.slice( o.charInterval[ 0 ], o.charInterval[ 1 ] - o.nl.length + 1 ); + o.onEach( o ); + } + + /* */ + +}, + "eachRight" : function eachRight( o ) +{ + + if( !_.map.is( o ) ) + { + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( arguments.length === 3 ) + o = { src : arguments[ 0 ], interval : arguments[ 1 ], onEach : arguments[ 2 ] }; + else + o = { src : arguments[ 0 ], onEach : arguments[ 1 ] }; + } + else + { + _.assert( arguments.length === 1 ); + } + + if( o.withLine === undefined ) + o.withLine = true; + + _.assert( _.routine.is( o.onEach ) ); + _.assert( _.str.is( o.src ) ); + + return this._eachRight( o ); +}, + "each" : function eachLeft( o ) +{ + + if( !_.map.is( o ) ) + { + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( arguments.length === 3 ) + o = { src : arguments[ 0 ], interval : arguments[ 1 ], onEach : arguments[ 2 ] }; + else + o = { src : arguments[ 0 ], onEach : arguments[ 1 ] }; + } + else + { + _.assert( arguments.length === 1 ); + } + + if( o.withLine === undefined ) + o.withLine = true; + + _.assert( _.routine.is( o.onEach ) ); + _.assert( _.str.is( o.src ) ); + + return this._eachLeft( o ); +} + }, + "is" : function is( src ) +{ + let result = Object.prototype.toString.call( src ) === '[object String]'; + return result; +}, + "like" : function like( src ) +{ + if( _.str.is( src ) ) + return true; + if( _.regexp.is( src ) ) + return true; + return false; +}, + "defined" : function defined( src ) +{ + if( !src ) + return false; + let result = Object.prototype.toString.call( src ) === '[object String]'; + return result; +}, + "has" : function has( src, ins ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ), () => `Expects string, got ${_.entity.strType( src )}` ); + _.assert( _.regexpLike( ins ), () => `Expects string-like, got ${_.entity.strType( ins )}` ); + + if( _.strIs( ins ) ) + return src.indexOf( ins ) !== -1; + else + return ins.test( src ); + +}, + "short_" : function short_( o ) /* version with binary search cutting */ +{ + + if( arguments.length === 2 ) + o = { src : arguments[ 0 ], widthLimit : arguments[ 1 ] }; + else if( arguments.length === 1 ) + if( _.strIs( o ) ) + o = { src : arguments[ 0 ] }; + + _.routine.options( short_, o ); + + _.assert( _.strIs( o.src ) ); + _.assert( _.number.is( o.widthLimit ) ); + _.assert( o.widthLimit >= 0, 'Option::o.widthLimit must be greater or equal to zero' ); + _.assert + ( + _.number.is( o.heightLimit ) && o.heightLimit >= 0, + 'If provided option::o.heightLimit must be greater or equal to zero' + ); + _.assert( o.delimeter === null || _.strIs( o.delimeter ) || _.bool.likeTrue( o.delimeter )); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( !o.delimeter ) + o.delimeter = ''; + if( !o.heightDelimeter ) + o.heightDelimeter = ''; + if( o.widthLimit === 0 ) + o.widthLimit = Infinity; + if( o.heightLimit === 0 ) + o.heightLimit = Infinity; + + if( _.bool.likeTrue( o.delimeter ) ) + o.delimeter = '...'; + + if( !o.onLength ) + o.onLength = ( src ) => src.length; + + let src = o.src; + + let isOneLine = o.src.indexOf( '\n' ) === -1; + + if( isOneLine && o.onLength( o.src ) < o.widthLimit ) + { + o.changed = false; + o.result = o.src; + + return o; + } + + let options = Object.create( null ); /* width cutting options */ + options.limit = o.widthLimit; + options.delimeter = o.delimeter; + options.onLength = o.onLength; + options.cutting = o.cutting; + + if( isOneLine ) + { + options.src = src; + _.strShortWidth( options ); + + o.result = options.result; + o.changed = options.changed; + + return o; + } + else + { + let splitted = o.src.split( '\n' ); + + let options2 = Object.create( null ); /* height cutting */ + options2.src = splitted; + options2.limit = o.heightLimit; + options2.delimeter = o.heightDelimeter; + options2.cutting = o.heightCutting; + _._strShortHeight( options2 ); + + options.src = options2.result; + + _._strShortWidth( options ); + + let result = options.result.join( '\n' ); + + if( result === o.src ) + o.changed = false; + else if( result !== o.src ) + o.changed = true; + + o.result = result; + + return o; + } +}, + "_shortWidth" : function _shortWidth( o ) +{ + /* + input : array of lines + output : array of lines ( each cutted down to o.limit ) + */ + _.assert( _.arrayIs( o.src ) ); + _.routine.options( _shortWidth, o ); + + let begin = ''; + let end = ''; + let fixLength = o.onLength( o.delimeter ); + + o.changed = false; + + let result = o.src.map( ( el ) => + { + let delimeter = o.delimeter; + fixLength = o.onLength( o.delimeter ); + + if( fixLength === o.limit ) + { + o.changed = true; + return o.delimeter; + } + else if( o.onLength( el ) + fixLength <= o.limit ) /* nothing to cut */ + { + return el; + } + else + { + if( o.onLength( delimeter ) > o.limit ) + { + el = delimeter; + delimeter = ''; + fixLength = 0; + } + + o.changed = true; + + if( o.cutting === 'left' ) + { + return delimeter + cutLeft( el ); + } + else if( o.cutting === 'right' ) + { + return cutRight( el ) + delimeter; + } + else + { + let [ begin, end ] = cutMiddle( el ); + return begin + delimeter + end; + } + } + }); + + o.result = result; + + return o; + + /* - */ + + function cutLeft( src ) + { + let startIndex = 0; + let endIndex = src.length - 1; + let endLength = o.onLength( src ); + let middleIndex = src.length - o.limit - 1; /* optimize default option::onLength */ + + while( endLength + fixLength > o.limit ) /* binary */ + { + [ begin, end ] = splitInTwo( src, middleIndex + 1 ); + endLength = o.onLength( end ); + + startIndex = middleIndex; /* all needed elements are in end */ + middleIndex = Math.floor( ( startIndex + endIndex ) / 2 ); + } + + while( o.onLength( end ) + fixLength <= o.limit ) /* add elements till o.limit is satisfied */ + { + /* + add elements and parts of element that might have been sliced, + example : onLength considers as 1 element substring of the same characters + 'aabbccdd' with o.limit = 2 might return 'cdd', but need 'ccdd' + */ + end = begin[ begin.length - 1 ] + end; + begin = begin.slice( 0, -1 ); + } + + return end.slice( 1 ); + } + + // + + function cutRight( src ) + { + let startIndex = 0; + let endIndex = src.length - 1; + let beginLength = o.onLength( src ); + let middleIndex = o.limit; /* optimize default option::onLength */ + + while( beginLength + fixLength > o.limit ) /* binary */ + { + [ begin, end ] = splitInTwo( src, middleIndex ); + beginLength = o.onLength( begin ); + + endIndex = middleIndex; /* all needed elements are in begin */ + middleIndex = Math.floor( ( startIndex + endIndex ) / 2 ); + } + + while( o.onLength( begin ) + fixLength <= o.limit ) /* add elements till o.limit is satisfied */ + { + /* + add elements and parts of element that might have been sliced, + example : onLength considers as 1 element substring of the same characters + 'aabbccdd' with o.limit = 2 might return 'aab', but need 'aabb' + */ + begin += end[ 0 ]; + end = end.slice( 1 ); + } + + return begin.slice( 0, -1 ); + } + + // + + function cutMiddle( src ) + { + let originalStr = src; + let chunkSize, middleIndexLeft, middleIndexRight; + + if( o.limit % 2 === 0 ) /* optimize default option::onLength */ + { + middleIndexLeft = ( o.limit / 2 ) - 1; + middleIndexRight = ( -o.limit / 2 ) + src.length; + } + else + { + middleIndexLeft = Math.floor( ( o.limit / 2 ) ); + middleIndexRight = Math.ceil( ( -o.limit / 2 ) ) + src.length; + } + + while( o.onLength( src ) + fixLength > o.limit ) /* binary */ + { + if( src.length <= 5 ) /* src.length = 4 || 3 || 2, base case */ + { + let index = Math.floor( src.length / 2 ); + begin = src.slice( 0, index ); + end = src.slice( index+1 ); + } + else /* begin : first 1/3, end : last 1/3 */ + { + begin = src.slice( 0, middleIndexLeft + 1 ); + end = src.slice( middleIndexRight ); + } + + /* delete middle, might delete part of the element, check later when desired length is obtained */ + src = begin + end; + + chunkSize = Math.floor( src.length / 3 ); /* split str into 3 'equal' parts, middle is to be removed */ + middleIndexLeft = chunkSize; + middleIndexRight = chunkSize * 2; + } + + while( o.onLength( begin + end ) + fixLength < o.limit ) /* overcut */ + { + if( o.onLength( begin ) > o.onLength( end ) ) /* shrink middle from the right */ + { + end = originalStr.slice( -end.length - 1 ); + } + else /* shrink middle from the left */ + { + begin = originalStr.slice( 0, begin.length + 1 ); + } + } + + /* + add parts of elements that might have been sliced, + example : onLength considers as 1 element substring of the same characters + 'aabbccdd' with o.limit = 2 might return 'ad', but need 'aadd' + */ + + let beginInitial = o.onLength( begin ); + let endInitial = o.onLength( end ); + + while( o.onLength( begin ) === beginInitial ) /* try to increase begin */ + { + begin = originalStr.slice( 0, begin.length + 1 );; + } + + while( o.onLength( end ) === endInitial ) /* try to increase end */ + { + end = originalStr.slice( -end.length - 1 ); + } + + return [ begin.slice( 0, -1 ), end.slice( 1 ) ]; + } + + // + + function splitInTwo( src, middle ) + { + let begin = src.slice( 0, middle ); + let end = src.slice( middle ); + return [ begin, end ]; + } + +}, + "shortHeight" : function shortHeight( o ) +{ + + if( arguments.length === 2 ) + o = { src : arguments[ 0 ], limit : arguments[ 1 ] }; + else if( arguments.length === 1 ) + if( _.strIs( o ) ) + o = { src : arguments[ 0 ] }; + + _.routine.options( shortHeight, o ); + + _.assert( _.strIs( o.src ) ); + _.assert + ( + ( _.number.is( o.limit ) && o.limit >= 0 ), + 'option::o.limit must be greater or equal to zero' + ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + let originalSrc = o.src; + let splitted = o.src.split( '\n' ); + + if( !o.delimeter ) + o.delimeter = ''; + + o.src = splitted; + + _._strShortHeight( o ); + o.src = originalSrc; + o.result = o.result.join( '\n' ); + + return o; + +}, + "_shortHeight" : function _shortHeight( o ) /* version with binary search cutting */ +{ + /* + input : array of lines + output : array of lines ( cutted down to o.limit ) + */ + + _.assert( _.arrayIs( o.src ) ); + _.routine.options( shortHeight, o ); + + o.changed = false; + + let delimeterLength = o.delimeter === '' ? 0 : 1; + + if( delimeterLength === o.limit ) + { + o.changed = true; + o.result = [ o.delimeter ]; + + return o; + } + + let result = cut( o.src.slice() ); + o.result = result; + + return o; + + /* - */ + + function cut( src ) + { + if( src.length + delimeterLength > o.limit ) + { + o.changed = true; + + if( o.cutting === 'left' ) + { + src = src.slice( - ( o.limit - delimeterLength ) ); + + if( o.delimeter !== '' ) + src.unshift( o.delimeter ); + } + else if( o.cutting === 'right' ) + { + src = src.slice( 0, o.limit - delimeterLength ); + + if( o.delimeter !== '' ) + src.push( o.delimeter ); + } + else + { + let [ left, right ] = handleHeightCuttingCenter( src ); + let result = []; + + result.push( ... left ); + + if( o.delimeter !== '' ) + result.push( o.delimeter ); + + if( right !== undefined ) /* no right when o.limit = 2 and there is a delimeter */ + result.push( ... right ); + + src = result; + + } + } + + return src; + } + + // + + function handleHeightCuttingCenter( src ) + { + let indexLeft, indexRight; + + let limit = o.limit - delimeterLength; + + if( limit === 1 ) + { + return [ src.slice( 0, 1 ) ]; + } + else if( limit % 2 === 0 ) + { + indexLeft = limit / 2; + indexRight = -indexLeft; + } + else + { + indexLeft = Math.floor( ( limit / 2 ) ) + 1; + indexRight = -indexLeft + 1; + } + + let splittedLeft = src.slice( 0, indexLeft ); + let splittedRight = src.slice( indexRight ); + + return [ splittedLeft, splittedRight ]; + } + +}, + "concat" : function concat( srcs, o ) +{ + + o = _.routine.options( concat, o || Object.create( null ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( this.strConcat === concat ); + + if( o.onToStr === null ) + o.onToStr = onToStr; + + let defaultOptionsForToStr = + { + stringWrapper : '', + }; + + o.optionsForToStr = _.props.supplement( o.optionsForToStr, defaultOptionsForToStr ); + o.optionsForToStr.format = o.optionsForToStr.format || 'string.diagnostic'; + + if( _.routine.is( srcs ) ) + srcs = srcs(); + + if( !_.argumentsArray.like( srcs ) ) + srcs = [ srcs ]; + + let result = ''; + if( !srcs.length ) + return result; + + let concatenatePairWithLineDelimeter = o.onPairWithDelimeter ? o.onPairWithDelimeter : concatenateSimple; + + /* */ + + let a = 0; + + while( !result && a < srcs.length ) + { + result = o.onToStr( srcs[ a ], o ); + ++a; + } + + for( ; a < srcs.length ; a++ ) + { + let src = srcs[ a ]; + src = o.onToStr( src, o ); + + result = result.replace( /[^\S\n]\s*$/, '' ); + + if( _.strEnds( result, o.lineDelimter ) || _.strBegins( src, o.lineDelimter ) ) + result = concatenatePairWithLineDelimeter( result, src, o ); + else + result = `${result} ${src.replace( /^\s+/, '' )}`; + } + + /* */ + + if( o.linePrefix || o.linePostfix ) + { + result = result.split( o.lineDelimter ); + result = o.linePrefix + result.join( o.linePostfix + o.lineDelimter + o.linePrefix ) + o.linePostfix; + } + + /* */ + + return result; + + /* */ + + function onToStr( src, op ) + { + return _.entity.exportString( src, op.optionsForToStr ); + } + + /* */ + + function concatenateSimple( src1, src2 ) + { + return src1 + src2; + } +}, + "_beginOf" : function _beginOf( src, begin ) +{ + + // _.assert( _.strIs( src ), 'Expects string' ); + // _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.strIs( begin ) ) + { + if( src.lastIndexOf( begin, 0 ) === 0 ) + return begin; + } + else if( _.regexpIs( begin ) ) + { + let matched = begin.exec( src ); + if( matched && matched.index === 0 ) + return matched[ 0 ]; + } + else _.assert( 0, 'Expects string-like ( string or regexp )' ); + + return undefined; +}, + "_endOf" : function _endOf( src, end ) +{ + + // _.assert( _.strIs( src ), 'Expects string' ); + // _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.strIs( end ) ) + { + if( src.indexOf( end, src.length - end.length ) !== -1 ) + return end; + } + else if( _.regexpIs( end ) ) + { + // let matched = end.exec( src ); + let newEnd = RegExp( end.toString().slice(1, -1) + '$' ); + let matched = newEnd.exec( src ); + + //if( matched && matched.index === 0 ) + if( matched && matched.index + matched[ 0 ].length === src.length ) + return matched[ 0 ]; + } + else _.assert( 0, 'Expects string-like ( string or regexp )' ); + + return undefined; +}, + "begins" : function begins( src, begin ) +{ + + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( _.strIs( begin ) || _.regexpIs( begin ) || _.longIs( begin ), 'Expects string/regexp or array of strings/regexps {-begin-}' ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !_.longIs( begin ) ) + { + let result = _._strBeginOf( src, begin ); + return !( result === undefined ); + // return result === undefined ? false : true; + } + + for( let b = 0, blen = begin.length ; b < blen; b++ ) + { + let result = _._strBeginOf( src, begin[ b ] ); + if( result !== undefined ) + return true; + } + + return false; +}, + "ends" : function ends( src, end ) +{ + + _.assert( _.strIs( src ), () => `Expects argument::src of type::string, but got ${_.entity.strType( src )}` ); + _.assert( _.strIs( end ) || _.regexpIs( end ) || _.longIs( end ), 'Expects string/regexp or array of strings/regexps {-end-}' ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !_.longIs( end ) ) + { + let result = _._strEndOf( src, end ); + return !( result === undefined ); + } + + for( let b = 0, blen = end.length ; b < blen; b++ ) + { + let result = _._strEndOf( src, end[ b ] ); + if( result !== undefined ) + return true; + } + + return false; +}, + "beginOf" : function beginOf( src, begin ) +{ + + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( _.strIs( begin ) || _.regexpIs( begin ) || _.longIs( begin ), 'Expects string/regexp or array of strings/regexps {-begin-}' ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !_.longIs( begin ) ) + { + let result = _._strBeginOf( src, begin ); + return result; + } + + for( let b = 0, blen = begin.length ; b < blen ; b++ ) + { + let result = _._strBeginOf( src, begin[ b ] ); + if( result !== undefined ) + return result; + } + + return undefined; +}, + "endOf" : function endOf( src, end ) +{ + + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( _.strIs( end ) || _.regexpIs( end ) || _.longIs( end ), 'Expects string/regexp or array of strings/regexps {-end-}' ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !_.longIs( end ) ) + { + let result = _._strEndOf( src, end ); + return result; + } + + for( let b = 0, blen = end.length ; b < blen; b++ ) + { + let result = _._strEndOf( src, end[ b ] ); + if( result !== undefined ) + return result; + } + + return undefined; +}, + "removeBegin" : function removeBegin( src, begin ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.longIs( src ) || _.strIs( src ), 'Expects string or array of strings {-src-}' ); + _.assert( _.longIs( begin ) || _.strIs( begin ) || _.regexpIs( begin ), 'Expects string/regexp or array of strings/regexps {-begin-}' ); + + let result = []; + let srcIsArray = _.longIs( src ); + + if( _.strIs( src ) && !_.longIs( begin ) ) + return _._strRemovedBegin( src, begin ); + + src = _.array.as( src ); + begin = _.array.as( begin ); + for( let s = 0, slen = src.length ; s < slen ; s++ ) + { + let beginOf = undefined; + let src1 = src[ s ] + for( let b = 0, blen = begin.length ; b < blen ; b++ ) + { + beginOf = _._strBeginOf( src1, begin[ b ] ); + if( beginOf !== undefined ) + break; + } + if( beginOf !== undefined ) + src1 = src1.substr( beginOf.length, src1.length ); + result[ s ] = src1; + } + + if( !srcIsArray ) + return result[ 0 ]; + + return result; +}, + "removeEnd" : function removeEnd( src, end ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.longIs( src ) || _.strIs( src ), 'Expects string or array of strings {-src-}' ); + _.assert( _.longIs( end ) || _.strIs( end ) || _.regexpIs( end ), 'Expects string/regexp or array of strings/regexps {-end-}' ); + + let result = []; + let srcIsArray = _.longIs( src ); + + if( _.strIs( src ) && !_.longIs( end ) ) + return _._strRemovedEnd( src, end ); + + src = _.array.as( src ); + end = _.array.as( end ); + + for( let s = 0, slen = src.length ; s < slen ; s++ ) + { + let endOf = undefined; + let src1 = src[ s ] + for( let b = 0, blen = end.length ; b < blen ; b++ ) + { + endOf = _._strEndOf( src1, end[ b ] ); + if( endOf !== undefined ) + break; + } + if( endOf !== undefined ) + src1 = src1.substr( 0, src1.length - endOf.length ); + result[ s ] = src1; + } + + if( !srcIsArray ) + return result[ 0 ]; + + return result; +}, + "remove" : function remove( srcStr, insStr ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( srcStr ), 'Expects string {-src-}' ); + _.assert( _.strIs( insStr ) || _.regexpIs( insStr ), 'Expects string/regexp {-begin-}' ); + + let result = srcStr; + + result = result.replace( insStr, '' ); + + return result; +}, + "_exportStringDiagnosticShallow" : function _exportStringDiagnosticShallow( src, o ) +{ + return src; +}, + "exportStringDiagnosticShallow" : function exportStringDiagnosticShallow( src, o ) +{ + let result; + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects 1 or 2 arguments' ); + _.assert( this.like( src ) ); + return this._exportStringDiagnosticShallow( ... arguments ); +}, + "_exportStringCodeShallow" : function _exportStringCodeShallow( src, o ) +{ + return `'${src}'`; +}, + "exportStringCodeShallow" : function exportStringCodeShallow( src, o ) +{ + let result; + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects 1 or 2 arguments' ); + _.assert( this.like( src ) ); + return this._exportStringCodeShallow( ... arguments ); +}, + "exportString" : function exportStringDiagnosticShallow( src, o ) +{ + let result; + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects 1 or 2 arguments' ); + _.assert( this.like( src ) ); + return this._exportStringDiagnosticShallow( ... arguments ); +}, + "_identicalShallow" : function _identicalShallow( src1, src2 ) +{ + return src1 === src2; +}, + "identicalShallow" : function identicalShallow( src1, src2, accuracy ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( !this.is( src1 ) ) + return false; + if( !this.is( src2 ) ) + return false; + return this._identicalShallow( ... arguments ); +}, + "identical" : function identicalShallow( src1, src2, accuracy ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( !this.is( src1 ) ) + return false; + if( !this.is( src2 ) ) + return false; + return this._identicalShallow( ... arguments ); +}, + "_equivalentShallow" : function _equivalentShallow( src1, src2 ) +{ + let strIs1 = _.strIs( src1 ); + let strIs2 = _.strIs( src2 ); + + if( !strIs1 && strIs2 ) + return this._equivalentShallow( src2, src1 ); + + if( strIs1 && strIs2 ) + { + if( src1 === src2 ) + return true; + return _.str.lines.strip( src1 ) === _.str.lines.strip( src2 ); + } + else if( strIs1 ) + { + _.assert( !!src2.exec ); + let matched = src2.exec( src1 ); + if( !matched ) + return false; + if( matched[ 0 ].length !== src1.length ) + return false; + return true; + } + else + { + return _.regexpIdentical( src1, src2 ); + } + + return false; +}, + "equivalentShallow" : function equivalentShallow( src1, src2, accuracy ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( !_.regexp.like( src1 ) ) + return false; + if( !_.regexp.like( src2 ) ) + return false; + return _.str._equivalentShallow( ... arguments ); +}, + "equivalent" : function equivalentShallow( src1, src2, accuracy ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( !_.regexp.like( src1 ) ) + return false; + if( !_.regexp.like( src2 ) ) + return false; + return _.str._equivalentShallow( ... arguments ); +}, + "prependOnce" : function prependOnce( src, begin ) +{ + _.assert( _.strIs( src ) && _.strIs( begin ), 'Expects {-src-} and {-begin-} as strings' ); + if( src.lastIndexOf( begin, 0 ) === 0 ) + return src; + else + return begin + src; +}, + "appendOnce" : function appendOnce( src, end ) +{ + _.assert( _.strIs( src ) && _.strIs( end ), 'Expects {-src-} and {-end-} as strings' ); + if( src.indexOf( end, src.length - end.length ) === -1 ) + return src + end; + else + return src; +}, + "parseType" : function parseType( src ) +{ + /* + - 'string' + - '5' + - '5n' + - 'null' + - 'undefined' + - 'Escape( 1 )' + - '{- Symbol undefined -}' + - '{- routine name -}' + - '{- routine.anonymous -}' + - '{- Map -}' + - '{- Map name -}' + - '{- Map with 9 elements -}' + - '{- Map.polluted with 9 elements -}' + - '{- Map name with 9 elements -}' + */ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ), 'Expects string' ); + + if( !( /^{- .+ -}$/g.test( src ) ) ) + return Object.create( null ); + + src = src.slice( 3, -3 ); + + return _.str._parseType( src ); + +}, + "_parseType" : function _parseType( src ) +{ + /* + + {- with with 2 elements -} 4 + {- with name with 2 elements -} 5 + {- with.with with with 2 elements -} 5 + + */ + _.assert( _.strIs( src ), 'Expects string' ); + + let o = + { + type : '', + traits : [], + } + + let splitted = src.split( ' ' ); + let type = splitted[ 0 ]; + let length; + + if( splitted.length === 2 ) /* with name & no length */ + { + o.name = splitted[ 1 ]; + } + else if( splitted.length === 4 ) /* without name & with length */ + { + length = +splitted[ 2 ]; + } + else if( splitted.length === 5 ) /* with name & with length */ + { + o.name = splitted[ 1 ]; + length = +splitted[ 3 ]; + } + + length = isNaN( length ) ? null : length; + + if( type.indexOf( '.' ) === -1 ) + { + o.type = type; + } + else + { + let [ t, ... traits ] = type.split( '.' ); + o.type = t; + o.traits = traits; + } + + if( length !== null ) + o.length = length; + + return o; + +}, + "quote" : function quote( o ) +{ + + if( !_.mapIs( o ) ) + o = { src : arguments[ 0 ], quote : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + if( o.quote === undefined || o.quote === null ) + o.quote = quote.defaults.quote; + _.map.assertHasOnly( o, quote.defaults ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( _.arrayIs( o.src ) ) + { + let result = []; + for( let s = 0 ; s < o.src.length ; s++ ) + result.push( _.strQuote({ src : o.src[ s ], quote : o.quote }) ); + return result; + } + + let src = o.src; + + if( !_.primitive.is( src ) ) + src = _.entity.exportString( src ); + + _.assert( _.primitive.is( src ) ); + + let result = o.quote + String( src ) + o.quote; + + return result; +}, + "unquote" : function unquote( o ) +{ + + if( !_.mapIs( o ) ) + o = { src : arguments[ 0 ], quote : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + if( o.quote === undefined || o.quote === null ) + o.quote = unquote.defaults.quote; + _.map.assertHasOnly( o, unquote.defaults ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( _.arrayIs( o.src ) ) + { + let result = []; + for( let s = 0 ; s < o.src.length ; s++ ) + result.push( _.strUnquote({ src : o.src[ s ], quote : o.quote }) ); + return result; + } + + let result = o.src; + let isolated = _.strIsolateInside( result, o.quote ); + if( isolated[ 0 ] === '' && isolated[ 4 ] === '' ) + result = isolated[ 2 ]; + + return result; +}, + "quotePairsNormalize" : function quotePairsNormalize( quote ) +{ + + if( ( _.bool.like( quote ) && quote ) ) + quote = quoteAnalyze.defaults.quote; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( quote ) || _.arrayIs( quote ) ); + + quote = _.array.as( quote ); + for( let q = 0 ; q < quote.length ; q++ ) + { + let quotingPair = quote[ q ]; + _.assert( _.pair.is( quotingPair ) || _.strIs( quotingPair ) ); + if( _.strIs( quotingPair ) ) + quotingPair = quote[ q ] = [ quotingPair, quotingPair ]; + _.assert( _.strIs( quotingPair[ 0 ] ) && _.strIs( quotingPair[ 1 ] ) ); + } + + return quote; +}, + "quoteAnalyze" : function quoteAnalyze( o ) +{ + let i = -1; + let result = Object.create( null ); + result.ranges = []; + result.quotes = []; + + if( !_.mapIs( o ) ) + o = { src : arguments[ 0 ], quote : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + if( o.quote === undefined || o.quote === null ) + o.quote = quoteAnalyze.defaults.quote; + _.map.assertHasOnly( o, quoteAnalyze.defaults ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + o.quote = _.strQuotePairsNormalize( o.quote ); + let maxQuoteLength = 0; + for( let q = 0 ; q < o.quote.length ; q++ ) + { + let quotingPair = o.quote[ q ]; + maxQuoteLength = Math.max( maxQuoteLength, quotingPair[ 0 ].length, quotingPair[ 1 ].length ); + } + + let isEqual = maxQuoteLength === 1 ? isEqualChar : isEqualString; + let inRange = false + do + { + while( i < o.src.length ) + { + i += 1; + + if( inRange ) + { + if( isEqual( inRange ) ) + { + result.ranges.push( i ); + inRange = false; + } + continue; + } + + for( let q = 0 ; q < o.quote.length ; q++ ) + { + let quotingPair = o.quote[ q ]; + if( isEqual( quotingPair[ 0 ] ) ) + { + result.quotes.push( quotingPair[ 0 ] ); + result.ranges.push( i ); + inRange = quotingPair[ 1 ]; + break; + } + } + } + + if( inRange ) + { + result.quotes.pop(); + i = result.ranges.pop()+1; + inRange = false; + } + + } + while( i < o.src.length ); + + return result; + + function isEqualChar( quote ) + { + _.assert( o.src.length >= i ); + if( o.src[ i ] === quote ) + return true; + return false; + } + + function isEqualString( quote ) + { + if( i+quote.length > o.src.length ) + return false; + let subStr = o.src.substring( i, i+quote.length ); + if( subStr === quote ) + return true; + return false; + } + +}, + "_leftSingle_" : function _leftSingle_( src, ins, cinterval ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( _.strIs( src ) ); + + if( _.number.is( cinterval ) ) + cinterval = [ cinterval, src.length - 1 ]; + else if( cinterval === undefined ) + cinterval = [ 0, src.length - 1 ]; + + cinterval[ 0 ] = cinterval[ 0 ] === undefined ? 0 : cinterval[ 0 ]; + cinterval[ 1 ] = cinterval[ 1 ] === undefined ? src.length - 1 : cinterval[ 1 ]; + + if( cinterval[ 0 ] < 0 ) + cinterval[ 0 ] = src.length + cinterval[ 0 ]; + if( cinterval[ 1 ] < -1 ) + cinterval[ 1 ] = src.length + cinterval[ 1 ]; + + _.assert( _.intervalIs( cinterval ) ); + _.assert( 0 <= cinterval[ 0 ] && cinterval[ 0 ] <= src.length ); + _.assert( -1 <= cinterval[ 1 ] && cinterval[ 1 ] <= src.length - 1 ); + + let result = Object.create( null ); + result.index = src.length; + result.instanceIndex = -1; + result.entry = undefined; + + let src1 = src.substring( cinterval[ 0 ], cinterval[ 1 ] + 1 ); + + ins = _.array.as( ins ); + + for( let k = 0 ; k < ins.length ; k++ ) + { + let entry = ins[ k ]; + if( _.strIs( entry ) ) + { + let found = src1.indexOf( entry ); + if( found >= 0 && ( found < result.index || result.entry === undefined ) ) + { + result.instanceIndex = k; + result.index = found; + result.entry = entry; + } + } + else if( _.regexpIs( entry ) ) + { + let found = src1.match( entry ); + if( found && ( found.index < result.index || result.entry === undefined ) ) + { + result.instanceIndex = k; + result.index = found.index; + result.entry = found[ 0 ]; + } + } + else _.assert( 0, 'Expects string-like ( string or regexp )' ); + } + + if( cinterval[ 0 ] !== 0 && result.index !== src.length ) + result.index += cinterval[ 0 ]; + + return result; +}, + "left_" : function left_( src, ins, cinterval ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( _.argumentsArray.like( src ) ) + { + let result = []; + for( let s = 0 ; s < src.length ; s++ ) + result[ s ] = _._strLeftSingle_( src[ s ], ins, cinterval ); + return result; + } + else + { + return _._strLeftSingle_( src, ins, cinterval ); + } + +}, + "right_" : function right_( src, ins, cinterval ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( _.argumentsArray.like( src ) ) + { + let result = []; + for( let s = 0 ; s < src.length ; s++ ) + result[ s ] = _._strRightSingle_( src[ s ], ins, cinterval ); + return result; + } + else + { + return _._strRightSingle_( src, ins, cinterval ); + } + +}, + "insideOf" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "insideOf_" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "outsideOf" : function outsideOf( src, begin, end ) +{ + + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + + let beginOf, endOf; + + beginOf = _.strBeginOf( src, begin ); + if( beginOf === undefined ) + return undefined; + + endOf = _.strEndOf( src, end ); + if( endOf === undefined ) + return undefined; + + let result = beginOf + endOf; + + return result; +}, + "_removedBegin" : function _removedBegin( src, begin ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + + let result = src; + let beginOf = _._strBeginOf( result, begin ); + if( beginOf !== undefined ) + result = result.substr( beginOf.length, result.length ); + + return result; +}, + "_removedEnd" : function _removedEnd( src, end ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + + let result = src; + let endOf = _._strEndOf( result, end ); + if( endOf !== undefined ) + result = result.substr( 0, result.length - endOf.length ); + + return result; +}, + "replaceBegin" : function replaceBegin( src, begin, ins ) +{ + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + _.assert( _.strIs( ins ) || _.longIs( ins ), 'Expects {-ins-} as string/array of strings' ); + if( _.longIs( begin ) && _.longIs( ins ) ) + _.assert( begin.length === ins.length ); + + begin = _.array.as( begin ); + let result = _.array.as( src ).slice(); + + for( let k = 0, srcLength = result.length; k < srcLength; k++ ) + for( let j = 0, beginLength = begin.length; j < beginLength; j++ ) + if( _.strBegins( result[ k ], begin[ j ] ) ) + { + let prefix = _.longIs( ins ) ? ins[ j ] : ins; + _.assert( _.strIs( prefix ) ); + result[ k ] = prefix + _.strRemoveBegin( result[ k ], begin[ j ] ); + break; + } + + if( result.length === 1 && _.strIs( src ) ) + return result[ 0 ]; + + return result; +}, + "replaceEnd" : function replaceEnd( src, end, ins ) +{ + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + _.assert( _.strIs( ins ) || _.longIs( ins ), 'Expects {-ins-} as string/array of strings' ); + if( _.longIs( end ) && _.longIs( ins ) ) + _.assert( end.length === ins.length ); + + end = _.array.as( end ); + let result = _.array.as( src ).slice(); + + for( let k = 0, srcLength = result.length; k < srcLength; k++ ) + for( let j = 0, endLength = end.length; j < endLength; j++ ) + if( _.strEnds( result[ k ], end[ j ] ) ) + { + let postfix = _.longIs( ins ) ? ins[ j ] : ins; + _.assert( _.strIs( postfix ) ); + result[ k ] = _.strRemoveEnd( result[ k ], end[ j ] ) + postfix; + break; + } + + if( result.length === 1 && _.strIs( src ) ) + return result[ 0 ]; + + return result; +}, + "replace" : function replace( src, ins, sub ) +{ + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + _.assert( _.strsAreAll( sub ), 'Expects {-sub-} as string/array of strings' ); + + if( _.longIs( ins ) && _.longIs( sub ) ) + _.assert( ins.length === sub.length ); + + ins = _.array.as( ins ); + for( let i = 0 ; i < ins.length ; i++ ) + _.assert( ins[ i ] !== '', '{-ins-} should be a string with length' ); + + /* */ + + let result = _.array.as( src ).slice(); + + for( let i = 0 ; i < result.length ; i++ ) + { + result[ i ] = _.strSplit + ({ + src : result[ i ], + delimeter : ins, + quoting : 0, + stripping : 0, + preservingEmpty : 1, + preservingDelimeters : 1, + onDelimeter : ( e, k ) => _.strIs( sub ) ? sub : sub[ k ], + }); + result[ i ] = result[ i ].join( '' ); + } + + if( result.length === 1 && _.strIs( src ) ) + return result[ 0 ]; + + return result; +}, + "strip" : function strip( o ) +{ + + if( _.strIs( o ) || _.arrayIs( o ) ) + o = { src : o }; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options( strip, o ); + + o.stripper = stripperNormalize(); + let stripRoutine = _.regexpIs( o.stripper ) ? singleStripByRegexp : singleStripByArrayOfStrings; + + if( _.arrayIs( o.src ) ) + { + _.assert( _.strsAreAll( o.src ), 'Expects strings {-o.srs-}' ); + + let result = []; + for( let i = 0 ; i < o.src.length ; i++ ) + result[ i ] = stripRoutine( o.src[ i ] ); + return result; + } + + _.assert( _.strIs( o.src ) ); + return stripRoutine( o.src ); + + /* */ + + function stripperNormalize() + { + let stripper = o.stripper; + if( _.bool.likeTrue( o.stripper ) ) + { + stripper = strip.defaults.stripper; + } + else if( _.arrayIs( o.stripper ) ) + { + _.assert( _.strsAreAll( o.stripper ), 'Expects characters in container {-o.stripper-}' ); + } + else if( _.strIs( o.stripper ) ) + { + stripper = _.regexpEscape( o.stripper ); + stripper = new RegExp( stripper, 'g' ); + } + else if( !_.regexpIs( o.stripper ) ) + { + _.assert( 0, 'Unexpected type of {-o.stripper-}. Expects either a String, an Array or a Regexp {-o.stripper-}' ); + } + return stripper; + } + + /* */ + + function singleStripByRegexp( src ) + { + return src.replace( o.stripper, '' ); + } + + /* */ + + function singleStripByArrayOfStrings( src ) + { + let begin = 0; + for( ; begin < src.length ; begin++ ) + if( o.stripper.indexOf( src[ begin ] ) === -1 ) + break; + + let end = src.length-1; + for( ; end >= 0 ; end-- ) + if( o.stripper.indexOf( src[ end ] ) === -1 ) + break; + + if( begin >= end ) + return ''; + + return src.substring( begin, end + 1 ); + } + +}, + "stripLeft" : function stripLeft( o ) +{ + + if( _.strIs( o ) || _.arrayIs( o ) ) + o = { src : o }; + + _.routine.options( stripLeft, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + return _.strStrip( o ); +}, + "stripRight" : function stripRight( o ) +{ + + if( _.strIs( o ) || _.arrayIs( o ) ) + o = { src : o }; + + _.routine.options( stripRight, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + return _.strStrip( o ); +}, + "_removeAllSpaces" : function _removeAllSpaces( src, sub ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( src ) ); + + if( sub === undefined ) + sub = ''; + + return src.replace( /\s/g, sub ); +}, + "_stripEmptyLines" : function _stripEmptyLines( srcStr ) +{ + let result = ''; + let lines = srcStr.split( '\n' ); + + _.assert( _.strIs( srcStr ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + for( let l = 0; l < lines.length; l += 1 ) + { + let line = lines[ l ]; + + if( !_.strStrip( line ) ) + continue; + + result += line + '\n'; + } + + result = result.substring( 0, result.length - 1 ); + return result; +}, + "splitsCoupledGroup" : function splitsCoupledGroup( o ) +{ + + if( _.arrayIs( o ) ) + o = { splits : o } + + o = _.routine.options( splitsCoupledGroup, o ); + + o.prefix = _.array.as( o.prefix ); + o.postfix = _.array.as( o.postfix ); + + _.assert( arguments.length === 1 ); + _.assert( _.regexpsLikeAll( o.prefix ) ); + _.assert( _.regexpsLikeAll( o.postfix ) ); + + let level = 0; + let begins = []; + for( let i = 0 ; i < o.splits.length ; i++ ) + { + let element = o.splits[ i ]; + + if( _.regexpsTestAny( o.prefix, element ) ) + { + begins.push( i ); + } + else if( _.regexpsTestAny( o.postfix, element ) ) + { + if( begins.length === 0 && !o.allowingUncoupledPostfix ) + throw _.err( `"${ element }" does not have complementing openning\n` ); + + if( begins.length === 0 ) + continue; + + let begin = begins.pop(); + let end = i; + let l = end-begin; + + _.assert( l >= 0 ) + let newElement = o.splits.splice( begin, l+1, null ); + o.splits[ begin ] = newElement; + + i -= l; + } + + } + + if( begins.length && !o.allowingUncoupledPrefix ) + { + debugger; + throw _.err( `"${ begins[ begins.length-1 ] }" does not have complementing closing\n` ); + } + + return o.splits; +}, + "splitsUngroupedJoin" : function splitsUngroupedJoin( o ) +{ + + if( _.arrayIs( o ) ) + o = { splits : o } + o = _.routine.options( splitsUngroupedJoin, o ); + + let s = o.splits.length-1; + let l = null; + + while( s >= 0 ) + { + let split = o.splits[ s ]; + + if( _.strIs( split ) ) + { + if( l === null ) + l = s; + } + else if( l !== null ) + { + join(); + } + + s -= 1; + } + + if( l !== null ) + join(); + + return o.splits; + + /* */ + + function join() + { + if( s+1 < l ) + { + let element = o.splits.slice( s+1, l+1 ).join( '' ); + o.splits.splice( s+1, l+1, element ); + } + l = null; + } + +}, + "splitsQuotedRejoin" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "splitsDropDelimeters" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "splitsStrip" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "splitsDropEmpty" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "splitFast" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "split" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "splitNonPreserving" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "splitInlined" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "splitInlinedStereo_" : function splitInlinedStereo_( o ) +{ + /* + New delimeter. + was : 'this #background:red#is#background:default# text and is not'. + is : 'this ❮background:red❯is❮background:default❯ text and is not'. + */ + + if( _.strIs( o ) ) + o = { src : o }; + o.quotingPrefixes = o.quotingPrefixes || [ '"' ]; + o.quotingPostfixes = o.quotingPostfixes || [ '"' ]; + + _.assert( this === _ ); + _.assert( _.strIs( o.src ) ); + _.assert( _.object.isBasic( o ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options( splitInlinedStereo_, o ); + + let isDefaultOnInlined = true; + + if( o.onInlined === null ) + { + o.onInlined = ( e ) => [ e ]; + } + else + { + _.assert( _.routine.is( o.onInlined ), 'Expects a routine as option::onInlined' ); + isDefaultOnInlined = false; + } + + /* Trivial cases */ + let end = handleTrivial(); + if( end !== false ) + return end; + + let replacementForPrefix = '\u{20330}'; + let isReplacedPrefix = false; + let splitOptions = _.mapOnly_( null, o, split.defaults ); + splitOptions.preservingDelimeters = 1; /* for distinguishing between inlined and ordinary */ + splitOptions.delimeter = o.prefix === o.postfix ? o.prefix : [ o.prefix, o.postfix ]; + splitOptions.stripping = 0; + splitOptions.preservingEmpty = 1; + + let result = _.strSplit( splitOptions ); /* array with separated ordinary, inlined and delimeters */ + result = preprocessBeforeJoin( result ); + + result = _.strSplitsQuotedRejoin + ({ + splits : result, + delimeter : [ o.prefix, o.postfix ], + quoting : 1, + quotingPrefixes : [ o.prefix ], + quotingPostfixes : [ o.postfix ], + preservingQuoting : o.preservingDelimeters, + inliningQuoting : 0, + onQuoting : o.preservingEmpty ? escapeInlined( o.onInlined ) : o.onInlined + }); + + if( o.preservingEmpty ) + handlePreservingEmpty(); + + unescape(); + + if( o.preservingDelimeters && !o.inliningDelimeters && isDefaultOnInlined ) /* for default onInlined */ + splitInlined(); + + if( isReplacedPrefix ) + result = result.map( ( el ) => + { + if( _.strIs( el ) ) + return el.replace( replacementForPrefix, o.prefix ) + else + return el; + }); + + return result; + + /* - */ + + function handleTrivial() + { + let delimLeftPosition = o.src.indexOf( o.prefix ); + let delimRightPosition = o.src.indexOf( o.postfix ); + + if( delimLeftPosition === -1 || delimRightPosition === -1 ) + { + if( o.preservingOrdinary ) + return [ o.src ]; + else + return []; + } + + if( !o.preservingOrdinary && !o.preservingInlined ) + return []; + + let splitted = o.src.split( o.prefix ); + + if( splitted.length === 1 ) + { + if( o.preservingOrdinary ) + return [ o.src ]; + else + return []; + } + + return false; + } + + /* */ + + function splitInlined() + { + result = result.map( ( el ) => + { + if( _.arrayIs( el ) ) + el = [ o.prefix, el[ 0 ].slice( 1, -1 ), o.postfix ]; + + return el; + }); + } + + /* */ + + function escapeInlined( func ) + { + return function ( el ) + { + return _.escape.wrap( func( el ) ); + } + } + + /* */ + + function preprocessBeforeJoin( array ) + { + let ordinary = ''; + let result = [] + for( let i = 0; i < array.length; i++ ) + { + /* + [ '', '❮', ' ', '❮', ' ', '❮', 'inline1', '❯', ' ', '❯', ' inline2' ] + into + [ '❮ ❮ ', '❮', 'inline1', '❯', ' ❯ inline2' ] + */ + if( array[ i ] === o.prefix ) + { + if( array[ i + 2 ] === o.postfix ) + { + /* push concatenated ordinary string */ + pushOrdinary( result, ordinary ); + /* push inlined : '❮', 'inline1', '❯' */ + if( o.preservingInlined ) + { + result.push( array[ i ] ); + result.push( o.stripping ? array[ i+1 ].trim() : array[ i+1 ] ); + result.push( array[ i+2 ] ); + } + i += 2; + ordinary = ''; + } + else + { + ordinary += array[ i ]; + } + } + else + { + ordinary += array[ i ]; + } + } + + pushOrdinary( result, ordinary ); + + return result; + } + + /* */ + + function pushOrdinary( result, ordinary ) + { + if( o.preservingOrdinary && ordinary ) + { + if( ordinary === o.prefix ) + { + result.push( replacementForPrefix ); + isReplacedPrefix = true; + } + else + { + ordinary = o.stripping ? ordinary.trim() : ordinary; + if( o.onOrdinary ) + { + let ordinary1 = o.onOrdinary( ordinary ); + ordinary = ordinary1 ? ordinary1 : ordinary; + } + + result.push( ordinary ); + } + } + } + + /* */ + + function handlePreservingEmpty() + { + if( _.escape.is( result[ 0 ] ) ) + { + result.unshift( '' ); + } + if( _.escape.is( result[ result.length-1 ] ) ) + { + result.push( '' ); + } + let len = result.length; + for( let i = 0; i < len; i++ ) + { + if( _.escape.is( result[ i ] ) ) + if( _.escape.is( result[ i + 1 ] ) ) + { + result.splice( i + 1, 0, '' ); + len++; + } + } + } + + /* */ + + function unescape() + { + for( let i = 0; i < result.length; i++ ) + { + if( _.escape.is( result[ i ] ) ) + result[ i ] = _.escape.unwrap( result[ i ] ); + } + } + +}, + "from" : function from( src ) +{ + + if( src === null ) + return src; + if( src === undefined ) + return src; + + if( _.primitive.is( src ) ) + return String( src ); + + if( _.bufferAnyIs( src ) ) + return _.bufferToStr( src ); + + _.assert( _.strIs( src ) ); + return src; +}, + "isolate" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "isolateLeftOrNone" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "isolateLeftOrAll" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "isolateRightOrNone" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "isolateRightOrAll" : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + }, + "isolateInsideSignle" : function isolateInsideSignle( src, begin, end ) +{ + + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( arguments.length === 2 || arguments.length === 3 ); + let b, e; + + if( end === undefined ) + { + let pairs = arguments[ 1 ]; + _.assert( _.strIs( pairs ) || _.arrayIs( pairs ) ); + pairs = _.strQuotePairsNormalize( pairs ); + + let l = 0; + let begin = []; + for( let q = 0 ; q < pairs.length ; q++ ) + { + let quotingPair = pairs[ q ]; + begin.push( quotingPair[ 0 ] ); + } + + do + { + + // b = _.strLeft( src, begin, [ l, src.length ] ); + b = _.strLeft_( src, begin, [ l, src.length-1 ] ); + + if( b.entry === undefined ) + return notFound(); + + _.assert( _.number.is( b.instanceIndex ) ); + let end = pairs[ b.instanceIndex ][ 1 ]; + + // e = _.strRight( src, end, Math.min( b.index+1, src.length ) ); + // e = _.strRight_( src, end, Math.min( b.index, src.length-1 ) ); /* Dmytro : if cinterval is a Number, it is defined first index, not last */ + e = _.strRight_( src, end, Math.min( b.index, src.length ) ); + + if( e.entry === undefined ) + l = b.index+1; + else + break; + // return notFound(); + + } + while( l < src.length ); + + if( e.entry === undefined ) + return notFound(); + + } + else + { + + // b = _.strLeft( src, begin ); + b = _.strLeft_( src, begin ); + + if( b.entry === undefined ) + return notFound(); + + // e = _.strRight( src, end, Math.min( b.index+1, src.length ) ); + // e = _.strRight_( src, end, Math.min( b.index, src.length-1 ) ); /* Dmytro : if cinterval is a Number, it is defined first index, not last */ + e = _.strRight_( src, end, Math.min( b.index, src.length ) ); + + if( e.entry === undefined ) + return notFound(); + + } + + if( e.index < b.index + b.entry.length ) + return notFound(); + + let result = + [ + src.substring( 0, b.index ), + b.entry, + src.substring( b.index + b.entry.length, e.index ), + e.entry, + src.substring( e.index + e.entry.length, src.length ) + ]; + + return result; + + function notFound() + { + // return [ '', '', src, '', '' ]; + return [ '', undefined, src, undefined, '' ]; + } +}, + "isolateInside" : function isolateInside( src, begin, end ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( _.argumentsArray.like( src ) ) + { + let result = []; + for( let s = 0 ; s < src.length ; s++ ) + result[ s ] = _.strIsolateInsideSignle( src[ s ], begin, end ); + return result; + } + else + { + return _.strIsolateInsideSignle( src, begin, end ); + } + +} +}; + +// + + + + + + _.entity._exportStringIsVisibleElement = function _exportStringIsVisibleElement( src, o ) +{ + + var isPrimitive = _.primitiveIs( src ); + var isArray = _.longIs( src ); + var isObject = !isArray && _.objectLike( src ); + var type = _.entity.strTypeSecondary( src ); + + /* */ + + // if( !isPrimitive && 'exportString' in src && _.routineIs( src.exportString ) && !src.exportString.notMethod ) + if( !isPrimitive && 'exportString' in src && _.routineIs( src.exportString ) && _.instanceIs( src ) ) + { + if( isObject && o.noObject ) + return false; + if( isArray && o.noArray ) + return false; + + return true; + } + else if( _.vectorAdapterIs( src ) ) + { + if( o.noRow ) + return false; + return true; + } + else if( _.errIs( src ) ) + { + if( o.noError ) + return false; + return true; + } + else if( type === 'Function' ) + { + if( o.noRoutine ) + return false; + return true; + } + else if( type === 'Number' ) + { + if( o.noNumber || o.noAtomic ) + return false; + return true; + } + else if( type === 'String' ) + { + if( o.noString || o.noAtomic ) + return false; + return true; + } + else if( type === 'Date' ) + { + if( o.noDate ) + return false; + return true; + } + else if( isArray ) + { + if( o.noArray ) + return false; + + if( !o.wrap ) + { + src = _.entity._exportStringFromArrayFiltered( src, o ); + if( !src.length ) + return false; + } + + return true; + } + else if( isObject ) + { + if( o.noObject ) + return false; + + if( !o.wrap ) + { + var keys = _.entity._exportStringFromObjectKeysFiltered( src, o ); + if( !keys.length ) + return false; + } + + return true; + } + else if( !isPrimitive && _.routineIs( src.toString ) ) + { + if( isObject && o.noObject ) + return false; + if( isArray && o.noArray ) + return false; + return true; + } + else + { + if( o.noAtomic ) + return false; + if( o.noUndefines && src === undefined ) + return false; + return true; + } + +} + +// + + + _.entity._exportStringIsSimpleElement = function _exportStringIsSimpleElement( element, o ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.object.isBasic( o ) || o === undefined, 'Expects map {-o-}' ); + + if( _.strIs( element ) ) + { + if( element.length > 40 ) + return false; + if( !o.escaping ) + return element.indexOf( '\n' ) === -1; + return true; + } + else if( element && !_.object.isBasic( element ) && _.numberIs( element.length ) ) + return !element.length; + else if( _.object.isBasic( element ) || _.objectLike( element ) ) + return !_.entity.lengthOf( element ); + else + return _.primitiveIs( element ); + +} + +// + + + _.entity._exportStringFromStr = function _exportStringFromStr( src, o ) +{ + var result = ''; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( _.object.isBasic( o ) || o === undefined, 'Expects map {-o-}' ); + + if( o.stringWrapper === undefined ) + o.stringWrapper = `\'`; + + var q = o.stringWrapper; + + if( o.widthLimit ) + { + + if( o.shortDelimeter === undefined || o.shortDelimeter === null ) + o.shortDelimeter = _.strShort_.defaults.delimeter || '...'; + + result = _.strShort_ + ({ + src : _.strEscape( src ), + widthLimit : o.widthLimit - q.length*2, + heightLimit : o.heightLimit || 0, + delimeter : o.shortDelimeter, + }).result; + + // if( result.length > o.widthLimit ) + // { + // result = '[ ' + result + ' ]'; + // q = ''; + // } + } + else if( o.escaping ) + { + if( o.stringWrapper === undefined ) + debugger; + result = _.strEscape({ src, stringWrapper : o.stringWrapper }); + } + else + { + result = src; + } + + // if( o.stringWrapper && !o.widthLimit ) + // { + // result = q + result + q; + // } + + if( q ) + // if( !o.widthLimit || result.length < o.widthLimit ) + { + result = q + result + q; + } + + return result; +} + +// + + + _.entity._exportStringFromSymbol = function _exportStringFromSymbol( src, o ) +{ + let text = src.toString().slice( 7, -1 ); + let result = `{- Symbol${text ? ' ' + text + ' ' : ' '}-}`; + return result; +} + +// + + + _.entity._exportStringFromBufferRaw = function _exportStringFromBufferRaw( src, o ) +{ + var result = ''; + + _.assert( _.bufferRawIs( src ) ); + + ( new U8x( src ) ).forEach( function( e, k ) + { + if( k !== 0 ) + result += ', '; + result += '0x' + e.toString( 16 ); + }); + + result = '( new U8x([ ' + result + ' ]) ).buffer'; + + return { text : result, simple : true }; +} + +// + + + _.entity._exportStringFromBufferTyped = function _exportStringFromBufferTyped( src, o ) +{ + var result = ''; + + _.assert( _.bufferTypedIs( src ) ); + + src.forEach( function( e, k ) + { + if( k !== 0 ) + result += ', '; + result += _.entity._exportStringFromNumber( e, o ); + }); + + result = '( new ' + src.constructor.name + '([ ' + result + ' ]) )'; + + return { text : result, simple : true }; +} + +// + + + _.entity._exportStringFromBufferNode = function _exportStringFromBufferNode( src, o ) +{ + var result = ''; + + _.assert( _.bufferNodeIs( src ) ); + + let k = 0; + for ( let value of src.values() ) + { + if( k !== 0 ) + result += ', '; + result += value; + ++k; + } + + result = '( BufferNode.from([ ' + result + ' ]) )'; + + return { text : result, simple : true }; +} + +// + + + _.entity._exportStringFromArray = function _exportStringFromArray( src, o ) +{ + var result = ''; + + _.assert( arguments.length === 2 ); + _.assert( src && _.numberIs( src.length ) ); + _.assert( _.object.isBasic( o ) || o === undefined, 'Expects map {-o-}' ); + + + if( o.level >= o.levels ) + { + return { text : _.entity._exportStringShortAct( src, o ), simple : 1 }; + } + + /* item options */ + + var optionsItem = _.props.extend( null, o ); + optionsItem.tab = o.tab + o.dtab; + optionsItem.level = o.level + 1; + optionsItem.prependTab = 0; + + /* empty case */ + + if( src.length === 0 ) + { + if( !o.wrap ) + return { text : '', simple : 1 }; + return { text : '[]', simple : 1 }; + } + + /* filter */ + + src = _.entity._exportStringFromArrayFiltered( src, o ); + + /* is simple */ + + var length = src.length; + var simple = !optionsItem.multiline; + if( simple ) + simple = length < 8; + if( simple ) + for( var i = 0 ; i < length ; i++ ) + { + simple = _.entity._exportStringIsSimpleElement( src[ i ], optionsItem );; + if( !simple ) + break; + } + + /* */ + + result += _.entity._exportStringFromContainer + ({ + values : src, + optionsContainer : o, + optionsItem, + simple, + prefix : '[', + postfix : ']', + }); + + return { text : result, simple }; +} + +// + + + _.entity._exportStringFromArrayFiltered = function _exportStringFromArrayFiltered( src, o ) +{ + var result = ''; + + _.assert( arguments.length === 2 ); + + /* item options */ + + var optionsItem = _.props.extend( null, o ); + optionsItem.level = o.level + 1; + + /* filter */ + + var v = 0; + var length = src.length; + for( var i = 0 ; i < length ; i++ ) + { + v += !!_.entity._exportStringIsVisibleElement( src[ i ], optionsItem ); + } + + if( v !== length ) + { + var i2 = 0; + var i = 0; + var src2 = _.long.makeUndefined( src, v ); + while( i < length ) + { + if( _.entity._exportStringIsVisibleElement( src[ i ], optionsItem ) ) + { + src2[ i2 ] = src[ i ]; + i2 += 1; + } + i += 1; + } + src = src2; + length = src.length; + } + + return src; +} + +// + + + _.entity._exportStringFromObject = function _exportStringFromObject( src, o ) +{ + var result = ''; + + _.assert( arguments.length === 2 ); + _.assert( _.objectLike( src ) || _.entity.strTypeSecondary( src ) === 'Error' ); + _.assert( _.object.isBasic( o ) || o === undefined, 'Expects map {-o-}' ); + + + if( o.level >= o.levels ) + { + return { text : _.entity._exportStringShortAct( src, o ), simple : 1 }; + } + + if( o.noObject ) + return; + + /* item options */ + + var optionsItem = _.props.extend( null, o ); + optionsItem.noObject = o.noSubObject ? 1 : optionsItem.noObject; + optionsItem.tab = o.tab + o.dtab; + optionsItem.level = o.level + 1; + optionsItem.prependTab = 0; + + /* get names */ + + var keys = _.entity._exportStringFromObjectKeysFiltered( src, o ); + + /* empty case */ + + var length = keys.length; + if( length === 0 ) + { + if( !o.wrap ) + return { text : '', simple : 1 }; + return { text : '{}', simple : 1 }; + } + + /* is simple */ + + var simple = !optionsItem.multiline; + if( simple ) + simple = length < 4; + if( simple ) + for( var k in src ) + { + simple = _.entity._exportStringIsSimpleElement( src[ k ], optionsItem ); + if( !simple ) + break; + } + + /* */ + + result += _.entity._exportStringFromContainer + ({ + values : src, + names : keys, + optionsContainer : o, + optionsItem, + simple, + prefix : '{', + postfix : '}', + keyWrapper : o.keyWrapper, + stringWrapper : o.stringWrapper, + }); + + return { text : result, simple }; +} + +// + + + _.entity._exportStringFromObjectKeysFiltered = function _exportStringFromObjectKeysFiltered( src, o ) +{ + var result = ''; + + _.assert( arguments.length === 2 ); + + /* item options */ + + var optionsItem = _.props.extend( null, o ); + optionsItem.noObject = o.noSubObject ? 1 : optionsItem.noObject; + + /* get keys */ + + var keys = _.props._keys + ({ + srcMap : src, + onlyOwn : o.onlyOwn, + onlyEnumerable : o.onlyEnumerable || o.onlyEnumerable === undefined || o.onlyEnumerable === null || false, + }); + + /* filter */ + + for( var n = 0 ; n < keys.length ; n++ ) + { + if( !_.entity._exportStringIsVisibleElement( src[ keys[ n ] ], optionsItem ) ) + { + keys.splice( n, 1 ); + n -= 1; + } + } + + return keys; +} + +// + + + _.entity._exportStringFromHashMap = function _exportStringFromHashMap( src, o ) +{ + var result = 'HashMap\n'; + var simple = 0; + + _.assert( src instanceof HashMap ); + + src.forEach( function( e, k ) + { + // result += '\n' + k + ' : ' + e; + result += '\n' + k + ' : ' + _.entity.exportStringDiagnosticShallow( e ); + }); + + return { text : result, simple : 0 }; + + /* item options */ + + var optionsItem = _.props.extend( null, o ); + optionsItem.noObject = o.noSubObject ? 1 : optionsItem.noObject; + optionsItem.tab = o.tab + o.dtab; + optionsItem.level = o.level + 1; + optionsItem.prependTab = 0; + + /* get names */ + + var keys = _.entity._exportStringFromObjectKeysFiltered( src, o ); + + /* empty case */ + + var length = keys.length; + if( length === 0 ) + { + if( !o.wrap ) + return { text : '', simple : 1 }; + return { text : '{}', simple : 1 }; + } + + /* is simple */ + + var simple = !optionsItem.multiline; + if( simple ) + simple = length < 4; + if( simple ) + for( var k in src ) + { + simple = _.entity._exportStringIsSimpleElement( src[ k ], optionsItem ); + if( !simple ) + break; + } + + /* */ + + result += _.entity._exportStringFromContainer + ({ + values : src, + names : keys, + optionsContainer : o, + optionsItem, + simple, + prefix : '{', + postfix : '}', + }); + + return { text : result, simple }; +} + +// + + + _.entity._exportStringFromSet = function _exportStringFromSet( src, o ) +{ + let result = _.entity._exportStringFromArray( _.array.from( src ), o ); + result.text = `new Set(${result.text})` ; + return result; +} + +// + + + _.entity._exportStringShortAct = function _exportStringShortAct( src, o ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.object.isBasic( o ), 'Expects map {-o-}' ); + + var result = ''; + + try + { + + if( _.strIs( src ) ) + { + + /* xxx : ? */ + var o2 = + { + widthLimit : o.widthLimit ? Math.min( o.widthLimit, 40 ) : 40, + heightLimit : o.heightLimit || 0, + stringWrapper : o.stringWrapper, + prefix : o.prefix, + postfix : o.postfix, + infix : o.infix, + shortDelimeter : o.shortDelimeter, + } + result = _.entity._exportStringFromStr( src, o2 ); + + } + else if( _.errIs( src ) ) + { + result += _ObjectToString.call( src ); + } + else if( _.routineIs( src ) ) + { + result += _.entity._exportStringFromRoutine( src, o ); + } + else if( _.numberIs( src ) ) + { + result += _.entity._exportStringFromNumber( src, o ); + } + else + { + result = _.entity.exportStringDiagnosticShallow( src ); + } + + } + catch( err ) + { + throw _.err( err ); + } + + return result; +} + +// + + + _.entity._exportStringFromContainer = function _exportStringFromContainer( o ) +{ + var result = ''; + + _.assert( arguments.length > 0 ); + _.assert( _.object.isBasic( o ) || o === undefined, 'Expects map {-o-}' ); + _.assert( _.arrayIs( o.names ) || !o.names ); + + var values = o.values; + var names = o.names; + var optionsContainer = o.optionsContainer; + var optionsItem = o.optionsItem; + + var length = ( names ? names.length : values.length ); + var simple = o.simple; + var prefix = o.prefix; + var postfix = o.postfix; + var limit = optionsContainer.limitElementsNumber; + var l = length; + + if( o.keyWrapper === undefined ) + o.keyWrapper = ''; + + if( limit > 0 && limit < l ) + { + l = limit; + optionsContainer.limitElementsNumber = 0; + } + + /* line postfix */ + + var linePostfix = ''; + if( optionsContainer.comma ) + linePostfix += optionsContainer.comma; + + if( !simple ) + { + linePostfix += '\n' + optionsItem.tab; + } + + /* prepend */ + + if( optionsContainer.prependTab ) + { + result += optionsContainer.tab; + } + + /* wrap */ + + if( optionsContainer.wrap ) + { + result += prefix; + if( simple ) + { + if( l ) + result += ' '; + } + else + { + result += '\n' + optionsItem.tab; + } + } + else if( !simple ) + { + /*result += '\n' + optionsItem.tab;*/ + } + + /* keyWrapper */ + + if( optionsContainer.json ) + { + optionsContainer.keyWrapper = '"'; + } + + /* exec */ + + var r; + var written = 0; + for( var n = 0 ; n < l ; n++ ) + { + + _.assert( optionsItem.tab === optionsContainer.tab + optionsContainer.dtab ); + _.assert( optionsItem.level === optionsContainer.level + 1 ); + + if( names ) + r = _.entity._exportString( values[ names[ n ] ], optionsItem ); + else + r = _.entity._exportString( values[ n ], optionsItem ); + + _.assert( _.object.isBasic( r ) && _.strIs( r.text ) ); + _.assert( optionsItem.tab === optionsContainer.tab + optionsContainer.dtab ); + + if( written > 0 ) + { + result += linePostfix; + } + else if( !optionsContainer.wrap ) + if( !names || !simple ) + //if( !simple ) + { + result += optionsItem.dtab; + } + + if( names ) + { + if( o.keyWrapper === undefined ) + debugger; + let name = _.strEscape({ src : names[ n ], stringWrapper : o.keyWrapper }); + if( optionsContainer.keyWrapper ) + result += optionsContainer.keyWrapper + name + optionsContainer.keyWrapper + optionsContainer.colon; + else + result += name + optionsContainer.colon; + + if( !r.simple ) + result += '\n' + optionsItem.tab; + } + + if( r.text ) + { + result += r.text; + written += 1; + } + + } + + /* other */ + + // if( names && l < names.length ) + // result += other( names.length ); + // else if( l < names.length ) + // result += other( names.length ); + + /* wrap */ + + if( length - l > 0 ) + result += other( length ); + + if( optionsContainer.wrap ) + { + if( simple ) + { + if( l ) + result += ' '; + } + else + { + result += '\n' + optionsContainer.tab; + } + result += postfix; + } + + return result; + + function other( length ) + { + return linePostfix + '[ ... other '+ ( length - l ) +' element(s) ]'; + } + +} + +// + + + _.entity._exportStringFromNumber = function _exportStringFromNumber( src, o ) +{ + var result = ''; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.numberIs( src ) && _.object.isBasic( o ) ); + + if( o.precision !== null ) + if( o.precision < 1 || o.precision > 21 ) + throw _.err( 'RangeError' ); + + if( o.fixed !== null ) + if( o.fixed < 0 || o.fixed > 20 ) + throw _.err( 'RangeError' ); + + if( _.numberIs( o.precision ) ) + result += src.toPrecision( o.precision ); + else if( _.numberIs( o.fixed ) ) + result += src.toFixed( o.fixed ); + else + result += String( src ); + + if( Object.is( src, -0 ) ) + result = '-' + result; + + return result; +} + +// + + + _.entity._exportString = function _exportString( src, o ) +{ + + if( o.precision !== null ) + if( o.precision < 1 || o.precision > 21 ) + { + throw _.err( 'RangeError' ); + } + + if( o.fixed !== null ) + if( o.fixed < 0 || o.fixed > 20 ) + throw _.err( 'RangeError' ); + + var result = ''; + var simple = 1; + var type = _.entity.strTypeSecondary( src ); + + if( o.level >= o.levels ) + { + return { text : _.entity._exportStringShortAct( src, o ), simple : 1 }; + } + + if( !_.entity._exportStringIsVisibleElement( src, o ) ) + return; + + var isPrimitive = _.primitiveIs( src ); + var isLong = _.longIs( src ); + var isArray = _.arrayIs( src ); + var isObject = !isLong && _.object.isBasic( src ); + var isObjectLike = !isLong && _.objectLike( src ) && !( 'toString' in src ); + + /* */ + + // if( !isPrimitive && 'exportString' in src && _.routineIs( src.exportString ) && !src.exportString.notMethod && !_ObjectHasOwnProperty.call( src, 'constructor' ) ) + if( !isPrimitive && 'exportString' in src && _.routineIs( src.exportString ) && _.instanceIs( src ) ) + { + + _.assert + ( + src.exportString.length === 0 || src.exportString.length === 1, + 'Method exportString should expect either none or one argument' + ); + + // var r = src.exportString( o ); + var r = src.exportString({ it : o }); + if( _.object.isBasic( r ) ) + { + _.assert( r.simple !== undefined && r.text !== undefined ); + simple = r.simple; + result += r.text; + } + else if( _.strIs( r ) ) + { + simple = r.indexOf( '\n' ) === -1; + result += r; + } + else throw _.err( 'unexpected' ); + + } + // else if( _.vectorAdapterIs( src ) ) + // { + // result += _.vectorAdapter.exportString( src, o ); + // } + else if( _.errIs( src ) ) + { + + if( !o.errorAsMap ) + { + result += src.toString(); + } + else + { + if( o.onlyEnumerable === undefined || o.onlyEnumerable === null ) + o.onlyEnumerable = 1; + var o2 = _.props.extend( null, o ); + o2.onlyEnumerable = 0; + var r = _.entity._exportStringFromObject( src, o2 ); + result += r.text; + simple = r.simple; + } + + } + else if( type === 'Function' ) + { + result += _.entity._exportStringFromRoutine( src, o ); + } + else if( type === 'Number' && _.numberIs( src ) ) + { + result += _.entity._exportStringFromNumber( src, o ); + } + else if( type === 'BigInt' ) + { + result += _.entity._exportStringFromBigInt( src, o ); + } + else if( type === 'String' ) + { + result += _.entity._exportStringFromStr( src, o ); + } + else if( type === 'Date' ) + { + if( o.jsonLike ) + result += '"' + src.toISOString() + '"'; + else if( o.jsLike ) + result += 'new Date( \'' + src.toISOString() + '\' )'; + else + result += src.toISOString(); + } + else if( type === 'Symbol' ) + { + result += _.entity._exportStringFromSymbol( src, o ); + } + else if( _.bufferRawIs( src ) ) + { + var r = _.entity._exportStringFromBufferRaw( src, o ); + result += r.text; + simple = r.simple; + } + else if( _.bufferTypedIs( src ) ) + { + var r = _.entity._exportStringFromBufferTyped( src, o ); + result += r.text; + simple = r.simple; + } + else if( _.bufferNodeIs( src ) ) + { + var r = _.entity._exportStringFromBufferNode( src, o ); + result += r.text; + simple = r.simple; + } + else if( isLong ) + { + var r = _.entity._exportStringFromArray( src, o ); + result += r.text; + simple = r.simple; + } + else if( isObject ) + { + var r = _.entity._exportStringFromObject( src, o ); + result += r.text; + simple = r.simple; + } + else if( _.hashMapLike( src ) ) + { + var r = _.entity._exportStringFromHashMap( src, o ); + result += r.text; + simple = r.simple; + } + else if( _.setLike( src ) ) + { + var r = _.entity._exportStringFromSet( src, o ); + result += r.text; + simple = r.simple; + } + else if( !isPrimitive && _.routineIs( src.toString ) ) + { + result += src.toString(); + } + else + { + if( o.jsonLike ) + { + if( src === undefined || src === NaN ) + result += 'null'; + else + result += String( src ); + } + else + { + result += String( src ); + } + } + + return { text : result, simple }; +} + +// + + + _.entity.exportString = ( function _exportStringFine_functor() +{ + + var primeFilter = + { + + noRoutine : 0, + noAtomic : 0, + noArray : 0, + noObject : 0, + noRow : 0, + noError : 0, + noNumber : 0, + noString : 0, + noDate : 0, + noUndefines : 0, + + } + + var composes = + { + + levels : 1, + level : 0, + + wrap : 1, + // stringWrapper : '\'', + stringWrapper : null, + keyWrapper : '', + prependTab : 1, + errorAsMap : 0, + onlyOwn : 1, + tab : '', + dtab : ' ', + colon : ' : ', + limitElementsNumber : 0, + widthLimit : 0, + heightLimit : 0, + + format : 'string.diagnostic', + + } + + /**/ + + var optional = + { + + /* secondary filter */ + + noSubObject : 0, + onlyRoutines : 0, + onlyEnumerable : 1, + + /**/ + + precision : null, + fixed : null, + // comma : ', ', + comma : null, + multiline : 0, + multilinedString : null, + escaping : 0, + jsonLike : 0, + jsLike : 0, + + } + + var restricts = + { + /*level : 0, */ + } + + Object.preventExtensions( primeFilter ); + Object.preventExtensions( composes ); + Object.preventExtensions( optional ); + Object.preventExtensions( restricts ); + + var def; + + def = _.props.extend( null, optional, primeFilter, composes ); + + var routine = exportStringFine; + routine.defaults = def; + routine.methods = _.entity.exportStringMethods; + routine.fields = _.entity.exportStringFields; + // routine.notMethod = 1; + return routine; + + function exportStringFine( src, o ) + { + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.object.isBasic( o ) || o === undefined, 'Expects map {-o-}' ); + + var o = o || Object.create( null ); + var exportStringDefaults = Object.create( null ); + // if( !_.primitiveIs( src ) && 'exportString' in src && _.routineIs( src.exportString ) && !src.exportString.notMethod && _.object.isBasic( src.exportString.defaults ) ) + if( !_.primitiveIs( src ) && 'exportString' in src && _.routineIs( src.exportString ) && _.instanceIs( src ) && _.object.isBasic( src.exportString.defaults ) ) + exportStringDefaults = src.exportString.defaults; + + if( o.levels === undefined || o.levels === null ) + if( o.jsonLike || o.jsLike ) + o.levels = 1 << 20; + + if( o.jsLike ) + { + if( o.escaping === undefined || o.escaping === null ) + o.escaping = 1; + if( o.keyWrapper === undefined || o.keyWrapper === null ) + o.keyWrapper = '"'; + if( o.stringWrapper === undefined || o.stringWrapper === null ) + o.stringWrapper = '`'; + } + + if( o.jsonLike ) + { + if( o.escaping === undefined || o.escaping === null ) + o.escaping = 1; + if( o.keyWrapper === undefined || o.keyWrapper === null ) + o.keyWrapper = '"'; + if( o.stringWrapper === undefined || o.stringWrapper === null ) + o.stringWrapper = '"'; + } + + // _.map.assertHasOnly( o, [ composes, primeFilter, optional ] ); + // o = _.props.supplement( null, o, exportStringDefaults, composes, primeFilter ); + + _.map.assertHasOnly( o, def ); + o = _.props.supplement( o, def ); + + if( o.multilinedString === undefined || o.multilinedString === null ) + o.multilinedString = o.stringWrapper === '`'; + + if( o.stringWrapper === undefined || o.stringWrapper === null ) + if( o.multilinedString ) + o.stringWrapper = '`'; + else + o.stringWrapper = `'`; + + if( o.onlyRoutines ) + { + _.assert( !o.noRoutine, 'Expects {-o.noRoutine-} false if( o.onlyRoutines ) is true' ); + for( var f in primeFilter ) + o[ f ] = 1; + o.noRoutine = 0; + } + + if( o.comma === undefined || o.comma === null ) + o.comma = o.wrap ? ', ' : ' '; + + if( o.comma && !_.strIs( o.comma ) ) + o.comma = ', '; + + // if( o.stringWrapper === '`' && o.multilinedString === undefined ) + // o.multilinedString = 1; + + _.assert( _.strIs( o.stringWrapper ), 'Expects string {-o.stringWrapper-}' ); + + if( o.jsonLike ) + { + if( !o.jsLike ) + _.assert( o.stringWrapper === '"', 'Expects double quote ( o.stringWrapper ) true if either ( o.jsonLike ) or ( o.jsLike ) is true' ); + _.assert( !o.multilinedString, 'Expects {-o.multilinedString-} false if either ( o.jsonLike ) or ( o.jsLike ) is true to make valid JSON' ); + } + + var r = _.entity._exportString( src, o ); + + return r ? r.text : ''; + } + +} )(); +_.entity.exportString.defaults = +{ + "noSubObject" : 0, + "onlyRoutines" : 0, + "onlyEnumerable" : 1, + "precision" : null, + "fixed" : null, + "comma" : null, + "multiline" : 0, + "multilinedString" : null, + "escaping" : 0, + "jsonLike" : 0, + "jsLike" : 0, + "noRoutine" : 0, + "noAtomic" : 0, + "noArray" : 0, + "noObject" : 0, + "noRow" : 0, + "noError" : 0, + "noNumber" : 0, + "noString" : 0, + "noDate" : 0, + "noUndefines" : 0, + "levels" : 1, + "level" : 0, + "wrap" : 1, + "stringWrapper" : null, + "keyWrapper" : ``, + "prependTab" : 1, + "errorAsMap" : 0, + "onlyOwn" : 1, + "tab" : ``, + "dtab" : ` `, + "colon" : ` : `, + "limitElementsNumber" : 0, + "widthLimit" : 0, + "heightLimit" : 0, + "format" : `string.diagnostic` +} + +// + + + _.entity.namespaceForExporting = function namespaceForExporting( src ) +{ + if( _.primitive.is( src ) ) + return _.primitive; + if( _.date.is( src ) ) + return _.date; + if( _.regexp.is( src ) ) + return _.regexp; + if( _.set.like( src ) ) + return _.set; + if( _.hashMap.like( src ) ) + return _.hashMap; + if( _.routine.is( src ) ) + return _.routine; + if( _.buffer.like( src ) ) + return _.buffer; + if( _.long.like( src ) ) + return _.long; + if( _.vector.like( src ) ) + return _.vector; + if( _.countable.like( src ) ) + return _.countable; + if( _.aux.like( src ) ) + return _.aux; + if( _.object.like( src ) ) + return _.object; + + return null; +} + +// + + + _.entity._exportStringShallow = function _exportStringShallow( src, o ) +{ + + _.assert( arguments.length === 2 ); + _.assert( _.number.is( o.widthLimit ) && o.widthLimit >= 0 ); + _.assert( _.number.is( o.heightLimit ) && o.heightLimit >= 0 ); + _.assert( o.src === undefined ) + _.assert( o.format === 'string.diagnostic' || o.format === 'string.code' ); + + let result = ''; + let method = o.format === 'string.diagnostic' ? 'exportStringDiagnosticShallow' : 'exportStringCodeShallow'; + + try + { + + let namespace = this.namespaceForExporting( src ); + if( namespace === null ) + { + _.assert( 0, 'not tested' ); + namespace = _.blank; + } + + result = namespace[ method ]( src ); + result = _.strShort_({ src : result, widthLimit : o.widthLimit, heightLimit : o.heightLimit }).result; + + } + catch( err ) + { + debugger; + throw err; + } + + return result; +} +_.entity._exportStringShallow.defaults = +{ "format" : null, "widthLimit" : 0, "heightLimit" : 0 } + +// + + + _.entity._exportStringDiagnosticShallow = function _exportStringDiagnosticShallow( src, o ) +{ + let result; + let namespace = this.namespaceForExporting( src ); + + if( namespace ) + result = namespace.exportStringDiagnosticShallow( src ); + else + result = _.strShort_( String( src ) ).result; + + return result; +} + +// + + + _.entity.exportStringDiagnosticShallow = function exportStringDiagnosticShallow( src, o ) /* */ +{ + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects one or two arguments' ); + o = _.aux.supplement( o || null, exportStringDiagnosticShallow.defaults ); + o.format = o.format || exportStringDiagnosticShallow.defaults.format; + return _.entity._exportStringShallow( src, o ); +} +_.entity.exportStringDiagnosticShallow.defaults = +{ "format" : `string.diagnostic`, "widthLimit" : 0, "heightLimit" : 0 } + +// + + + _.entity._exportStringFromRoutine = function _exportStringFromRoutine( src, o ) +{ + var result = ''; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.routineIs( src ), 'Expects routine {-src-}' ); + + if( o.jsLike ) + { + if( _.routineSourceGet ) + result = _.routineSourceGet( src ); + else + result = src.toString(); + } + else + { + result = '[ routine ' + ( src.name || src._name || 'without name' ) + ' ]'; + } + + return result; +} + +// + + + + _.error._setupUncaughtErrorHandler2 = function _setupUncaughtErrorHandler2() +{ + + if( _realGlobal_._setupUncaughtErrorHandlerDone ) + return; + + _realGlobal_._setupUncaughtErrorHandlerDone = 1; + + if( _realGlobal_.process && typeof _realGlobal_.process.on === 'function' ) + { + + _realGlobal_.process.on( 'uncaughtException', _.error._handleUncaught1 ); + _realGlobal_.process.on( 'unhandledRejection', _.error._handleUncaughtPromise1 ); + _.error._handleUncaughtHead = _handleUncaughtHeadNode; + if( Config.interpreter === 'browser' ) + _.error._handleUncaughtHead = _handleUncaughtHeadBrowser; + } + else if( Object.hasOwnProperty.call( _realGlobal_, 'onerror' ) ) + { + _.error._handleUncaught0 = _realGlobal_.onerror; + _realGlobal_.onerror = _.error._handleUncaught1; + _.error._handleUncaughtHead = _handleUncaughtHeadBrowser; + } + + /* */ + + function _handleUncaughtHeadBrowser( args ) + { + debugger; + let [ message, sourcePath, lineno, colno, error ] = args; + let err = error || message; + return [ { err : new Error( args[ 0 ] ), args } ]; + } + + /* */ + + function _handleUncaughtHeadNode( args ) + { + return [ { err : args[ 0 ], args } ]; + } + + /* */ + +} + +// + + + _.error._setupUncaughtErrorHandler9 = function _setupUncaughtErrorHandler9() +{ + + if( !_realGlobal_._setupUncaughtErrorHandlerDone ) + { + debugger; + throw Error( 'setup0 should be called first' ); + } + + if( _realGlobal_._setupUncaughtErrorHandlerDone > 1 ) + return; + + _realGlobal_._setupUncaughtErrorHandlerDone = 2; + + /* */ + + if( _global.process && _.routine.is( _global.process.on ) ) + { + _.error._handleUncaughtHead = _errHeadNode; + } + else if( Object.hasOwnProperty.call( _global, 'onerror' ) ) + { + _.error._handleUncaughtHead = _errHeadBrowser; + } + + /* */ + + function _errHeadBrowser( args ) + { + let [ message, sourcePath, lineno, colno, error ] = args; + let err = error || message; + + if( _._err ) + err = _._err + ({ + args : [ error || message ], + level : 1, + fallBackStack : 'at handleError @ ' + sourcePath + ':' + lineno, + throwLocation : + { + filePath : sourcePath, + line : lineno, + col : colno, + }, + }); + + return [ { err, args } ]; + } + + /* */ + + function _errHeadNode( args ) + { + return [ { err : args[ 0 ], args } ]; + } + + /* */ + +} + +// + + + _.error._handleUncaughtHead = function _errHeadNode( args ) + { + return [ { err : args[ 0 ], args } ]; + } + +// + + + _.error._handleUncaught1 = function _handleUncaught1() +{ + + debugger; + let args = _.error._handleUncaughtHead( arguments ); + let result = _.error._handleUncaught2.apply( this, args ); + + if( _.error._handleUncaught0 ) + _.error._handleUncaught0.apply( this, arguments ); + + return result; +} + +// + + + _.error._handleUncaughtPromise1 = function _handleUncaughtPromise1( err, promise ) +{ + let o = Object.create( null ); + o.promise = promise; + o.err = err; + o.origination = 'uncaught promise error'; + let result = _.error._handleUncaught2.call( this, o ); + return result; +} + +// + + + _.error._handleUncaught2 = function _handleUncaught2( o ) +{ + const __ = _global_.globals && _globals_.testing.wTools; + const process0 = processNamespaceGet(); + + optionsRefine(); + + /* xxx qqq : resolve issue in browser + if file has syntax error then unachught error should not ( probably ) be throwen + because browser thows uncontrolled information about syntax error after that + avoid duplication of errors in log + */ + + o.err = errRefine( o.err ); + + processUncaughtErrorEvent(); + + if( _.error.isAttended( o.err ) ) + return; + + consoleUnbar(); + + console.error( o.prefix ); + + errLogFields(); + errLog(); + + console.error( o.postfix ); + + processExit(); + + /* */ + + function optionsRefine() + { + + if( !o.origination ) + o.origination = 'uncaught error'; + + // for( let k in o ) + // if( _handleUncaught2.defaults[ k ] !== undefined ) + // { + // console.error( `Routine::_handleUncaught2() does not expect option::${k}` ); + // } + + o.prefix = `--------------- ${o.origination} --------------->\n`; + o.postfix = `--------------- ${o.origination} ---------------<\n`; + o.logger = _global.logger || _global.console; + + } + + /* */ + + function consoleUnbar() + { + let Logger = loggerClassGet(); + try + { + if( Logger && Logger.ConsoleBar && Logger.ConsoleIsBarred( console ) ) + Logger.ConsoleBar({ on : 0 }); + } + catch( err2 ) + { + debugger; + console.error( err2 ); + } + } + + /* */ + + function errLog() + { + try + { + if( _.error && _.error._log ) + _.error._log( o.err, o.logger ); + else + console.error( o.err ); + } + catch( err2 ) + { + debugger; + console.error( err2 ); + console.error( o.err ); + } + } + + /* */ + + function errLogFields() + { + if( !o.err.originalMessage && _.object.like && _.object.like( o.err ) ) + try + { + let props = Object.create( null ); + for( let k in o.err ) + props[ k ] = o.err[ k ]; + // let serr = _.entity.exportString && _.props ? _.entity.exportString.fields( o.err, { errorAsMap : 1 } ) : o.err; + o.logger.error( _.entity.exportString( props ) ); + debugger; + } + catch( err2 ) + { + debugger; + console.error( err2 ); + } + } + + /* */ + + function errRefine( err ) + { + try + { + return _.error.process( err ); + } + catch( err2 ) + { + console.error( err2 ); + return err; + } + } + + /* */ + + function processNamespaceGet() + { + let result; + if( !result && _.process && _.process.exitReason ) + result = _.process; + if( !result && _realGlobal_ && _realGlobal_.wTools && _realGlobal_.wTools.process && _realGlobal_.wTools.process.exitReason ) + result = _realGlobal_.wTools.process; + if + ( + !result + && _realGlobal_._globals_.testing + && __ + && __.process + && __.process.exitReason + ) + result = __.process; + if( !result ) + result = _.process; + return result; + } + + /* */ + + function loggerClassGet() + { + let result; + if( !result && _.Logger && _.Logger.ConsoleBar ) + result = _.Logger; + if( !result && _realGlobal_ && _realGlobal_.wTools && _realGlobal_.wTools.Logger && _realGlobal_.wTools.Logger.ConsoleBar ) + result = _realGlobal_.wTools.Logger; + if + ( + !result + && __ + && __.Logger + && __.Logger.ConsoleBar + ) + result = __.Logger; + return result; + } + + /* */ + + function processUncaughtErrorEvent() + { + try + { + // if( process0.eventGive ) /* xxx : cover in starter not catching uncaught error */ + if( process0 && process0.eventGive ) + // process0.eventGive({ event : 'uncaughtError', args : [ o ] }); + /* xxx : move to namespace app? */ + process0.eventGive({ event : 'uncaughtError', origination : o.origination, err : o.err }); + for( let g in _realGlobal_._globals_ ) + { + const _global = _realGlobal_._globals_[ g ]; + if( _global.wTools && _global.wTools.process && _global.wTools.process.eventGive ) + if( _global.wTools.process !== process0 ) + _global.wTools.process.eventGive({ event : 'uncaughtError', origination : o.origination, err : o.err }); + // _global.wTools.process.eventGive({ event : 'uncaughtError', args : [ o ] }); + } + } + catch( err2 ) + { + debugger; + console.log( err2 ); + exitError( err2, false ); + } + } + + /* */ + + function exitError( err, rewriting ) + { + let set = false; + debugger; + if( process0 && process0.exit ) + try + { + process0.exitCode( -1 ); + if( !process0.exitReason() ) + process0.exitReason( err ); + set = true; + } + catch( err2 ) + { + debugger; + console.log( err2 ); + } + if( !set ) + try + { + if( _global.process ) + { + if( !process.exitCode ) + process.exitCode = -1; + set = true; + } + } + catch( err2 ) + { + } + } + + /* */ + + function processExit() + { + exitError( o.err, true ); + if( process0 && process0.exit ) + try + { + process0.exit(); + } + catch( err2 ) + { + debugger; + console.log( err2 ); + exitError( o.err, false ); + } + try + { + if( _global.process ) + process.exit(); + } + catch( err2 ) + { + } + } + +} +_.error._handleUncaught2.defaults = +{ "err" : null, "origination" : null } + +// + + + + _.event._chainGenerate = function _chainGenerate( args ) +{ + let chain = []; + + _.assert( arguments.length === 1 ); + _.assert( _.longIs( args ) ); + + for( let a = 0 ; a < args.length-2 ; a++ ) + chainMake( a ); + + // chain.push([ _.event.nameValueFrom( args[ args.length-2 ] ), args[ args.length-1 ] ]); + chain.push([ args[ args.length-2 ], args[ args.length-1 ] ]); + + _.assert( _.routine.is( args[ args.length-1 ] ) ); + + return chain; + + /* */ + + function chainMake( a ) + { + // let e1 = _.event.nameValueFrom( args[ a ] ); + let e1 = args[ a ]; + chain.push([ e1, on ]); + function on() + { + let self = this; + let next = chain[ a + 1 ]; + + if( _.routine.is( self.on ) ) + { + /* + Dmytro : it is strange code because the owners of edispatcher can be classes like Process. + And this solution allows direct call of callbacks when the routine eventGive is not used : + https://github.com/Wandalen/wProcess/blob/master/proto/wtools/abase/l4_process/Basic.s#L210 + https://github.com/Wandalen/wProcedure/blob/master/proto/wtools/abase/l8_procedure/Namespace.s#L59 + */ + self.on( next[ 0 ], next[ 1 ] ); + if( self.eventHasHandler( e1, on ) ) + self.off( e1, on ); + } + else + { + let o = _.event.onHead( _.event.on, next ); + o.once = on.once; + _.event._on( self, o ); + + if( !on.once ) + if( _.event.eventHasHandler( self, { eventName : e1, eventHandler : on } ) ) + _.event.off( self, { callbackMap : { [ e1 ] : on } } ); + } + + } + } +} + +// + + + _.event._chainToCallback = function _chainToCallback( args ) +{ + let chain = _.event._chainGenerate( args ); + let firstPair = chain[ 0 ]; + return firstPair[ 1 ]; +} + +// + + + _.event._chainValidate = function _chainValidate( chain ) +{ + + for( let i = 0 ; i < chain.length - 1 ; i++ ) + _.assert( _.str.defined( chain[ i ] ) ); + // for( let i = 0 ; i < chain.length - 1 ; i++ ) + // { + // _.assert( _.event.nameIs( chain[ i ] ) ); + // } + _.assert( _.routine.is( chain[ chain.length - 1 ] ) ); + + return true; +} + +// + + + _.event._callbackMapValidate = function _callbackMapValidate( callbackMap ) +{ + + _.assert( _.mapIs( callbackMap ) ); + for( let k in callbackMap ) + { + let callback = callbackMap[ k ]; + _.assert( _.routine.is( callback ) || _.longIs( callback ) ); + if( _.routine.is( callback ) ) + continue; + _.event._chainValidate( callback ); + } + +} + +// + + + _.event.nameValueFrom = undefined; + +// + + + _.event.nameIs = undefined; + +// + + + _.event.chainIs = function chainIs( src ) +{ + return src instanceof _.event.Chain; +} + +// + + + _.event.Name = undefined; + +// + + + _.event.Chain = function Chain() +{ + if( !( _.event.chainIs( this ) ) ) + { + if( _.event.chainIs( arguments[ 0 ] ) ) + { + _.assert( arguments.length === 1, 'Expects single Chain or set of event names' ); + return arguments[ 0 ]; + } + return new Chain( ... arguments ); + } + + let result = _.array.make( arguments.length ); + _.assert( arguments.length >= 1, 'Expects events names' ); + for( let i = 0 ; i < arguments.length ; i++ ) + { + _.assert( _.str.is( arguments[ i ] ) ); + result[ i ] = arguments[ i ]; + } + // result[ i ] = _.event.Name( arguments[ i ] ); + + this.chain = result; + return this; +} + +// + + + _.event._on = function _on( edispatcher, o ) +{ + + _.routine.options( _on, o ); + _.assert( _.mapIs( o.callbackMap ) ); + _.assert( _.object.isBasic( edispatcher ) ); + _.assert( _.object.isBasic( edispatcher.events ) ); + _.map.assertHasOnly( o.callbackMap, edispatcher.events, 'Unknown kind of event' ); + _.assert( arguments.length === 2 ); + + const once = !!o.once; + let descriptors = Object.create( null ); + let append; + if( o.first ) + append = _.arrayPrepend; + else + append = _.arrayAppend; + + for( let c in o.callbackMap ) + { + let callback = o.callbackMap[ c ]; + descriptors[ c ] = descriptorMake(); + + if( _.longIs( callback ) ) + callback = _.event._chainToCallback([ c, ... callback ]); + + _.assert( _.routine.is( callback ) ); + + callback = callbackOn_functor.call( descriptors[ c ], callback, c ); + descriptors[ c ].off = off_functor.call( descriptors[ c ], edispatcher, { callbackMap : { [ c ] : callback } } ); + + append( edispatcher.events[ c ], callback ); + + // if( o.first ) + // _.arrayPrepend( edispatcher.events[ c ], callback ); + // else + // _.arrayAppend( edispatcher.events[ c ], callback ); + + /* */ + + } + + return descriptors; + + /* */ + + // function callbackOn_functor( callback ) /* Dmytro : can't extract name from descriptor. Maybe, it can contains field `name` */ + function callbackOn_functor( callback, name ) + { + let self = this; + + function callbackOn() + { + let result; + if( self.enabled ) + { + result = callback.apply( this, arguments ); + if( once === true ) + _.event.off( edispatcher, { callbackMap : { [ name ] : callbackOn } } ); + // _.event.off( edispatcher, { callbackMap : { [ name ] : callbackOnce } } ); /* Dmytro : callbackOnce does not exist */ + } + return result; + } + callbackOn.native = callback; + callbackOn.native.once = once; + + return callbackOn; + } + + /* */ + + function descriptorMake() + { + let descriptor = Object.create( null ); + descriptor.off = null; + descriptor.enabled = true; + descriptor.first = o.first; /* Dmytro : please, explain, does it need to save original value? */ + descriptor.callbackMap = o.callbackMap; /* Dmytro : please, explain, does it need to save link to original callback map? */ + return descriptor; + } + + /* */ + + function off_functor( edispatcher, o ) + { + let self = this; + + return function() + { + _.assert( arguments.length === 0, 'Expects no arguments.' ); + return _.event.off( edispatcher, o ); + } + } + + /* */ + +} +_.event._on.defaults = +{ "callbackMap" : null, "first" : false, "once" : false } + +// + + + _.event.on = function on( edispatcher, o ) +{ + o.once = false; + return _.event._on( edispatcher, o ); +} + +// + + + _.event.onHead = function onHead( routine, args ) +{ + let o; + + _.assert( _.longIs( args ) ); + _.assert( arguments.length === 2 ); + + if( args.length === 2 ) + { + _.assert( _.routine.is( args[ 1 ] ) ); + + o = Object.create( null ); + o.callbackMap = Object.create( null ); + + if( _.event.chainIs( args[ 0 ] ) ) + { + let chain = args[ 0 ].chain; + o.callbackMap[ chain[ 0 ] ] = _.longOnly_( null, chain, [ 1, chain.length - 1 ] ); + o.callbackMap[ chain[ 0 ] ].push( args[ 1 ] ); + // o.callbackMap[ chain[ 0 ].value ] = _.longOnly_( null, chain, [ 1, chain.length - 1 ] ); + // o.callbackMap[ chain[ 0 ].value ].push( args[ 1 ] ); + } + else if( _.str.is( args[ 0 ] ) ) + { + o.callbackMap[ args[ 0 ] ] = args[ 1 ]; + } + // else if( _.event.nameIs( args[ 0 ] ) ) + // { + // o.callbackMap[ args[ 0 ].value ] = args[ 1 ]; + // } + else + { + _.assert( 0, 'Expects Chain with names or single name of event.' ); + } + } + else if( args.length === 1 ) + { + o = args[ 0 ]; + } + else + { + _.assert( 0, 'Expects single options map {-o-} or events Chain and callback as arguments.' ); + } + + if( Config.debug ) + { + _.assert( _.mapIs( o ) ); + _.event._callbackMapValidate( o.callbackMap ); + } + + // _.event._callbackMapNormalize( o.callbackMap ); + + return o; +} + +// + + + _.event.once = function once( edispatcher, o ) +{ + o.once = true; + return _.event._on( edispatcher, o ); +} + +// + + + _.event.off = function off( edispatcher, o ) +{ + + _.routine.options( off, o ); + _.assert( _.mapIs( o.callbackMap ) ); + _.assert( _.object.isBasic( edispatcher ) ); + _.assert( _.object.isBasic( edispatcher.events ) ); + _.map.assertHasOnly( o.callbackMap, edispatcher.events, 'Unknown kind of event' ); + _.assert( arguments.length === 2 ); + + for( let c in o.callbackMap ) + { + if( o.callbackMap[ c ] === null ) + _.array.empty( edispatcher.events[ c ] ); + else + _.arrayRemoveOnceStrictly( edispatcher.events[ c ], o.callbackMap[ c ], callbackEqualize ); + } + + return o; + + /* */ + + function callbackEqualize( callback, handler ) + { + return handler === callback || handler === callback.native; + } +} +_.event.off.defaults = +{ "callbackMap" : null } + +// + + + _.event.eventHasHandler = function eventHasHandler( edispatcher, o ) +{ + + _.routine.options( eventHasHandler, o ); + _.assert( _.strIs( o.eventName ) ); + _.assert( _.routine.is( o.eventHandler ) ); + _.assert( _.mapIs( edispatcher ) ); + _.assert( _.mapIs( edispatcher.events ) ); + _.assert( arguments.length === 2 ); + + return _.longHas( edispatcher.events[ o.eventName ], o.eventHandler, handlerEqualize ); + + /* */ + + function handlerEqualize( callback, handler ) + { + return handler === callback || handler === callback.native; + } +} +_.event.eventHasHandler.defaults = +{ "eventName" : null, "eventHandler" : null } + +// + + + _.event.eventGive = function eventGive( edispatcher, o ) +{ + + // if( _.strIs( o ) ) + // o = { event : o } + // _.routine.options( eventGive, o ); + // + // if( o.onError === null ) + // o.onError = onError; + // if( o.args === null ) + // { + // o.args = [ Object.create( null ) ]; + // o.args[ 0 ].event = o.event; + // } + + _.assert( arguments.length === 2 ); + _.assert( !!edispatcher.events[ o.event ], `Unknown event ${o.event}` ); + _.assert( _.long.is( o.args ), 'Expects arguments {-o.args-}' ); + + let was; + let visited = []; + do + { + was = visited.length; + let events = edispatcher.events[ o.event ].slice(); + _.each( events, ( callback ) => + { + if( _.longHas( visited, callback ) ) + return; + visited.push( callback ); + try + { + callback.apply( edispatcher, o.args ); + } + catch( err ) + { + o.onError( err, o ); + } + }); + } + while( was !== visited.length ); + + /* */ + + // function onError( err, o ) + // { + // throw _.err( `Error on handing event ${o.event}\n`, err ); + // } + +} +_.event.eventGive.defaults = +{ "event" : null, "args" : null, "onError" : null } + +// + + + _.event.eventGiveHead = function eventGiveHead( edispatcher, routine, args ) +{ + let o = args[ 0 ]; + + _.assert( arguments.length === 3, 'Expects exactly three arguments.' ); + _.assert( args.length > 0 ); + _.assert( _.aux.is( edispatcher.events ), 'Expects events dispatcher.' ); + + if( _.strIs( o ) ) + o = { event : o }; + _.assert( _.aux.is( o ), 'Expects string or options map in {-o.args[ 1 ]-}.' ); /* Dmytro : restrict using options map in first argument */ + + if( o.onError === null || o.onError === undefined ) + o.onError = onError; + + _.map.assertHasOnly( o, routine.defaults ); + + if( o.args ) + _.assert( args.length === 1 ); /* Dmytro : restrict using options map in first argument */ + else /* Dmytro : do not overwrite arguments if the field exists */ + o.args = args; + + // if( o.args === null ) + // { + // o.args = [ Object.create( null ) ]; + // o.args[ 0 ].event = o.event; + // } + + return o; + + /* */ + + function onError( err, o ) + { + throw _.err( `Error on handing event ${o.event}\n`, err ); + } +} + +// + + + + + _.each = function entityEach( src, onEach ) +{ + + _.assert( arguments.length === 2 ); + _.assert( onEach.length <= 3 ); + _.assert( _.routine.is( onEach ) ); + + /* */ + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) ) + { + + for( let k = 0 ; k < src.length ; k++ ) + { + onEach( src[ k ], k, src ); + } + + } + else if( _.aux.is( src ) ) + { + + for( let k in src ) + { + onEach( src[ k ], k, src ); + } + + } + else + { + onEach( src, undefined, undefined ); + } + + /* */ + + return src; +} + +// + + + + /* + Uri namespace( parseConsecutive ) is required to make _.include working in a browser + */ + + // parseFull maybe? + + _.uri.isGlobal = function isGlobal( filePath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), 'Expects string' ); + return _.strHas( filePath, '://' ); +} + +// + + + _.uri.parseConsecutive = ( function() { + + const _parse_head = function parse_head( routine, args ) + { + _.assert( args.length === 1, 'Expects single argument' ); + + let o = { srcPath : args[ 0 ] }; + + _.routine.options_( routine, o ); + _.assert( _.strIs( o.srcPath ) || _.mapIs( o.srcPath ) ); + _.assert( _.longHas( routine.Kind, o.kind ), () => 'Unknown kind of parsing ' + o.kind ); + + return o; + } + + const _parse_body = function parse_body( o ) + { + let self = this; + let result = Object.create( null ); + + if( _.mapIs( o.srcPath ) ) + { + _.map.assertHasOnly( o.srcPath, this.UriFull.propsExtension ); + if( o.srcPath.protocols ) + return o.srcPath; + else if( o.srcPath.full ) + o.srcPath = o.srcPath.full; + else + o.srcPath = this.str( o.srcPath ); + } + + let postfixes = ''; + + longPathParse(); + + let delimeter = [ self.tagToken, self.hashToken, self.queryToken ]; + if( _.strHasAny( result.longPath, delimeter ) ) + postfixesParse( delimeter ); + + /* */ + + if( o.kind === 'full' ) + { + + result.postfixedPath = result.longPath + postfixes; + + self._parseLongPath( result, result.longPath ); + + if( result.protocol ) + result.protocols = result.protocol.split( '+' ); + else + result.protocols = []; + + if( _.strIs( result.protocol ) ) + result.origin = result.protocol + self.protocolToken + result.hostFull; + + result.full = o.srcPath; + + } + else if( o.kind === 'consecutive' ) + { + } + else if( o.kind === 'atomic' ) + { + self._parseLongPath( result, result.longPath ); + delete result.hostFull; + delete result.longPath; + } + else _.assert( 0 ); + + return result; + + /* */ + + function longPathParse() + { + + let isolates = _.strIsolateLeftOrNone.body + ({ + src : o.srcPath, + delimeter : self.protocolToken, + times : 1, + quote : false, + }); + + if( isolates[ 1 ] ) + result.protocol = isolates[ 0 ]; + + result.longPath = isolates[ 2 ]; + } + + /* */ + + function postfixesParse( delimeter ) + { + + let rest = ''; + let splits2 = _.path.split( result.longPath ); + let left, s; + + for( s = 0 ; s < splits2.length ; s++ ) + { + let split = splits2[ s ]; + if( _.path._unescape( split ).wasEscaped ) + continue; + left = _.strLeft_( split, delimeter ); + if( left.entry ) + { + if( s > 0 ) + { + result.longPath = splits2.slice( 0, s ).join( self.upToken ); + result.longPath += self.upToken + split.slice( 0, left.index ); + } + else + { + result.longPath = split.slice( 0, left.index ); + } + split = split.slice( left.index + 1 ); + splits2[ s ] = split + rest = splits2.slice( s ).join( self.upToken ); + break; + } + } + + if( left && left.entry ) + restParse( rest, left.entry, delimeter ); + + } + + /* */ + + function restParse( rest, entry, delimeter ) + { + + _.arrayRemoveOnceStrictly( delimeter, entry ); + + let isolates = _.strIsolateLeftOrAll( rest, delimeter ); + + if( entry === self.queryToken ) + result.query = isolates[ 0 ]; + else if( entry === self.hashToken ) + result.hash = isolates[ 0 ]; + else if( entry === self.tagToken ) + result.tag = isolates[ 0 ]; + + postfixes += entry + isolates[ 0 ]; + + // rest = isolates[ 2 ]; /* xxx : remove variable? */ + if( isolates[ 1 ] ) + { + restParse( isolates[ 2 ], isolates[ 1 ], delimeter ); + } + + } + + /* */ + + } + _parse_body.defaults = { "srcPath" : null, "kind" : `full` } + _parse_body.components = { + "protocol" : null, + "query" : null, + "hash" : null, + "tag" : null, + "protocols" : null, + "postfixedPath" : null, + "resourcePath" : null, + "longPath" : null, + "full" : null, + "hostFull" : null, + "host" : null, + "port" : null, + "user" : null, + "origin" : null + } + _parse_body.Kind = [ `full`, `atomic`, `consecutive` ] + + const _parse_ = _.routine.unite + ({ + head : _parse_head, + body : _parse_body, + }); + + return _parse_; +})(); +_.uri.parseConsecutive.defaults = +{ "srcPath" : null, "kind" : `consecutive` } + +// + + + _.uri.refine = function refine( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ); + else + return parent.refine.call( this, filePath ); + + if( _.strDefined( filePath.longPath ) ) + filePath.longPath = parent.refine.call( this, filePath.longPath ); + + if( filePath.hash || filePath.tag ) + filePath.longPath = parent.detrail( filePath.longPath ); + + return this.str( filePath ); +} + +// + + + _.uri._normalize = function _normalize( o ) +{ + // let debug = 0; + // if( 0 ) + // debug = 1; + + _.routine.assertOptions( _normalize, arguments ); + _.assert( _.strIs( o.src ), 'Expects string' ); + + if( !o.src.length ) + return ''; + + let result = o.src; + + result = this.refine( result ); + + // if( debug ) + // console.log( 'normalize.refined : ' + result ); + + /* detrailing */ + + if( o.tolerant ) + { + /* remove "/" duplicates */ + result = result.replace( this._delUpDupRegexp, this.upToken ); + } + + let endsWithUp = false; + let beginsWithHere = false; + + /* remove right "/" */ + + if( result !== this.upToken && !_.strEnds( result, this.upToken + this.upToken ) && _.strEnds( result, this.upToken ) ) + { + endsWithUp = true; + result = _.strRemoveEnd( result, this.upToken ); + } + + /* undoting */ + + while( !_.strBegins( result, this.hereUpToken + this.upToken ) && _.strBegins( result, this.hereUpToken ) ) + { + beginsWithHere = true; + result = _.strRemoveBegin( result, this.hereUpToken ); + } + + /* remove second "." */ + + if( result.indexOf( this.hereToken ) !== -1 ) + { + + while( this._delHereRegexp.test( result ) ) + result = result.replace( this._delHereRegexp, function( match, postSlash ) + { + return postSlash || ''; + }); + if( result === '' ) + result = this.upToken; + + } + + /* remove .. */ + + if( result.indexOf( this.downToken ) !== -1 ) + { + + while( this._delDownRegexp.test( result ) ) + result = result.replace( this._delDownRegexp, function( /* match, notBegin, split, preSlash, postSlash */ ) + { + let match = arguments[ 0 ]; + let notBegin = arguments[ 1 ]; + let split = arguments[ 2 ]; + let preSlash = arguments[ 3 ]; + let postSlash = arguments[ 4 ]; + + if( preSlash === '' ) + return notBegin; + if( !notBegin ) + return notBegin + preSlash; + else + return notBegin + ( postSlash || '' ); + }); + + } + + /* nothing left */ + + if( !result.length ) + result = '.'; + + /* dot and trail */ + + if( o.detrailing ) + if( result !== this.upToken && !_.strEnds( result, this.upToken + this.upToken ) ) + result = _.strRemoveEnd( result, this.upToken ); + + if( !o.detrailing && endsWithUp ) + if( result !== this.rootToken ) + result = result + this.upToken; + + if( !o.undoting && beginsWithHere ) + result = this._dot( result ); + + // if( debug ) + // console.log( 'normalize.result : ' + result ); + + return result; +} +_.uri._normalize.defaults = +{ + "src" : null, + "tolerant" : false, + "detrailing" : false, + "undoting" : false +} + +// + + + _.uri.canonize = function canonize( filePath ) +{ + let parent = this.path; + if( _.strIs( filePath ) ) + { + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ); + else + return parent.canonize.call( this, filePath ); + } + _.assert( !!filePath ); + filePath.longPath = parent.canonize.call( this, filePath.longPath ); + return this.str( filePath ); +} + +// + + + _.uri.canonizeTolerant = function canonizeTolerant( src ) +{ + _.assert( _.strIs( src ), 'Expects string' ); + + let result = this._normalize({ src, tolerant : true, detrailing : true, undoting : true }); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( result === this.upToken || _.strEnds( result, this.upToken ) || !_.strEnds( result, this.upToken + this.upToken ) ); + _.assert( result.lastIndexOf( this.upToken + this.hereToken + this.upToken ) === -1 ); + _.assert( !_.strEnds( result, this.upToken + this.hereToken ) ); + + if( Config.debug ) + { + _.assert( !this._delUpDupRegexp.test( result ) ); + } + + return result; +} + +// + + + _.uri.protocolToken = `://`; + +// + + _.uri.portToken = `:`; + +// + + _.uri.userToken = `@`; + +// + + _.uri.tagToken = `!`; + +// + + _.uri.hashToken = `#`; + +// + + _.uri.queryToken = `?`; + +// + + _.uri._delDownRegexp = /((?:.|^))(?:(?:\/\/)|(((?:^|\/))(?!\.\.(?:\/|$))(?:(?!\/).)+\/))\.\.((?:\/|$))/; + +// + + _.uri._delHereRegexp = /\/\.(\/|$)/; + +// + + _.uri._delUpDupRegexp = /\/{2,}/g; + +// + + _.uri.rootToken = `/`; + +// + + _.uri.upToken = `/`; + +// + + _.uri.hereToken = `.`; + +// + + _.uri.downToken = `..`; + +// + + _.uri.hereUpToken = `./`; + +// + + _.uri.downUpToken = `../`; + +// + + _.uri._pathIsGlobRegexp = /(?:[?*]+)|(?:([!?*@+]*)\((.*?(?:\|(.*?))*)\))|(?:\[(.+?)\])|(?:\{(.*)\})|(?:)/; + +// + + + + _.color.strFg = function formatForeground( srcStr, color ) +{ + + if( _.number.is( color ) ) + color = _.color.colorNameNearest( color ); + + _.assert( arguments.length === 2, 'Expects 2 arguments' ); + _.assert( _.strIs( srcStr ), 'Expects string {-srcStr-}' ); + _.assert( _.strIs( color ), 'Expects string {-color-}' ); + + return `❮foreground : ${color}❯${srcStr}❮foreground : default❯`; +} + +// + + + _.color.strBg = function formatBackground( srcStr, color ) +{ + + if( _.number.is( color ) ) + color = _.color.colorNameNearest( color ); + + _.assert( arguments.length === 2, 'Expects 2 arguments' ); + _.assert( _.strIs( srcStr ), 'Expects string {-srcStr-}' ); + _.assert( _.strIs( color ), 'Expects string {-color-}' ); + + return `❮background : ${color}❯${srcStr}❮background : default❯`; +} + +// + + + _.color.rgbaHtmlFrom = function rgbaHtmlFrom( o ) +{ + + if( !_.mapIs( o ) ) + o = { src : arguments[ 0 ], colorMap : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options_( rgbaHtmlFrom, o ); + + let result = this.rgbaHtmlFromTry( o ); + + if( !result ) + debugger; + if( !result ) + throw _.err( `Not color : "${_.entity.exportStringDiagnosticShallow( o.src )}"` ); + + return result; + + // let result; + // + // if( !_.mapIs( o ) ) + // o = { src : arguments[ 0 ], colorMap : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + // + // _.assert( arguments.length === 1, 'Expects single argument' ); + // _.routine.options_( rgnaFrom, arguments ); + // + // if( _.numberIs( o.src ) || _.longIs( o.src ) || ( !_.mapIs( o.src ) && _.object.isBasic( o.src ) ) ) + // return this._rgbaFromNotName( o.src ); + // + // /* */ + // + // if( _.strIs( o.src ) ) + // result = this.fromTable( o ); + // + // if( result ) + // return end(); + // + // /* */ + // + // if( _.strIs( o.src ) ) + // result = _.color.hexToColor( o.src ); + // + // if( result ) + // return end(); + // + // /* */ + // + // _.assertWithoutBreakpoint( 0, 'Unknown color', _.strQuote( o.src ) ); + // + // function end() + // { + // _.assert( _.longIs( result ) ); + // if( result.length !== 4 ) + // result = _.longGrow_( result, result, [ 0, 3 ], 1 ); /* xxx : replace */ + // return result; + // } + +} +_.color.rgbaHtmlFrom.defaults = +{ "src" : null, "colorMap" : null } + +// + + + _.color.rgbaHtmlFromTry = function rgbaHtmlFromTry( o ) +{ + let result; + + if( !_.mapIs( o ) ) + o = { src : arguments[ 0 ] }; + + _.assert( arguments.length === 1 ); + _.routine.options_( rgbaHtmlFromTry, o ); + + if( _.numberIs( o.src ) || _.longIs( o.src ) || ( !_.mapIs( o.src ) && _.object.isBasic( o.src ) ) ) + return this._rgbaFromNotName( o.src ); + + /* */ + + if( _.strIs( o.src ) ) + result = this.fromTable( o ); + + if( result ) + return end(); + + /* */ + + if( _.strIs( o.src ) ) + result = _.color.hexToColor( o.src ); + + if( result ) + return end(); + + if( _.strIs( o.src ) ) + result = _.color.rgbaHtmlToRgba( o.src ); + + if( result ) + return end(); + + if( _.strIs( o.src ) ) + result = _.color.hslaToRgba( o.src ); + + if( result ) + return end(); + + /* */ + + return o.def; + + function end() + { + _.assert( _.longIs( result ) ); + if( result.length !== 4 ) + result = _.longGrow_( result, result, [ 0, 3 ], 1 ); /* xxx : replace */ + return result; + } + +} +_.color.rgbaHtmlFromTry.defaults = +{ "src" : null, "colorMap" : null, "def" : null } + +// + + + _.color.rgbaHtmlToRgba = function rgbaHtmlToRgba( src ) +{ + _.assert( _.strDefined( src ) ); + + let splitted = _.strSplitFast + ({ + src, + delimeter : [ '(', ')', ',' ], + preservingDelimeters : 0, + preservingEmpty : 0 + }) + + if( _.strBegins( splitted[ 0 ], 'rgb' ) ) + { + let result = + [ + parseInt( splitted[ 1 ] ) / 255, + parseInt( splitted[ 2 ] ) / 255, + parseInt( splitted[ 3 ] ) / 255, + 1 + ] + + if( splitted[ 0 ] === 'rgba' ) + result[ 3 ] = Number( splitted[ 4 ] ) + + return result; + } + + return null; +} + +// + + + _.color.rgba.fromHexStr = function fromHexStr( hex ) +{ + let result; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( hex ) ); + + result = /^#?([a-f\d])([a-f\d])([a-f\d])$/i.exec( hex ); + if( result ) + { + result = + [ + parseInt( result[ 1 ], 16 ) / 15, + parseInt( result[ 2 ], 16 ) / 15, + parseInt( result[ 3 ], 16 ) / 15, + ] + return result; + } + + result = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])$/i.exec( hex ); + if( result ) + { + result = + [ + parseInt( result[ 1 ], 16 ) / 15, + parseInt( result[ 2 ], 16 ) / 15, + parseInt( result[ 3 ], 16 ) / 15, + parseInt( result[ 4 ], 16 ) / 15, + ] + return result; + } + + result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec( hex ); + if( result ) + { + result = + [ + parseInt( result[ 1 ], 16 ) / 255, + parseInt( result[ 2 ], 16 ) / 255, + parseInt( result[ 3 ], 16 ) / 255, + ] + return result; + } + + result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec( hex ); + if( result ) + { + result = + [ + parseInt( result[ 1 ], 16 ) / 255, + parseInt( result[ 2 ], 16 ) / 255, + parseInt( result[ 3 ], 16 ) / 255, + parseInt( result[ 4 ], 16 ) / 255, + ] + return result; + } + + return null; +} + +// + + + _.color.hslaToRgba = function hslaToRgba( hsla, result ) +{ + +} + +// + + + _.color._colorDistance = function _colorDistance( c1, c2 ) +{ + _.assert( _.longIs( c1 ) ); + _.assert( _.longIs( c2 ) ); + + let a = c1.slice(); + let b = c2.slice(); + + // function _definedIs( src ) + // { + // return src !== undefined && src !== null && !isNaN( src ) + // } + + for( let i = 0 ; i < 4 ; i++ ) + { + if( !_.numberIsFinite( a[ i ] ) ) + // a[ i ] = _definedIs( b[ i ] ) ? b[ i ] : 1; + a[ i ] = 1; + + if( !_.numberIsFinite( b[ i ] ) ) + // b[ i ] = _definedIs( a[ i ] ) ? a[ i ] : 1; + b[ i ] = 1; + } + + // a[ 3 ] = _definedIs( a[ 3 ] ) ? a[ i ] : 1; + // b[ 3 ] = _definedIs( b[ 3 ] ) ? b[ i ] : 1; + + return Math.pow( a[ 0 ] - b[ 0 ], 2 ) + + Math.pow( a[ 1 ] - b[ 1 ], 2 ) + + Math.pow( a[ 2 ] - b[ 2 ], 2 ) + + Math.pow( a[ 3 ] - b[ 3 ], 2 ) +} + +// + + + _.color._rgbByBitmask = function _rgbByBitmask( src ) +{ + let result = []; + + result[ 0 ] = ( ( src >> 16 ) & 0xff ) / 255; + result[ 1 ] = ( ( src >> 8 ) & 0xff ) / 255; + result[ 2 ] = ( ( src >> 0 ) & 0xff ) / 255; + + return result; +} + +// + + + _.color._rgbaFromNotName = function _rgbaFromNotName( src ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.numberIs( src ) || _.longIs( src ) || _.object.isBasic( src ) ); + + if( _.object.isBasic( src ) ) + { + _.map.assertHasOnly( src, { r : null, g : null, b : null, a : null } ); + let result = []; + result[ 0 ] = src.r === undefined ? 1 : src.r; + result[ 1 ] = src.g === undefined ? 1 : src.g; + result[ 2 ] = src.b === undefined ? 1 : src.b; + result[ 3 ] = src.a === undefined ? 1 : src.a; + return result; + } + + if( _.numberIs( src ) ) + { + let result = this._rgbByBitmask( src ); + return _.longGrow_( result, result, [ 0, 3 ], 1 ); + } + + let result = []; + + /* */ + + for( let r = 0 ; r < src.length ; r++ ) + result[ r ] = Number( src[ r ] ); + + if( result.length < 4 ) + result[ 3 ] = 1; + + /* */ + + return result; +} + +// + + + _.color._colorNameNearest = function _colorNameNearest( color, map ) +{ + let self = this; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( arguments.length === 1 ) + map = _.color.ColorMap; + + _.assert( _.object.isBasic( map ) ); + + if( _.strIs( color ) ) + { + _.assertWithoutBreakpoint( map[ color ], 'Unknown color', _.strQuote( color ) ); + + if( _.objectLike( map[ color ] ) ) + { + _.assert( map[ color ].name ); + return self._colorNameNearest( map[ color ].name, map ); + } + + return color; + } + + color = this._rgbaFromNotName( color ); + + _.assert( color.length === 4 ); + + for( let r = 0 ; r < 4 ; r++ ) + { + color[ r ] = Number( color[ r ] ); + if( color[ r ] < 0 ) + color[ r ] = 0; + else if( color[ r ] > 1 ) + color[ r ] = 1; + } + + // if( color[ 3 ] === undefined ) + // color[ 3 ] = 1; + + /* */ + + let names = Object.keys( map ); + let nearest = names[ 0 ]; + let max = this._colorDistance( map[ names[ 0 ] ], color ); + + if( max === 0 ) + return nearest; + + for( let i = 1; i <= names.length - 1; i++ ) + { + let d = this._colorDistance( map[ names[ i ] ], color ); + if( d < max ) + { + max = d; + nearest = names[ i ]; + } + + if( d === 0 ) + return names[ i ]; + } + + return nearest; +} + +// + + + _.color.colorNameNearest = function colorNameNearest( color ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.strIs( color ) ) + { + let color2 = _.color.hexToColor( color ); + if( color2 ) + color = color2; + } + + try + { + return self._colorNameNearest( color ); + } + catch( err ) + { + return; + } + +} + +// + + + _.color._fromTable = function _fromTable( o ) +{ + let result = o.colorMap[ o.src ]; + + _.routine.assertOptions( _fromTable, o ); + + if( !result ) + result = o.def; + + if( result ) + result = result.slice(); + + return result; +} +_.color._fromTable.defaults = +{ "src" : null, "def" : null, "colorMap" : null } + +// + + + _.color.fromTable = function fromTable( o ) +{ + // let o = _.routineOptionsFromThis( fromTable, this, Self ); + + if( !_.mapIs( o ) ) + o = + { + src : arguments[ 0 ], + def : ( arguments.length > 1 ? arguments[ 1 ] : null ), + colorMap : ( arguments.length > 2 ? arguments[ 2 ] : null ), + } + + let result; + if( !o.colorMap ) + o.colorMap = this.ColorMap; + + _.routine.options_( fromTable, o ); + _.assert( arguments.length <= 3 ); + _.assert( _.strIs( o.src ) ); + + o.src = o.src.toLowerCase(); + o.src = o.src.trim(); + + return this._fromTable( o ); + // return this._fromTable( o.src, o.def, o.colorMap ); +} +_.color.fromTable.defaults = +{ "src" : null, "def" : null, "colorMap" : null } + +// + + + _.color.hexToColor = function hexToColor( hex ) +{ + return _.color.rgba.fromHexStr( hex ); +} + +// + + + + _.color.ColorMap = { + "invisible" : [ 0, 0, 0, 0 ], + "transparent" : [ 1, 1, 1, 0.5 ], + "cyan" : [ 0, 1, 1 ], + "magenta" : [ 1, 0, 1 ], + "maroon" : [ 0.5, 0, 0 ], + "dark green" : [ 0, 0.5, 0 ], + "navy" : [ 0, 0, 0.5 ], + "olive" : [ 0.5, 0.5, 0 ], + "teal" : [ 0, 0.5, 0.5 ], + "bright green" : [ 0.5, 1, 0 ], + "spring green" : [ 0, 1, 0.5 ], + "pink" : [ 1, 0, 0.5 ], + "dark orange" : [ 1, 0.5, 0 ], + "azure" : [ 0, 0.5, 1 ], + "dark blue" : [ 0, 0, 0.63 ], + "brown" : [ 0.65, 0.16, 0.16 ], + "white" : [ 1, 1, 1 ], + "smoke" : [ 0.9, 0.9, 0.9 ], + "silver" : [ 0.75, 0.75, 0.75 ], + "gray" : [ 0.5, 0.5, 0.5 ], + "dim" : [ 0.35, 0.35, 0.35 ], + "black" : [ 0, 0, 0 ], + "yellow" : [ 1, 1, 0 ], + "purple" : [ 0.5, 0, 0.5 ], + "orange" : [ 1, 0.65, 0 ], + "bright blue" : [ 0.68, 0.85, 0.9 ], + "red" : [ 1, 0, 0 ], + "buff" : [ 0.94, 0.86, 0.51 ], + "green" : [ 0, 1, 0 ], + "purplish pink" : [ 0.96, 0.46, 0.56 ], + "blue" : [ 0, 0, 1 ], + "yellowish pink" : [ 1, 0.48, 0.36 ], + "violet" : [ 0.5, 0, 1 ], + "orange yellow" : [ 1, 0.56, 0 ], + "purplish red" : [ 0.7, 0.16, 0.32 ], + "greenish yellow" : [ 0.96, 0.78, 0 ], + "reddish brown" : [ 0.5, 0.1, 0.05 ], + "yellow green" : [ 0.57, 0.6, 0 ], + "yellowish brown" : [ 0.34, 0.2, 0.08 ], + "reddish orange" : [ 0.95, 0.23, 0.07 ], + "olive green" : [ 0.14, 0.17, 0.09 ], + "aquamarine" : [ 0.5, 1, 0.83 ], + "light blue" : [ 0.94, 1, 1 ], + "beige" : [ 0.96, 0.96, 0.86 ], + "bisque" : [ 1, 0.89, 0.77 ], + "chocolate" : [ 0.82, 0.41, 0.12 ], + "coral" : [ 1, 0.5, 0.3 ], + "cornsilk" : [ 1, 0.97, 0.86 ], + "crimson" : [ 0.86, 0.08, 0.23 ], + "gainsboro" : [ 0.86, 0.86, 0.86 ], + "gold" : [ 1, 0.84, 0 ], + "honeydew" : [ 0.94, 1, 0.94 ], + "indigo" : [ 0.29, 0, 0.51 ], + "ivory" : [ 1, 1, 0.94 ], + "khaki" : [ 0.94, 0.9, 0.55 ], + "lavender" : [ 0.9, 0.9, 0.98 ], + "linen" : [ 0.98, 0.94, 0.9 ], + "moccasin" : [ 1, 0.89, 0.71 ], + "orchid" : [ 0.85, 0.44, 0.84 ], + "peru" : [ 0.8, 0.52, 0.25 ], + "plum" : [ 0.87, 0.63, 0.87 ], + "salmon" : [ 0.98, 0.5, 0.45 ], + "sienna" : [ 0.63, 0.32, 0.17 ], + "snow" : [ 1, 0.98, 0.98 ], + "tan" : [ 0.82, 0.7, 0.55 ], + "thistle" : [ 0.85, 0.75, 0.85 ], + "tomato" : [ 1, 0.39, 0.28 ], + "turquoise" : [ 0.25, 0.88, 0.81 ], + "wheat" : [ 0.96, 0.87, 0.7 ], + "moderate pink" : [ 0.93, 0.56, 0.53 ], + "dark pink" : [ 0.78, 0.41, 0.39 ], + "pale pink" : [ 1, 0.8, 0.73 ], + "grayish pink" : [ 0.81, 0.61, 0.56 ], + "pinkish white " : [ 0.98, 0.86, 0.78 ], + "pinkish gray " : [ 0.78, 0.65, 0.59 ], + "vivid red" : [ 0.76, 0, 0.13 ], + "strong red" : [ 0.75, 0.13, 0.2 ], + "deep red" : [ 0.48, 0, 0.11 ], + "very deep red" : [ 0.31, 0, 0.08 ], + "moderate red" : [ 0.67, 0.2, 0.23 ], + "dark red" : [ 0.41, 0.11, 0.14 ], + "very dark red" : [ 0.2, 0.04, 0.09 ], + "light grayish red" : [ 0.69, 0.45, 0.4 ], + "grayish red" : [ 0.55, 0.28, 0.26 ], + "dark grayish red" : [ 0.28, 0.16, 0.16 ], + "blackish red" : [ 0.12, 0.05, 0.07 ], + "reddish gray" : [ 0.55, 0.42, 0.38 ], + "dark reddish gray" : [ 0.32, 0.24, 0.21 ], + "reddish black" : [ 0.12, 0.07, 0.07 ], + "vivid yellowish pink" : [ 1, 0.52, 0.36 ], + "deep yellowish pink" : [ 0.96, 0.29, 0.27 ], + "light yellowish pink" : [ 1, 0.7, 0.55 ], + "moderate yellowish pink" : [ 0.93, 0.58, 0.45 ], + "dark yellowish pink" : [ 0.8, 0.42, 0.36 ], + "pale yellowish pink" : [ 1, 0.78, 0.66 ], + "grayish yellowish pink" : [ 0.83, 0.61, 0.52 ], + "brownish pink" : [ 0.8, 0.6, 0.48 ], + "strong reddish orange" : [ 1, 0.73, 0.38 ], + "deep reddish orange" : [ 0.66, 0.11, 0.07 ], + "moderate reddish orange" : [ 0.83, 0.33, 0.22 ], + "dark reddish orange" : [ 0.61, 0.18, 0.12 ], + "grayish reddish orange" : [ 0.72, 0.36, 0.26 ], + "deep reddish brown" : [ 0.29, 0, 0.02 ], + "light reddish brown" : [ 0.67, 0.4, 0.32 ], + "moderate reddish brown" : [ 0.44, 0.18, 0.15 ], + "dark reddish brown" : [ 0.2, 0.06, 0.07 ], + "light grayish reddish brown" : [ 0.59, 0.42, 0.34 ], + "grayish reddish brown" : [ 0.37, 0.22, 0.19 ], + "dark grayish reddish brown" : [ 0.22, 0.12, 0.11 ], + "vivid orange" : [ 1, 0.41, 0 ], + "brilliant orange" : [ 1, 0.72, 0.25 ], + "strong orange" : [ 1, 0.44, 0.1 ], + "deep orange" : [ 0.76, 0.3, 0.04 ], + "light orange" : [ 1, 0.63, 0.38 ], + "moderate orange" : [ 0.91, 0.47, 0.24 ], + "brownish orange" : [ 0.69, 0.32, 0.14 ], + "strong brown" : [ 0.46, 0.2, 0.07 ], + "deep brown" : [ 0.3, 0.13, 0.05 ], + "light brown" : [ 0.66, 0.4, 0.25 ], + "moderate brown" : [ 0.4, 0.22, 0.14 ], + "dark brown" : [ 0.21, 0.09, 0.05 ], + "light grayish brown" : [ 0.58, 0.42, 0.33 ], + "grayish brown" : [ 0.35, 0.24, 0.19 ], + "dark grayish brown" : [ 0.2, 0.13, 0.1 ], + "light brownish gray" : [ 0.55, 0.43, 0.36 ], + "brownish gray" : [ 0.31, 0.24, 0.2 ], + "brownish black" : [ 0.08, 0.06, 0.04 ], + "brilliant orange yellow" : [ 1, 0.69, 0.18 ], + "strong orange yellow" : [ 1, 0.56, 0.05 ], + "deep orange yellow" : [ 0.84, 0.43, 0 ], + "light orange yellow" : [ 1, 0.73, 0.38 ], + "moderate orange yellow" : [ 0.97, 0.58, 0.24 ], + "dark orange yellow" : [ 0.76, 0.46, 0.16 ], + "pale orange yellow" : [ 1, 0.79, 0.53 ], + "strong yellowish brown" : [ 0.58, 0.31, 0.05 ], + "light yellowish brown" : [ 0.73, 0.55, 0.33 ], + "moderate yellowish brown" : [ 0.49, 0.32, 0.18 ], + "dark yellowish brown" : [ 0.25, 0.15, 0.07 ], + "light grayish yellowish brown" : [ 0.71, 0.53, 0.39 ], + "grayish yellowish brown" : [ 0.47, 0.35, 0.25 ], + "dark grayish yellowish brown" : [ 0.24, 0.17, 0.12 ], + "vivid yellow" : [ 1, 0.7, 0 ], + "brilliant yellow" : [ 1, 0.81, 0.25 ], + "strong yellow" : [ 0.9, 0.62, 0.12 ], + "deep yellow" : [ 0.71, 0.47, 0 ], + "light yellow" : [ 1, 0.83, 0.37 ], + "moderate yellow" : [ 0.84, 0.62, 0.25 ], + "dark yellow" : [ 0.69, 0.49, 0.17 ], + "pale yellow" : [ 1, 0.86, 0.55 ], + "grayish yellow" : [ 0.81, 0.64, 0.38 ], + "dark grayish yellow" : [ 0.64, 0.49, 0.27 ], + "yellowish white" : [ 1, 0.89, 0.72 ], + "yellowish gray" : [ 0.79, 0.66, 0.52 ], + "light olive brown" : [ 0.58, 0.36, 0.04 ], + "moderate olive brown" : [ 0.39, 0.25, 0.06 ], + "dark olive brown" : [ 0.19, 0.13, 0.07 ], + "vivid greenish yellow" : [ 0.96, 0.78, 0 ], + "brilliant greenish yellow" : [ 1, 0.86, 0.2 ], + "strong greenish yellow" : [ 0.8, 0.66, 0.09 ], + "deep greenish yellow" : [ 0.62, 0.51, 0 ], + "light greenish yellow" : [ 1, 0.87, 0.35 ], + "moderate greenish yellow" : [ 0.77, 0.64, 0.24 ], + "dark greenish yellow" : [ 0.61, 0.51, 0.15 ], + "pale greenish yellow" : [ 1, 0.87, 0.52 ], + "grayish greenish yellow" : [ 0.77, 0.65, 0.37 ], + "light olive" : [ 0.52, 0.42, 0.13 ], + "moderate olive" : [ 0.37, 0.29, 0.06 ], + "dark olive" : [ 0.21, 0.17, 0.07 ], + "light grayish olive" : [ 0.55, 0.45, 0.29 ], + "grayish olive" : [ 0.32, 0.27, 0.17 ], + "dark grayish olive" : [ 0.17, 0.15, 0.09 ], + "light olive gray" : [ 0.53, 0.45, 0.35 ], + "olive gray" : [ 0.3, 0.26, 0.2 ], + "olive black" : [ 0.07, 0.1, 0.06 ], + "brilliant yellow green" : [ 0.81, 0.82, 0.23 ], + "strong yellow green" : [ 0.5, 0.56, 0.09 ], + "deep yellow green" : [ 0.26, 0.37, 0.09 ], + "light yellow green" : [ 0.86, 0.83, 0.42 ], + "moderate yellow green" : [ 0.55, 0.54, 0.25 ], + "pale yellow green" : [ 0.94, 0.84, 0.6 ], + "grayish yellow green" : [ 0.56, 0.52, 0.36 ], + "strong olive green" : [ 0.04, 0.27, 0 ], + "deep olive green" : [ 0.08, 0.14, 0 ], + "moderate olive green" : [ 0.26, 0.29, 0.11 ], + "grayish olive green" : [ 0.28, 0.27, 0.18 ], + "dark grayish olive green" : [ 0.15, 0.15, 0.1 ], + "vivid yellowish green" : [ 0.22, 0.6, 0.19 ], + "brilliant yellowish green" : [ 0.55, 0.8, 0.37 ], + "strong yellowish green" : [ 0.28, 0.52, 0.19 ], + "deep yellowish green" : [ 0, 0.33, 0.12 ], + "very deep yellowish green" : [ 0, 0.16, 0 ], + "very light yellowish green" : [ 0.78, 0.87, 0.56 ], + "light yellowish green" : [ 0, 0.48, 0.65 ], + "moderate yellowish green" : [ 0.4, 0.5, 0.29 ], + "dark yellowish green" : [ 0.19, 0.29, 0.15 ], + "very dark yellowish green" : [ 0.07, 0.15, 0.07 ], + "vivid green" : [ 0, 0.49, 0.2 ], + "brilliant green" : [ 0.28, 0.65, 0.42 ], + "strong green" : [ 0, 0.42, 0.24 ], + "deep green" : [ 0, 0.27, 0.14 ], + "very light green" : [ 0.6, 0.78, 0.58 ], + "light green" : [ 0.44, 0.61, 0.43 ], + "moderate green" : [ 0.22, 0.4, 0.27 ], + "very dark green" : [ 0.09, 0.15, 0.11 ], + "very pale green" : [ 0.85, 0.87, 0.73 ], + "pale green" : [ 0.55, 0.57, 0.48 ], + "grayish green" : [ 0.34, 0.37, 0.31 ], + "dark grayish green" : [ 0.19, 0.22, 0.19 ], + "blackish green" : [ 0.08, 0.09, 0.07 ], + "greenish white" : [ 0.96, 0.9, 0.8 ], + "light greenish gray" : [ 0.73, 0.69, 0.59 ], + "greenish gray" : [ 0.48, 0.46, 0.4 ], + "dark greenish gray" : [ 0.27, 0.26, 0.23 ], + "greenish black" : [ 0.09, 0.08, 0.07 ], + "vivid bluish green" : [ 0, 0.51, 0.43 ], + "brilliant bluish green" : [ 0, 0.61, 0.46 ], + "strong bluish green" : [ 0, 0.43, 0.36 ], + "deep bluish green" : [ 0, 0.22, 0.17 ], + "very light bluish green" : [ 0.63, 0.84, 0.71 ], + "light bluish green" : [ 0.4, 0.62, 0.52 ], + "moderate bluish green" : [ 0.18, 0.4, 0.34 ], + "dark bluish green" : [ 0, 0.23, 0.2 ], + "very dark bluish green" : [ 0, 0.11, 0.09 ], + "vivid greenish blue" : [ 0, 0.48, 0.65 ], + "brilliant greenish blue" : [ 0.16, 0.55, 0.61 ], + "strong greenish blue" : [ 0, 0.4, 0.49 ], + "deep greenish blue" : [ 0, 0.48, 0.65 ], + "very light greenish blue" : [ 0.64, 0.78, 0.75 ], + "light greenish blue" : [ 0.39, 0.6, 0.62 ], + "moderate greenish blue" : [ 0.19, 0.38, 0.42 ], + "dark greenish blue" : [ 0, 0.22, 0.25 ], + "very dark greenish blue" : [ 0.01, 0.13, 0.15 ], + "vivid blue,ultramarine" : [ 0, 0.49, 0.68 ], + "brilliant blue,celestial blue" : [ 0.26, 0.52, 0.71 ], + "strong blue,bright blue" : [ 0, 0.33, 0.54 ], + "deep blue,royal blue" : [ 0, 0.18, 0.33 ], + "very light blue" : [ 0.65, 0.74, 0.84 ], + "sky blue" : [ 0.42, 0.57, 0.69 ], + "moderate blue,cerulean blue" : [ 0.22, 0.34, 0.47 ], + "dark blue,navy blue" : [ 0, 0.13, 0.22 ], + "very pale blue,cloud blue" : [ 0.76, 0.79, 0.79 ], + "pale blue,alice blue" : [ 0.57, 0.57, 0.57 ], + "grayish blue,slate blue" : [ 0.29, 0.33, 0.36 ], + "dark grayish blue" : [ 0.17, 0.2, 0.22 ], + "blackish blue" : [ 0.09, 0.1, 0.12 ], + "bluish white" : [ 0.98, 0.87, 0.81 ], + "light bluish gray" : [ 0.75, 0.68, 0.63 ], + "bluish gray" : [ 0.49, 0.45, 0.43 ], + "dark bluish gray" : [ 0.27, 0.27, 0.27 ], + "bluish black" : [ 0.08, 0.09, 0.1 ], + "vivid purplish blue" : [ 0.13, 0.08, 0.37 ], + "brilliant purplish blue" : [ 0.38, 0.39, 0.61 ], + "strong purplish blue" : [ 0.28, 0.26, 0.54 ], + "deep purplish blue" : [ 0.1, 0.08, 0.25 ], + "very light purplish blue" : [ 0.73, 0.67, 0.78 ], + "light purplish blue" : [ 0.51, 0.49, 0.64 ], + "moderate purplish blue" : [ 0.26, 0.24, 0.39 ], + "dark purplish blue" : [ 0.1, 0.09, 0.16 ], + "very pale purplish blue" : [ 0.8, 0.73, 0.77 ], + "pale purplish blue" : [ 0.54, 0.5, 0.56 ], + "grayish purplish blue" : [ 0.25, 0.24, 0.32 ], + "vivid violet" : [ 0.53, 0.29, 0.68 ], + "brilliant violet" : [ 0.46, 0.36, 0.6 ], + "strong violet" : [ 0.33, 0.22, 0.48 ], + "deep violet" : [ 0.14, 0.04, 0.21 ], + "very light violet" : [ 0.93, 0.75, 0.95 ], + "light violet" : [ 0.53, 0.42, 0.6 ], + "moderate violet" : [ 0.33, 0.22, 0.39 ], + "dark violet" : [ 0.13, 0.07, 0.17 ], + "very pale violet" : [ 0.85, 0.69, 0.75 ], + "pale violet" : [ 0.58, 0.48, 0.55 ], + "grayish violet" : [ 0.27, 0.22, 0.29 ], + "vivid purple" : [ 0.58, 0.2, 0.57 ], + "brilliant purple" : [ 0.87, 0.5, 0.8 ], + "strong purple" : [ 0.5, 0.24, 0.46 ], + "deep purple" : [ 0.33, 0.1, 0.31 ], + "very deep purple" : [ 0.2, 0.04, 0.21 ], + "very light purple" : [ 0.89, 0.66, 0.75 ], + "light purple" : [ 0.73, 0.5, 0.64 ], + "moderate purple" : [ 0.5, 0.28, 0.44 ], + "dark purple" : [ 0.28, 0.16, 0.25 ], + "very dark purple" : [ 0.14, 0.05, 0.13 ], + "very pale purple" : [ 0.9, 0.73, 0.76 ], + "pale purple" : [ 0.68, 0.52, 0.55 ], + "grayish purple" : [ 0.45, 0.32, 0.36 ], + "dark grayish purple" : [ 0.27, 0.18, 0.21 ], + "blackish purple" : [ 0.11, 0.06, 0.09 ], + "purplish white" : [ 0.98, 0.86, 0.78 ], + "light purplish gray" : [ 0.78, 0.66, 0.62 ], + "purplish gray" : [ 0.53, 0.44, 0.42 ], + "dark purplish gray" : [ 0.34, 0.25, 0.26 ], + "purplish black" : [ 0.11, 0.07, 0.09 ], + "vivid reddish purple" : [ 0.49, 0, 0.35 ], + "strong reddish purple" : [ 0.6, 0.21, 0.42 ], + "deep reddish purple" : [ 0.39, 0.07, 0.29 ], + "very deep reddish purple" : [ 0.28, 0.03, 0.21 ], + "light reddish purple" : [ 0.73, 0.42, 0.54 ], + "moderate reddish purple" : [ 0.55, 0.27, 0.4 ], + "dark reddish purple" : [ 0.31, 0.15, 0.23 ], + "very dark reddish purple" : [ 0.15, 0.04, 0.12 ], + "pale reddish purple" : [ 0.67, 0.46, 0.5 ], + "grayish reddish purple" : [ 0.49, 0.3, 0.36 ], + "brilliant purplish pink" : [ 1, 0.59, 0.73 ], + "deep purplish pink" : [ 0.92, 0.32, 0.52 ], + "light purplish pink" : [ 1, 0.66, 0.69 ], + "moderate purplish pink" : [ 0.89, 0.5, 0.56 ], + "dark purplish pink" : [ 0.78, 0.4, 0.45 ], + "pale purplish pink" : [ 0.99, 0.74, 0.73 ], + "grayish purplish pink" : [ 0.8, 0.57, 0.58 ], + "vivid purplish red" : [ 0.84, 0.15, 0.36 ], + "deep purplish red" : [ 0.44, 0, 0.21 ], + "very deep purplish red" : [ 0.28, 0, 0.15 ], + "moderate purplish red" : [ 0.65, 0.22, 0.33 ], + "dark purplish red" : [ 0.36, 0.12, 0.19 ], + "very dark purplish red" : [ 0.16, 0.03, 0.1 ], + "light grayish purplish red" : [ 0.7, 0.44, 0.44 ], + "grayish purplish red" : [ 0.55, 0.28, 0.32 ], + "light gray" : [ 0.76, 0.66, 0.58 ], + "medium gray" : [ 0.51, 0.44, 0.4 ], + "dark gray" : [ 0.29, 0.26, 0.24 ], + "bright black" : [ 0.5, 0.5, 0.5 ], + "dark magenta" : [ 0.5, 0, 0.5 ], + "dark cyan" : [ 0, 0.5, 0.5 ], + "dark white" : [ 0.75, 0.75, 0.75 ], + "bright white" : [ 1, 1, 1 ], + "bright red" : [ 1, 0, 0 ], + "bright yellow" : [ 1, 1, 0 ], + "bright cyan" : [ 0, 1, 1 ], + "bright magenta" : [ 1, 0, 1 ], + "dark black" : [ 0, 0, 0 ] +}; + +// + + + + _.Logger.TransformCssStylingToDirectives = function TransformCssStylingToDirectives( input ) +{ + //https://developers.google.com/web/tools/chrome-devtools/console/console-write#styling_console_output_with_css + + if( !_.strHas( input[ 0 ], '%c' ) ) + return input; + + let result = [ '' ]; + + let splitted = _.strSplitFast + ({ + src : input[ 0 ], + delimeter : '%c', + preservingEmpty : 0, + preservingDelimeters : 0 + }); + + splitted.forEach( ( chunk, i ) => + { + let styles = input[ i + 1 ]; + + if( styles ) + { + let splits = _.strSplitFast + ({ + src : styles, + delimeter : [ ';', ':' ], + preservingEmpty : 0, + preservingDelimeters : 0 + }); + + if( splits.length > 1 ) + for( let i = 0; i < splits.length; i += 2 ) + { + let key = _.strStrip( splits[ i ] ); + let value = _.strStrip( splits[ i + 1 ] ); + + if( value === 'none' ) + continue; + + if( key === 'color' ) + { + value = _.color.rgbaHtmlFrom( value ); + value = _.color.colorNameNearest( value ); + chunk = _.color.strFg( chunk, value ); + } + else if( key === 'background' ) + { + value = _.color.rgbaHtmlFrom( value ); + value = _.color.colorNameNearest( value ) + chunk = _.color.strBg( chunk, value ); + } + else if( key === 'text-decoration' ) + { + chunk = `❮${value} : true❯${chunk}❮${value} : false❯` + } + } + } + + result[ 0 ] += chunk; + }) + + if( !result[ 0 ] ) + return input; + + result.push( ... input.slice( splitted.length + 1 ) ); + + return result; +} + +// + + + + + + + + let StarterExtension = + { + + debuggerEnabled : _starter_.debug, + + } + + Object.assign( _starter_, StarterExtension ); + +; + +/* */ /* end of extract */ })(); + + +/* */ /* begin of globing */ ( function _proceduring_() { + + + + 'use strict'; + + const _global = _global_; + let _starter_ = _global._starter_ = _global._starter_ || Object.create( null ); + let _ = _starter_; + + // + + function TokensSyntax() + { + let result = + { + idToValue : null, + idToName : [], + nameToId : {}, + alternatives : {}, + } + Object.setPrototypeOf( result, TokensSyntax ); + return result; + } + + // + +; + + + + _.array.likeResizable = function likeResizable( src ) +{ + return _.array.is( src ); +} + +// + + + _.arrayLikeResizable = _.array.likeResizable.bind( _.array ) + /* _.arrayLikeResizable = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.map.extend = function extend( dstMap, srcMap ) +{ + + if( dstMap === null ) + dstMap = Object.create( null ); + + if( arguments.length === 2 ) + { + let srcProto = Object.getPrototypeOf( srcMap ); + if( srcProto === null || srcProto === Object.prototype ) + return Object.assign( dstMap, srcMap ); + } + + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + _.assert( this.like( dstMap ), () => `Expects dstMap::${this.NamespaceName} as the first argument` ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + let srcMap = arguments[ a ]; + + _.assert( !_.primitive.is( srcMap ), 'Expects non-primitive' ); + + let srcProto = Object.getPrototypeOf( srcMap ); + if( srcProto === null || srcProto === Object.prototype ) + Object.assign( dstMap, srcMap ); + else + this._extendWithProps( dstMap, srcMap ); + + } + + return dstMap; +} + +// + + + _.map.supplement = function supplement( dstMap, srcMap ) +{ + if( dstMap === null && arguments.length === 2 ) + return Object.assign( Object.create( null ), srcMap ); + if( dstMap === null ) + dstMap = Object.create( null ); + + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + _.assert( this.like( dstMap ), () => `Expects dstMap::${this.NamespaceName} as the first argument` ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + srcMap = arguments[ a ]; + this._supplementWithProps( dstMap, srcMap ); + } + + return dstMap +} + +// + + + _.mapExtend = _.map.extend.bind( _.map ) + _.mapSupplement = _.map.supplement.bind( _.map ) + /* _.mapExtend = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + /* _.mapSupplement = function () { [native code] } + +// + + */ /* Dmytro : binded, source code is not available */ + + _.vectorize = ( function() { + + const _vectorize_head = function vectorize_head( routine, args ) + { + let o = args[ 0 ]; + + if( args.length === 2 ) + o = { routine : args[ 0 ], select : args[ 1 ] } + else if( _.routine.is( o ) || _.strIs( o ) ) + o = { routine : args[ 0 ] } + + _.routine.options( routine, o ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.routine.is( o.routine ) || _.strIs( o.routine ) || _.strsAreAll( o.routine ), () => 'Expects routine {-o.routine-}, but got ' + o.routine ); + _.assert( args.length === 1 || args.length === 2 ); + _.assert( o.select >= 1 || _.strIs( o.select ) || _.argumentsArray.like( o.select ), () => 'Expects {-o.select-} as number >= 1, string or array, but got ' + o.select ); + + return o; + } + + const _vectorize_body = function vectorize_body( o ) + { + + _.routine.assertOptions( vectorize_body, arguments ); + + if( _.argumentsArray.like( o.routine ) && o.routine.length === 1 ) + o.routine = o.routine[ 0 ]; + + let routine = o.routine; + let propertyCondition = o.propertyCondition; + let bypassingFilteredOut = o.bypassingFilteredOut; + let bypassingEmpty = o.bypassingEmpty; + let vectorizingArray = o.vectorizingArray; + let vectorizingMapVals = o.vectorizingMapVals; + let vectorizingMapKeys = o.vectorizingMapKeys; + let vectorizingContainerAdapter = o.vectorizingContainerAdapter; + let unwrapingContainerAdapter = o.unwrapingContainerAdapter; + let head = null; + let select = o.select === null ? 1 : o.select; + let selectAll = o.select === Infinity; + let multiply = select > 1 ? multiplyReally : multiplyNo; + + routine = routineNormalize( routine ); + + _.assert( _.routine.is( routine ), () => 'Expects routine {-o.routine-}, but got ' + routine ); + + /* */ + + let resultRoutine = vectorizeArray; + + if( _.number.is( select ) ) + { + + if( !vectorizingArray && !vectorizingMapVals && !vectorizingMapKeys ) + resultRoutine = routine; + else if( propertyCondition ) + resultRoutine = vectorizeWithFilters; + else if( vectorizingMapKeys ) + { + + if( vectorizingMapVals ) + { + _.assert( select === 1, 'Only single argument is allowed if {-o.vectorizingMapKeys-} and {-o.vectorizingMapVals-} are enabled.' ); + resultRoutine = vectorizeMapWithKeysOrArray; + } + else + { + resultRoutine = vectorizeKeysOrArray; + } + + } + else if( !vectorizingArray || vectorizingMapVals ) + resultRoutine = vectorizeMapOrArray; + else if( multiply === multiplyNo ) + resultRoutine = vectorizeArray; + else + resultRoutine = vectorizeArrayMultiplying; + + } + else + { + _.assert( multiply === multiplyNo ); + if( routine.head ) + { + head = routine.head; + routine = routine.body; + } + if( propertyCondition ) + { + _.assert( 0, 'not implemented' ); + } + else if( vectorizingArray || !vectorizingMapVals ) + { + if( _.strIs( select ) ) + resultRoutine = vectorizeForOptionsMap; + else + resultRoutine = vectorizeForOptionsMapForKeys; + } + else _.assert( 0, 'not implemented' ); + } + + /* */ + + resultRoutine.vectorized = o; + + /* */ + + _.routine.extend( resultRoutine, routine ); + return resultRoutine; + + /* + vectorizeWithFilters : multiply + array/map vectorizing + filter + vectorizeArray : array vectorizing + vectorizeArrayMultiplying : multiply + array vectorizing + vectorizeMapOrArray : multiply + array/map vectorizing + */ + + /* - */ + + function routineNormalize( routine ) + { + + if( _.strIs( routine ) ) + { + return function methodCall() + { + _.assert( _.routine.is( this[ routine ] ), () => 'Context ' + _.entity.exportStringDiagnosticShallow( this ) + ' does not have routine ' + routine ); + return this[ routine ].apply( this, arguments ); + } + } + else if( _.argumentsArray.like( routine ) ) + { + _.assert( routine.length === 2 ); + return function methodCall() + { + let c = this[ routine[ 0 ] ]; + _.assert( _.routine.is( c[ routine[ 1 ] ] ), () => 'Context ' + _.entity.exportStringDiagnosticShallow( c ) + ' does not have routine ' + routine ); + return c[ routine[ 1 ] ].apply( c, arguments ); + } + } + + return routine; + } + + /* - */ + + function multiplyNo( args ) + { + return args; + } + + /* - */ + + function multiplyReally( args ) + { + let length, keys; + + args = [ ... args ]; + + if( selectAll ) + select = args.length; + + _.assert( args.length === select, () => 'Expects ' + select + ' arguments, but got ' + args.length ); + + for( let d = 0 ; d < select ; d++ ) + { + if( vectorizingArray && _.argumentsArray.like( args[ d ] ) ) + { + length = args[ d ].length; + break; + } + else if( vectorizingArray && _.set.like( args[ d ] ) ) + { + length = args[ d ].size; + break; + } + else if( vectorizingContainerAdapter && _.containerAdapter.is( args[ d ] ) ) + { + length = args[ d ].length; + break; + } + else if( vectorizingMapVals && _.aux.is( args[ d ] ) ) + { + keys = _.props.onlyOwnKeys( args[ d ] ); + break; + } + } + + if( length !== undefined ) + { + for( let d = 0 ; d < select ; d++ ) + { + if( vectorizingMapVals ) + _.assert( !_.mapIs( args[ d ] ), () => 'Arguments should have only arrays or only maps, but not both. Incorrect argument : ' + args[ d ] ); + else if( vectorizingMapKeys && _.mapIs( args[ d ] ) ) + continue; + args[ d ] = _.multiple( args[ d ], length ); + } + + } + else if( keys !== undefined ) + { + for( let d = 0 ; d < select ; d++ ) + if( _.mapIs( args[ d ] ) ) + { + _.assert( _.arraySet.identical( _.props.onlyOwnKeys( args[ d ] ), keys ), () => 'Maps should have same keys : ' + keys ); + } + else + { + if( vectorizingArray ) + _.assert( !_.argumentsArray.like( args[ d ] ), () => 'Arguments should have only arrays or only maps, but not both. Incorrect argument : ' + args[ d ] ); + let arg = Object.create( null ); + _.mapSetWithKeys( arg, keys, args[ d ] ); + args[ d ] = arg; + } + } + + return args; + } + + /* - */ + + function vectorizeArray() + { + if( bypassingEmpty && !arguments.length ) + return []; + + let args = arguments; + let src = args[ 0 ]; + + if( _.arrayIs( src ) ) /* Dmytro : arrayLike returns true for instances of containerAdapter */ + { + let args2 = [ ... args ]; + let result = _.long.makeEmpty( src ); + let append = _.long.appender( result ); + let each = _.long.eacher( src ); + each( ( e ) => + { + args2[ 0 ] = e; + append( routine.apply( this, args2 ) ); + }); + return result; + } + else if( _.set.like( src ) ) /* qqq : cover please */ + { + let args2 = [ ... args ]; + let result = new Set; + for( let e of src ) + { + args2[ 0 ] = e; + result.add( routine.apply( this, args2 ) ); + } + return result; + } + else if( vectorizingContainerAdapter && _.containerAdapter.is( src ) ) + { + let args2 = [ ... args ]; + let result = src.filter( ( e ) => + { + args2[ 0 ] = e; + return routine.apply( this, args2 ); + }); + if( unwrapingContainerAdapter ) + return result.original; + else + return result; + } + + return routine.apply( this, args ); + } + + /* - */ + + function vectorizeArrayMultiplying() + { + if( bypassingEmpty && !arguments.length ) + return []; + + let args = multiply( arguments ); + let src = args[ 0 ]; + + if( _.argumentsArray.like( src ) ) + { + + let args2 = [ ... args ]; + let result = _.long.makeEmpty( src ); + let append = _.long.appender( result ); + let each = _.long.eacher( src ); + each( ( e, r ) => + { + for( let m = 0 ; m < select ; m++ ) + args2[ m ] = args[ m ][ r ]; /* zzz qqq : use _.long.get */ + append( routine.apply( this, args2 ) ); + }); + return result; + } + + return routine.apply( this, args ); + } + + /* - */ + + function vectorizeForOptionsMap( srcMap ) + { + if( bypassingEmpty && !arguments.length ) + return []; + + let src = srcMap[ select ]; + let args = [ ... arguments ]; + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.argumentsArray.like( src ) ) + { + if( head ) + { + args = head( routine, args ); + _.assert( _.arrayLikeResizable( args ) ); + } + + let result = _.long.makeEmpty( src ); + let append = _.long.appender( result ); + let each = _.long.eacher( src ); + each( ( e ) => + { + args[ 0 ] = _.props.extend( null, srcMap ); + args[ 0 ][ select ] = e; + append( routine.apply( this, args ) ); + }); + return result; + + } + else if( _.set.like( src ) ) /* qqq : cover */ + { + if( head ) + { + args = head( routine, args ); + _.assert( _.arrayLikeResizable( args ) ); + } + let result = new Set; + for( let e of src ) + { + args[ 0 ] = _.props.extend( null, srcMap ); + args[ 0 ][ select ] = e; + result.add( routine.apply( this, args ) ); + } + return result; + } + else if( vectorizingContainerAdapter && _.containerAdapter.is( src ) ) /* qqq : cover */ + { + if( head ) + { + args = head( routine, args ); + _.assert( _.arrayLikeResizable( args ) ); + } + result = src.filter( ( e ) => + { + args[ 0 ] = _.props.extend( null, srcMap ); + args[ 0 ][ select ] = e; + return routine.apply( this, args ); + }); + if( unwrapingContainerAdapter ) + return result.original; + else + return result; + } + + return routine.apply( this, arguments ); + } + + /* - */ + + function vectorizeForOptionsMapForKeys() + { + let result = []; + + if( bypassingEmpty && !arguments.length ) + return result; + + for( let i = 0; i < o.select.length; i++ ) + { + select = o.select[ i ]; + result[ i ] = vectorizeForOptionsMap.apply( this, arguments ); + } + return result; + } + + /* - */ + + function vectorizeMapOrArray() + { + if( bypassingEmpty && !arguments.length ) + return []; + + let args = multiply( arguments ); + let src = args[ 0 ]; + + if( vectorizingArray && _.argumentsArray.like( src ) ) + { + + let args2 = [ ... args ]; + let result = _.long.makeEmpty( src ); + let append = _.long.appender( result ); + let each = _.long.eacher( src ); + each( ( e, r ) => + { + + for( let m = 0 ; m < select ; m++ ) + args2[ m ] = args[ m ][ r ]; /* qqq zzz : use _.long.get? */ + + append( routine.apply( this, args2 ) ); + }); + return result; + } + else if( vectorizingMapVals && _.mapIs( src ) ) + { + let args2 = [ ... args ]; + let result = Object.create( null ); + for( let r in src ) + { + for( let m = 0 ; m < select ; m++ ) + args2[ m ] = args[ m ][ r ]; + + result[ r ] = routine.apply( this, args2 ); + } + return result; + } + + return routine.apply( this, arguments ); + } + + /* - */ + + function vectorizeMapWithKeysOrArray() + { + if( bypassingEmpty && !arguments.length ) + return []; + + let args = multiply( arguments ); + let srcs = args[ 0 ]; + + _.assert( args.length === select, () => 'Expects ' + select + ' arguments but got : ' + args.length ); + + if( vectorizingMapKeys && vectorizingMapVals &&_.mapIs( srcs ) ) + { + let result = Object.create( null ); + for( let s in srcs ) + { + let val = routine.call( this, srcs[ s ] ); + let key = routine.call( this, s ); + result[ key ] = val; + } + return result; + } + else if( vectorizingArray && _.argumentsArray.like( srcs ) ) + { + let result = []; + for( let s = 0 ; s < srcs.length ; s++ ) + result[ s ] = routine.call( this, srcs[ s ] ); + return result; + } + + return routine.apply( this, arguments ); + } + + /* - */ + + function vectorizeWithFilters( src ) + { + + _.assert( 0, 'not tested' ); /* qqq : cover please */ + _.assert( arguments.length === 1, 'Expects single argument' ); + + let args = multiply( arguments ); + + if( vectorizingArray && _.argumentsArray.like( src ) ) + { + args = [ ... args ]; + throw _.err( 'not tested' ); /* cover please */ + + let result = _.long.makeEmpty( src ); + let append = _.long.appender( result ); + let each = _.long.eacher( src ); + each( ( e, r ) => + { + if( propertyCondition( e, r, src ) ) + { + args[ 0 ] = e; + append( routine.apply( this, args ) ); + } + else if( bypassingFilteredOut ) + { + append( e ); + } + + args2[ 0 ] = e; + append( routine.apply( this, args2 ) ); + }); + return result; + + } + else if( vectorizingMapVals && _.mapIs( src ) ) + { + args = [ ... args ]; + let result = Object.create( null ); + throw _.err( 'not tested' ); /* qqq : cover please */ + for( let r in src ) + { + if( propertyCondition( src[ r ], r, src ) ) + { + args[ 0 ] = src[ r ]; + result[ r ] = routine.apply( this, args ); + } + else if( bypassingFilteredOut ) + { + result[ r ] = src[ r ]; + } + } + return result; + } + + return routine.call( this, src ); + } + + /* - */ + + function vectorizeKeysOrArray() + { + if( bypassingEmpty && !arguments.length ) + return []; + + // let args = multiply( _.originalsFromAdaptersInplace( arguments ) ); + let args = multiply( arguments ); + let src = args[ 0 ]; + let args2, result, map, mapIndex, arr; + + _.assert( args.length === select, () => 'Expects ' + select + ' arguments but got : ' + args.length ); + + if( vectorizingMapKeys ) + { + for( let d = 0; d < select; d++ ) + { + if( vectorizingArray && _.argumentsArray.like( args[ d ] ) ) + arr = args[ d ]; + else if( _.mapIs( args[ d ] ) ) + { + _.assert( map === undefined, () => 'Arguments should have only single map. Incorrect argument : ' + args[ d ] ); + map = args[ d ]; + mapIndex = d; + } + } + } + + if( map ) + { + result = Object.create( null ); + args2 = [ ... args ]; + + if( vectorizingArray && _.argumentsArray.like( arr ) ) + { + for( let i = 0; i < arr.length; i++ ) + { + for( let m = 0 ; m < select ; m++ ) + args2[ m ] = args[ m ][ i ]; + + for( let k in map ) + { + args2[ mapIndex ] = k; + let key = routine.apply( this, args2 ); + result[ key ] = map[ k ]; + } + } + } + else + { + for( let k in map ) + { + args2[ mapIndex ] = k; + let key = routine.apply( this, args2 ); + result[ key ] = map[ k ]; + } + } + + return result; + } + else if( vectorizingArray && _.argumentsArray.like( src ) ) + { + + let args2 = [ ... args ]; + let result = _.long.makeEmpty( src ); + let append = _.long.appender( result ); + let each = _.long.eacher( src ); + each( ( e, r ) => + { + for( let m = 0 ; m < select ; m++ ) + args2[ m ] = args[ m ][ r ]; /* qqq zzz : use _.long.get */ + append( routine.apply( this, args2 ) ); + }); + return result; + + } + + return routine.apply( this, arguments ); + } + + } + _vectorize_body.defaults = { + "routine" : null, + "propertyCondition" : null, + "bypassingFilteredOut" : 1, + "bypassingEmpty" : 0, + "vectorizingArray" : 1, + "vectorizingMapVals" : 0, + "vectorizingMapKeys" : 0, + "vectorizingContainerAdapter" : 0, + "unwrapingContainerAdapter" : 0, + "select" : 1 + } + + const _vectorize_ = _.routine.unite + ({ + head : _vectorize_head, + body : _vectorize_body, + }); + + return _vectorize_; +})(); +_.vectorize.defaults = +{ + "routine" : null, + "propertyCondition" : null, + "bypassingFilteredOut" : 1, + "bypassingEmpty" : 0, + "vectorizingArray" : 1, + "vectorizingMapVals" : 0, + "vectorizingMapKeys" : 0, + "vectorizingContainerAdapter" : 0, + "unwrapingContainerAdapter" : 0, + "select" : 1 +} + +// + + + _.strsAreAll = function strsAreAll( src ) +{ + _.assert( arguments.length === 1 ); + + if( _.argumentsArray.like( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( !_.strIs( src[ s ] ) ) + return false; + return true; + } + + return _.strIs( src ); +} + +// + + + _.strReplaceAll = function strReplaceAll( src, ins, sub ) +{ + let o; + let foundArray = []; + + if( arguments.length === 3 ) + { + o = { src }; + o.dictionary = [ [ ins, sub ] ]; + } + else if( arguments.length === 2 ) + { + o = { src : arguments[ 0 ], dictionary : arguments[ 1 ] }; + } + else if( arguments.length === 1 ) + { + o = arguments[ 0 ]; + } + else + { + _.assert( 0, 'Expects at least single options map {-o-} or a combination of arguments : src-dictionary, src-ins-sub. ' ); + } + + /* verify */ + + _.routine.options_( strReplaceAll, o ); + _.assert( _.strIs( o.src ) ); + + _._strReplaceMapPrepare( o ); + + /* */ + + let found = _.strFindAll( o.src, o.ins ); + let result = []; + let index = 0; + + found.forEach( ( it ) => + { + let sub = o.sub[ it.tokenId ]; + + let unknown = o.src.substring( index, it.charsRangeLeft[ 0 ] ); + if( unknown && o.onUnknown ) + unknown = o.onUnknown( unknown, it, o ); + + if( unknown !== '' ) + result.push( unknown ); + + if( _.routineIs( sub ) ) + sub = sub.call( o, it.match, it ); + + if( sub !== '' ) + result.push( sub ); + + index = it.charsRangeLeft[ 1 ]; + }); + + result.push( o.src.substring( index, o.src.length ) ); + + if( o.joining ) + result = result.join( '' ) + + return result; +} +_.strReplaceAll.defaults = +{ + "src" : null, + "dictionary" : null, + "ins" : null, + "sub" : null, + "joining" : 1, + "onUnknown" : null +} + +// + + + _.strFindAll = function strFindAll( src, ins ) +{ + let o; + + if( arguments.length === 2 ) + { + o = { src : arguments[ 0 ], ins : arguments[ 1 ] }; + } + else if( arguments.length === 1 ) + { + o = arguments[ 0 ]; + } + + if( _.strIs( o.ins ) || _.regexpIs( o.ins ) ) + o.ins = [ o.ins ]; + + /* */ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( o.src ) ); + _.assert( _.argumentsArray.like( o.ins ) || _.object.isBasic( o.ins ) ); + _.routine.options_( strFindAll, o ); + + /* */ + + let tokensSyntax = _.tokensSyntaxFrom( o.ins ); + let descriptorsArray = []; + let execeds = []; + let closests = []; + let closestTokenId = -1; + let closestIndex = o.src.length; + let currentIndex = 0; + let descriptorFor = o.fast ? descriptorForFast : descriptorForFull; + + /* */ + + tokensSyntax.idToValue.forEach( ( ins, tokenId ) => + { + // Dmytro : not optimal - double check. qqq : ? + _.assert( _.strIs( ins ) || _.regexpIs( ins ) ); + + if( _.regexpIs( ins ) ) + _.assert( !ins.sticky ); + + let found = find( o.src, ins, tokenId ); + closests[ tokenId ] = found; + if( found < closestIndex ) + { + closestIndex = found + closestTokenId = tokenId; + } + }); + + /* */ + + while( closestIndex < o.src.length ) + { + + if( o.tokenizingUnknown && closestIndex > currentIndex ) + { + descriptorFor( o.src, currentIndex, -1 ); + } + + descriptorFor( o.src, closestIndex, closestTokenId ); + + closestIndex = o.src.length; + closests.forEach( ( index, tokenId ) => + { + if( index < currentIndex ) + index = closests[ tokenId ] = find( o.src, tokensSyntax.idToValue[ tokenId ], tokenId ); + + _.assert( closests[ tokenId ] >= currentIndex ); + + if( index < closestIndex ) + { + closestIndex = index + closestTokenId = tokenId; + } + }); + + _.assert( closestIndex <= o.src.length ); + } + + if( o.tokenizingUnknown && closestIndex > currentIndex ) + { + descriptorFor( o.src, currentIndex, -1 ); + } + + /* */ + + return descriptorsArray; + + /* */ + + function find( src, ins, tokenId ) + { + let result; + + if( _.strIs( ins ) ) + { + result = findWithString( o.src, ins, tokenId ); + } + else if( _.regexpIs( ins ) ) + { + if( ins.source === '(?:)' ) + result = src.length; + else + result = findWithRegexp( o.src, ins, tokenId ); + } + else _.assert( 0 ); + + _.assert( result >= 0 ); + return result; + } + + /* */ + + function findWithString( src, ins ) + { + + if( !ins.length ) + return src.length; + + let index = src.indexOf( ins, currentIndex ); + + if( index < 0 ) + return src.length; + + return index; + } + + /* */ + + function findWithRegexp( src, ins, tokenId ) + { + let execed; + let result = src.length; + + if( currentIndex === 0 || ins.global ) + { + + do + { + + execed = ins.exec( src ); + if( execed ) + result = execed.index; + else + result = src.length; + + } + while( result < currentIndex ); + + } + else + { + execed = ins.exec( src.substring( currentIndex ) ); + + if( execed ) + result = execed.index + currentIndex; + + } + + if( execed ) + execeds[ tokenId ] = execed; + + return result; + } + + /* */ + + function descriptorForFast( src, index, tokenId ) + { + let originalIns = tokensSyntax.idToValue[ tokenId ]; + let match; + let it = []; + + if( tokenId === -1 ) + originalIns = src.substring( index, closestIndex ); + + if( _.strIs( originalIns ) ) + { + match = originalIns; + } + else + { + let execed = execeds[ tokenId ]; + _.assert( !!execed ); + match = execed[ 0 ]; + } + + it[ 0 ] = index; + it[ 1 ] = index + match.length; + it[ 2 ] = tokenId; + + descriptorsArray.push( it ); + + _.assert( _.strIs( match ) ); + if( match.length > 0 ) + currentIndex = index + match.length; + else + currentIndex = index + 1; + + o.counter += 1; + } + + /* */ + + function descriptorForFull( src, index, tokenId ) + { + let originalIns = tokensSyntax.idToValue[ tokenId ]; + let match; + let it = Object.create( null ); + let groups; + + if( tokenId === -1 ) + originalIns = src.substring( index, closestIndex ); + + if( _.strIs( originalIns ) ) + { + match = originalIns; + groups = []; + } + else + { + let execed = execeds[ tokenId ]; + _.assert( !!execed ); + match = execed[ 0 ]; + groups = _.longSlice( execed, 1, execed.length ); + } + + it.match = match; + it.groups = groups; + it.tokenId = tokenId; + it.charsRangeLeft = [ index, index + match.length ]; /* yyy */ + it.counter = o.counter; + it.input = src; + + if( tokensSyntax.idToName && tokensSyntax.idToName[ tokenId ] ) + it.tokenName = tokensSyntax.idToName[ tokenId ]; + + descriptorsArray.push( it ); + + _.assert( _.strIs( match ) ); + if( match.length > 0 ) + currentIndex = index + match.length; + else + currentIndex = index + 1; + + o.counter += 1; + } + + /* */ + +} +_.strFindAll.defaults = +{ + "src" : null, + "ins" : null, + "fast" : 0, + "counter" : 0, + "tokenizingUnknown" : 0 +} + +// + + + _.strReverse = function strReverse( srcStr ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + let result = ''; + for( let i = 0 ; i < srcStr.length ; i++ ) + result = srcStr[ i ] + result; + return result; +} + +// + + + _.strCount = function strCount( src, ins ) +{ + let result = 0; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ) ); + _.assert( _.regexpLike( ins ) ); + + let i = 0; + do + { + // let found = _.strLeft( src, ins, [ i, src.length ] ); + let found = _.strLeft_( src, ins, [ i, src.length-1 ] ); + if( found.entry === undefined ) + break; + i = found.index + found.entry.length; + if( !found.entry.length ) + i += 1; + result += 1; + _.assert( i !== -1, 'not tested' ); + } + while( i !== -1 && i < src.length ); + + return result; +} + +// + + + _.strLeft_ = function left_( src, ins, cinterval ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( _.argumentsArray.like( src ) ) + { + let result = []; + for( let s = 0 ; s < src.length ; s++ ) + result[ s ] = _._strLeftSingle_( src[ s ], ins, cinterval ); + return result; + } + else + { + return _._strLeftSingle_( src, ins, cinterval ); + } + +} + +// + + + _.tokensSyntaxFrom = function tokensSyntaxFrom( ins ) +{ + + if( ins instanceof _.TokensSyntax ) + return ins + + let result = TokensSyntax(); + + if( _.strIs( ins ) || _.regexpIs( ins ) ) + ins = [ ins ]; + + /* */ + + _.assert( arguments.length === 1 ); + _.assert( _.argumentsArray.like( ins ) || _.object.isBasic( ins ) ); + + /* */ + + result.idToValue = ins; + if( _.mapIs( ins ) ) + { + result.idToValue = []; + result.idToName = []; + let i = 0; + for( var name in ins ) + { + let element = ins[ name ]; + if( _.longIs( element ) ) + { + let alternative = result.alternatives[ name ] = result.alternatives[ name ] || []; + for( let e = 0 ; e < element.length ; e++ ) + { + let name2 = name + '_' + element[ e ]; + result.idToValue[ i ] = ins[ name ][ e ]; // qqq : ? Dmytro : better to use local variable 'let element'. Also, maybe, needs check type of element - regexp or string. + result.idToName[ i ] = name2; + result.nameToId[ name2 ] = i; + alternative.push( name2 ); + i += 1; + } + } + else + { + result.idToValue[ i ] = ins[ name ]; // qqq : ? Dmytro : better to use local variable 'let element' + result.idToName[ i ] = name; + result.nameToId[ name ] = i; + i += 1; + } + } + } + + return result; +} + +// + + + _._strReplaceMapPrepare = function _strReplaceMapPrepare( o ) +{ + + /* verify */ + + _.map.assertHasAll( o, _strReplaceMapPrepare.defaults ); + _.assert( arguments.length === 1 ); + _.assert( _.object.isBasic( o.dictionary ) || _.longIs( o.dictionary ) || o.dictionary === null ); + _.assert( ( _.longIs( o.ins ) && _.longIs( o.sub ) ) || ( o.ins === null && o.sub === null ) ); + + /* head */ + + if( o.dictionary ) + { + + o.ins = []; + o.sub = []; + + if( _.object.isBasic( o.dictionary ) ) + { + let i = 0; + for( let d in o.dictionary ) + { + o.ins[ i ] = d; + o.sub[ i ] = o.dictionary[ d ]; + i += 1; + } + } + else + { + let i = 0; + o.dictionary.forEach( ( d ) => + { + let ins = d[ 0 ]; + let sub = d[ 1 ]; + _.assert( d.length === 2 ); + // _.assert( !( _.arrayIs( ins ) ^ _.arrayIs( sub ) ) ); + // debugger; + _.assert( _.arrayIs( ins ) === _.arrayIs( sub ) ); + if( _.arrayIs( ins ) ) + { + _.assert( ins.length === sub.length ) + for( let n = 0 ; n < ins.length ; n++ ) + { + o.ins[ i ] = ins[ n ]; + o.sub[ i ] = sub[ n ]; + i += 1; + } + } + else + { + o.ins[ i ] = ins; + o.sub[ i ] = sub; + i += 1; + } + }); + } + + o.dictionary = null; + } + + /* verify */ + + _.assert( !o.dictionary ); + _.assert( o.ins.length === o.sub.length ); + + if( Config.debug ) + { + o.ins.forEach( ( ins ) => _.assert( _.strIs( ins ) || _.regexpIs( ins ) ), 'Expects String or RegExp' ); + o.sub.forEach( ( sub ) => _.assert( _.strIs( sub ) || _.routineIs( sub ) ), 'Expects String or Routine' ); + } + + return o; +} +_._strReplaceMapPrepare.defaults = +{ "dictionary" : null, "ins" : null, "sub" : null } + +// + + + _.map.assertHasAll = function assertHasAll( srcMap, all, msg ) +{ + if( Config.debug === false ) + return true; + return _.map.sureHasAll.apply( this, arguments ); +} + +// + + + _.map.sureHasAll = function sureHasAll( srcMap, all, msg ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4, 'Expects two, three or four arguments' ); + + let but = Object.keys( _.mapBut_( null, all, srcMap ) ); + + if( but.length > 0 ) + { + let err; + if( arguments.length === 2 ) + { + err = _._err + ({ + args : [ `${ _.entity.strType( srcMap ) } should have fields :`, _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + else + { + let arr = []; + for( let i = 2; i < arguments.length; i++ ) + { + if( _.routine.is( arguments[ i ] ) ) + arguments[ i ] = ( arguments[ i ] )(); + arr.push( arguments[ i ] ); + } + err = _._err + ({ + args : [ arr.join( ' ' ), _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + debugger; /* eslint-disable-line no-debugger */ + throw err; + return false; + } + + return true; +} + +// + + + _.longSlice = function _longShallow( src, f, l ) +{ + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + _.assert( _.longIs( src ), 'Expects long {-src-}' ); + _.assert( f === undefined || _.number.is( f ) ); + _.assert( l === undefined || _.number.is( l ) ); + + /* xxx qqq for Dmytro : check and cover */ + + f = f === undefined ? 0 : f; + l = l === undefined ? src.length : l; + + if( f < 0 ) + f = src.length + f; + if( l < 0 ) + l = src.length + l; + + if( f < 0 ) + f = 0; + if( f > l ) + l = f; + + if( _.bufferTypedIs( src ) ) + return _.longOnly_( null, src, [ f, l - 1 ] ); + return Array.prototype.slice.call( src, f, l ); + + // if( _.bufferTypedIs( src ) ) + // return src.subsrc( f, l ); + // else if( _.srcLikeResizable( src ) ) + // return src.slice( f, l ); + // else if( _.argumentssrcIs( src ) ) + // return src.prototype.slice.call( src, f, l ); + // else + // _.assert( 0 ); +} + +// + + + _.regexpEscape = function escape( src ) +{ + _.assert( _.strIs( src ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + return src.replace( /([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1' ); +} + +// + + + _.regexpLike = function like( src ) +{ + if( src instanceof RegExp || Object.prototype.toString.call( src ) === '[object String]' ) + return true; + return false; +} + +// + + + _.regexpsLikeAll = function likeAll( src ) +{ + _.assert( arguments.length === 1 ); + + if( _.argumentsArray.like( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( !_.regexp.like( src[ s ] ) ) + return false; + return true; + } + + return _.regexp.like( src ); +} + +// + + + _.filter_ = function filter_( dst, src, onEach ) +{ + + if( arguments.length === 2 ) + { + _.assert( arguments.length === 3, 'Expects three arguments' ); + onEach = src; + src = dst; + } + else + { + _.assert( arguments.length === 3, 'Expects two or three arguments' ); + } + onEach = _._filter_functor( onEach, 1 ); + + _.assert( _.routine.is( onEach ) ); + + /* */ + + let result; + + if( dst === src ) + { + + result = src; + if( _.longIs( src ) ) + { + /* qqq for junior : add branch for countable case */ + /* qqq : should be direct! check other cycles */ + for( let s = src.length - 1 ; s >= 0 ; s-- ) + { + let r = onEach.call( src, src[ s ], s, src ); + if( _.unrollIs( r ) ) + _.longBut_( result, s, r ); + else if( r === undefined ) + result.splice( s, 1 ); + else + result[ s ] = r; + // else if( r !== undefined ) + // result[ s ] = r; + // else + // result.splice( s, 1 ); + } + } + else if( _.aux.is( src ) ) + { + for( let s in src ) + { + let r = onEach.call( src, src[ s ], s, src ); + if( r === undefined ) + delete src[ s ]; + else + src[ s ] = r; + } + } + else + { + result = onEach.call( null, src, null, null ); + } + + } + else + { + + result = dst; + if( _.longIs( src ) ) + { + if( dst === null ) + { + if( _.argumentsArray.is( src ) ) + result = []; + else + result = _.long.make( src, 0 ); + } + else + { + _.assert( _.longIs( dst ), '{-dst-} container should be long like' ); + } + + let s, d; + /* qqq for junior : add branch for countable case */ + for( s = 0, d = 0 ; s < src.length ; s++ ) + { + let r = onEach.call( src, src[ s ], s, src ); + if( _.unrollIs( r ) ) + { + _.longBut_( result, d, r ); + d += r.length; + } + else if( r !== undefined ) + { + result[ d ] = r; + d += 1; + } + } + } + else if( _.aux.is( src ) ) + { + if( dst === null ) + result = _.entity.makeUndefined( src ); + else + _.assert( _.aux.is( dst ), '{-dst-} container should be map like' ); + + for( let s in src ) + { + let r = onEach.call( src, src[ s ], s, src ); + if( r !== undefined ) + result[ s ] = r; + } + } + else + { + let r = onEach.call( null, src, null, null ); + + if( r !== undefined ) + { + if( _.longIs( dst ) ) + result = _.arrayAppendElement( dst, r ); + else if( _.aux.is( dst ) ) + result = _.props.extend( dst, r ); + else if( _.primitive.is( dst ) ) + result = r; + else + _.assert( 0, 'Not clear how to add result in destination container {-dst-}' ); + } + } + + } + + return result; +} + +// + + + _._filter_functor = function _filter_functor( condition, levels ) +{ + let result; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.routine.is( condition ) || _.object.isBasic( condition ) ); + + if( _.object.isBasic( condition ) ) + { + let template = condition; + condition = function condition( e, k, src ) + { + _.assert( arguments.length === 3 ); + if( e === template ) + return e; + if( !_.object.like( e ) ) + return; + let satisfied = _.objectSatisfy + ({ + template, + src : e, + levels + }); + if( satisfied ) + return e; + }; + } + + return condition; +} + +// + + + _.entityMakeUndefined = undefined; + +// + + + _.props.keys = function keys( srcMap, o ) +{ + let result; + + // _.assert( this === _.object ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( keys, o || null ); + // _.assert( !_.primitive.is( srcMap ) ); + + o.srcMap = srcMap; + + result = this._keys( o ); + + return result; +} +_.props.keys.defaults = +{ "onlyOwn" : 0, "onlyEnumerable" : 1 } + +// + + + + _.path.globShortFilterKeys = ( function() { + + const _globShortFilter_head = function globShortFilter_head( routine, args ) + { + let result; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + + let o = args[ 0 ]; + if( args[ 1 ] !== undefined ) + o = { src : args[ 0 ], selector : args[ 1 ] } + + o = _.routine.options_( routine, o ); + + if( o.onEvaluate === null ) + o.onEvaluate = function byVal( e, k, src ) + { + return e; + } + + return o; + } + + const _globShortFilter_body = function globShortFilter_body( o ) + { + let self = this; + let result; + + _.assert( arguments.length === 1 ); + + // if( _global_.debugger ) + // debugger; + + if( self.isGlob( o.selector ) ) + { + let regexp = self.globShortSplitsToRegexps( o.selector ); + result = _.filter_( null, o.src, ( e, k ) => + { + let val = o.onEvaluate( e, k, o.src ); + return regexp.test( val ) ? e : undefined; + } ); + } + else + { + result = _.filter_( null, o.src, ( e, k ) => + { + return o.onEvaluate( e, k, o.src ) === o.selector ? e : undefined; + } ); + } + + return result; + } + _globShortFilter_body.defaults = { "src" : null, "selector" : null, "onEvaluate" : null } + + const _globShortFilter_ = _.routine.unite + ({ + head : _globShortFilter_head, + body : _globShortFilter_body, + }); + + return _globShortFilter_; +})(); +_.path.globShortFilterKeys.defaults = +{ + "src" : null, + "selector" : null, + "onEvaluate" : function byKey( e, k, src ) +{ + return _.arrayIs( src ) ? e : k; +} +} + +// + + + _.path.globShortSplitsToRegexps = +(function() +{ + let toVectorize = Object.create( null ); + toVectorize.routine = function globShortSplitToRegexp( glob ) +{ + let self = this; + + _.assert( _.strIs( glob ) || _.regexpIs( glob ) ); + _.assert( arguments.length === 1 ); + + if( _.regexpIs( glob ) ) + return glob; + + let str = self._globShortSplitToRegexpSource( glob ); + let result = new RegExp( '^' + str + '$' ); + return result; +} + +// + +toVectorize.vectorizingArray = 1; + +// + +toVectorize.vectorizingMapVals = 0; + +// + +toVectorize.vectorizingMapKeys = 1; + +// + +toVectorize.select = 1; + +// + +toVectorize.propertyCondition = null; + +// + +toVectorize.bypassingFilteredOut = 1; + +// + +toVectorize.bypassingEmpty = 0; + +// + +toVectorize.vectorizingContainerAdapter = 0; + +// + +toVectorize.unwrapingContainerAdapter = 0; + +// + + + return _.vectorize( toVectorize ); +})(); + + +// + + + _.path._globShortSplitToRegexpSource = ( function functor() +{ + + let self; + let _globRegexpSourceCache = Object.create( null ) + + let _transformation0 = + [ + [ /\[(.+?)\]/g, handlePass ], /* square brackets */ + [ /\.\./g, handlePass ], /* dual dot */ + [ /\./g, handlePass ], /* dot */ + [ /\(\)|\0/g, handlePass ], /* empty parentheses or zero */ + [ /([!?*@+]*)\((.*?(?:\|(.*?))*)\)/g, handlePass ], /* parentheses */ + [ /\*\*\*/g, handlePass ], /* triple asterix */ + [ /\*\*/g, handlePass ], /* dual asterix */ + [ /(\*)/g, handlePass ], /* single asterix */ + [ /(\?)/g, handlePass ], /* question mark */ + ] + + let _transformation1 = + [ + [ /\[(.+?)\]/g, handleSquareBrackets ], /* square brackets */ + [ /\{(.*)\}/g, handleCurlyBrackets ], /* curly brackets */ + ] + + let _transformation2 = + [ + [ /\.\./g, '\\.\\.' ], /* dual dot */ + [ /\./g, '\\.' ], /* dot */ + [ /\(\)|\0/g, '' ], /* empty parentheses or zero */ + [ /([!?*@+]?)\((.*?(?:\|(.*?))*)\)/g, hanleParentheses ], /* parentheses */ + // [ /\/\*\*/g, '(?:\/.*)?', ], /* slash + dual asterix */ + [ /\*\*\*/g, '(?:.*)' ], /* triple asterix */ + [ /\*\*/g, '.*' ], /* dual asterix */ + [ /(\*)/g, '[^\/]*' ], /* single asterix */ + [ /(\?)/g, '[^\/]' ], /* question mark */ + ] + + /* */ + + _globShortSplitToRegexpSource.functor = functor; + return _globShortSplitToRegexpSource; + + function _globShortSplitToRegexpSource( src ) + { + self = this; + + let result = _globRegexpSourceCache[ src ]; + if( result ) + return result; + + _.assert( _.strIs( src ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert + ( + !_.strHas( src, /(^|\/)\.\.(\/|$)/ ) || src === self.downToken, + 'glob should not has splits with ".." combined with something' + ); + + result = transform( src ); + + _globRegexpSourceCache[ src ] = result; + + return result; + } + + /* */ + + function transform( src ) + { + let result = src; + + result = _.strReplaceAll + ( { + src : result, + dictionary : _transformation0, + joining : 1, + onUnknown : handleUnknown, + } ); + + result = _.strReplaceAll( result, _transformation1 ); + result = _.strReplaceAll( result, _transformation2 ); + + return result; + } + + /* */ + + function handleUnknown( src ) + { + return _.regexpEscape( src ); + } + + /* */ + + function handlePass( src ) + { + return src; + } + + /* */ + + function handleCurlyBrackets( src, it ) + { + throw _.err( 'Glob with curly brackets is not allowed ', src ); + } + + /* */ + + function handleSquareBrackets( src, it ) + { + let inside = it.groups[ 0 ]; + /* escape inner [] */ + inside = inside.replace( /[\[\]]/g, ( m ) => '\\' + m ); + /* replace ! -> ^ at the beginning */ + inside = inside.replace( /^!/g, '^' ); + if( inside[ 0 ] === '^' ) + inside = inside + '\/'; + return [ '[' + inside + ']' ]; + } + + /* */ + + function hanleParentheses( src, it ) + { + + let inside = it.groups[ 1 ].split( '|' ); + let multiplicator = it.groups[ 0 ]; + + multiplicator = _.strReverse( multiplicator ); + if( multiplicator === '*' ) + multiplicator += '?'; + + _.assert( _.strCount( multiplicator, '!' ) === 0 || multiplicator === '!' ); + _.assert( _.strCount( multiplicator, '@' ) === 0 || multiplicator === '@' ); + + inside = inside.map( ( i ) => self._globShortSplitToRegexpSource( i ) ); + + let result = '(?:' + inside.join( '|' ) + ')'; + if( multiplicator === '@' ) + result = result; + else if( multiplicator === '!' ) + result = '(?:(?!(?:' + result + '|\/' + ')).)*?'; + else + result += multiplicator; + + /* (?:(?!(?:abc)).)+ */ + + return result; + } + + /* */ + +} )(); + +// + + + _.path.is = function is( path ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + return _.strIs( path ); +} + +// + + + _.path.name = ( function() { + + const _name_head = function name_head( routine, args ) + { + let o = args[ 0 ]; + if( _.strIs( o ) ) + o = { path : o }; + + _.routine.options_( routine, o ); + _.assert( args.length === 1 ); + _.assert( arguments.length === 2 ); + _.assert( _.strIs( o.path ), 'Expects string {-o.path-}' ); + + return o; + } + + const _name_body = function name_body( o ) + { + + if( _.strIs( o ) ) + o = { path : o }; + + _.routine.assertOptions( name_body, arguments ); + + o.path = this.canonize( o.path ); + + let i = o.path.lastIndexOf( '/' ); + if( i !== -1 ) + o.path = o.path.substr( i+1 ); + + if( !o.full ) + { + let i = o.path.lastIndexOf( '.' ); + if( i !== -1 ) o.path = o.path.substr( 0, i ); + } + + return o.path; + } + _name_body.defaults = { "path" : null, "full" : 0 } + + const _name_ = _.routine.unite + ({ + head : _name_head, + body : _name_body, + }); + + return _name_; +})(); +_.path.name.defaults = +{ "path" : null, "full" : 0 } + +// + + + _.path.fullName = ( function() { + + const _name_head = function name_head( routine, args ) + { + let o = args[ 0 ]; + if( _.strIs( o ) ) + o = { path : o }; + + _.routine.options_( routine, o ); + _.assert( args.length === 1 ); + _.assert( arguments.length === 2 ); + _.assert( _.strIs( o.path ), 'Expects string {-o.path-}' ); + + return o; + } + + const _name_body = function name_body( o ) + { + + if( _.strIs( o ) ) + o = { path : o }; + + _.routine.assertOptions( name_body, arguments ); + + o.path = this.canonize( o.path ); + + let i = o.path.lastIndexOf( '/' ); + if( i !== -1 ) + o.path = o.path.substr( i+1 ); + + if( !o.full ) + { + let i = o.path.lastIndexOf( '.' ); + if( i !== -1 ) o.path = o.path.substr( 0, i ); + } + + return o.path; + } + _name_body.defaults = { "path" : null, "full" : 0 } + + const _name_ = _.routine.unite + ({ + head : _name_head, + body : _name_body, + }); + + return _name_; +})(); +_.path.fullName.defaults = +{ "path" : null, "full" : 1 } + +// + + + _.path.detrail = function detrail( path ) +{ + _.assert( this.is( path ) ); + _.assert( arguments.length === 1 ); + + if( path !== this.rootToken ) + return _.strRemoveEnd( path, this.upToken ); + + return path; +} + +// + + + _.path.reroot = ( function() { + + const _join_head = function join_head( routine, args ) + { + _.assert( args.length > 0, 'Expects argument' ) + let o = { paths : args }; + + _.routine.options_( routine, o ); + //_.assert( o.paths.length > 0 ); + _.assert( _.boolLike( o.reroot ) ); + _.assert( _.boolLike( o.allowingNull ) ); + _.assert( _.boolLike( o.raw ) ); + + return o; + } + + const _join_body = function join_body( o ) + { + let self = this; + let result = null; + let prepending = true; + + /* */ + + if( Config.debug ) + for( let a = o.paths.length-1 ; a >= 0 ; a-- ) + { + let src = o.paths[ a ]; + _.assert + ( + _.strIs( src ) || src === null, () => `Expects strings as path arguments, but #${a} argument is ${_.entity.strType( src )}` + ); + } + + /* */ + + for( let a = o.paths.length-1 ; a >= 0 ; a-- ) + { + let src = o.paths[ a ]; + + if( o.allowingNull ) + if( src === null ) + break; + + if( result === null ) + result = ''; + + _.assert( _.strIs( src ), () => `Expects strings as path arguments, but #${a} argument is ${_.entity.strType( src )}` ); + + if( !prepend( src ) ) + break; + + } + + /* */ + + if( !o.raw && result !== null ) + result = self.normalize( result ); + + return result; + + /* */ + + function prepend( src ) + { + let trailed = false; + let endsWithUp = false; + + if( src ) + src = self.refine( src ); + + if( !src ) + return true; + + // src = src.replace( /\\/g, self.upToken ); + + // if( result ) + if( _.strEnds( src, self.upToken ) ) + // if( _.strEnds( src, self.upToken ) && !_.strEnds( src, self.upToken + self.upToken ) ) + // if( src.length > 1 || result[ 0 ] === self.upToken ) + { + if( src.length > 1 ) + { + if( result ) + src = src.substr( 0, src.length-1 ); + trailed = true; + + if( result === self.downToken ) + result = self.hereToken; + else if( result === self.downUpToken ) + result = self.hereUpToken; + else + result = _.strRemoveBegin( result, self.downUpToken ); + + } + else + { + endsWithUp = true; + } + } + + if( src && result ) + if( !endsWithUp && !_.strBegins( result, self.upToken ) ) + result = self.upToken + result; + + result = src + result; + + if( !o.reroot ) + { + if( _.strBegins( result, self.rootToken ) ) + return false; + } + + return true; + } + + } + _join_body.defaults = { + "paths" : null, + "reroot" : 0, + "allowingNull" : 1, + "raw" : 0 + } + + const _join_ = _.routine.unite + ({ + head : _join_head, + body : _join_body, + }); + + return _join_; +})(); +_.path.reroot.defaults = +{ + "paths" : null, + "reroot" : 1, + "allowingNull" : 1, + "raw" : 0 +} + +// + + + _.path.traceToRoot = function traceToRoot( filePath ) +{ + let self = this; + let result = []; + + filePath = self.normalize( filePath ); + // filePath = self.detrail( filePath ); // Dmytro : cycled loop if path is absolute and has form '/..' + // filePath = self.canonize( filePath ); + + _.assert( arguments.length === 1 ); + _.assert( self.isAbsolute( filePath ) ); + + /* + should preserve trailing of the longest path + /a/b/ -> [ '/', '/a', '/a/b/' ] + */ + + // if( self.isAbsolute( filePath ) ) + // { + result.push( filePath ); + filePath = self.detrail( filePath ); + while( filePath !== self.rootToken ) + { + _.assert + ( + filePath !== self.rootToken + self.downToken + && !_.strBegins( filePath, self.rootToken + self.downToken + self.upToken ) + ); + filePath = self.dir( filePath ); + result.push( filePath ); + // filePath = self.detrail( dir ); /* qqq : not optimal! | aaa : Moved outside of the loop. */ + } + // } + // else + // { + // filePath = self.undot( filePath ); + // if( !self.isDotted( filePath ) ) + // do + // { + // result.unshift( filePath ); + // filePath = self.detrail( self.dir( filePath ) ); /* qqq : not optimal! */ + // } + // while( !self.isDotted( filePath ) ); + // } + + // result.push( filePath ); + + return result.reverse(); +} + +// + + + + + + + let ToolsExtension = + { + TokensSyntax, + } + + Object.assign( _starter_, ToolsExtension ); + + let PathExtension = + { + } + + Object.assign( _starter_.path, PathExtension ); + +; + +/* */ /* end of globing */ })(); + + +/* */ /* begin of njs */ ( function _njs_() { + + + + 'use strict'; + + const _global = _global_; + let _starter_ = _global_._starter_; + let _ = _starter_; + // let path = _starter_.path; // xxx + // let sourcesMap = _starter_.sourcesMap; // xxx + + // if( _global._starter_ && _global._starter_._inited ) // xxx + // return; + + let _natInclude = typeof require === 'undefined' ? null : require; + let _natResolve = typeof require === 'undefined' ? null : require.resolve; + + // + + function _njsModuleFromSource( sourceFile ) + { + if( sourceFile.njsModule ) + return sourceFile.njsModule; + let Module = _natInclude( 'module' ); + let natPath = this.path.nativize( sourceFile.filePath ); + let njsModule = Module._cache[ natPath ]; + if( !njsModule ) + { + njsModule = new Module( natPath, sourceFile.parent ? sourceFile.parent.njsModule : null ); + Module._cache[ natPath ] = njsModule; + } + njsModule.sourceFile = sourceFile; + sourceFile.njsModule = njsModule; + return njsModule; + } + + // + + function _sourceForIncludeWithNjsModule( njsModule, filePath ) + { + let starter = this; + let sourceFile = njsModule.sourceFile || null; + return starter._sourceForInclude( sourceFile, _.path.dir( njsModule.filename ), filePath ); + } + + // + + function _sourceFromNjsModule( njsModule ) + { + let starter = this; + let r = starter._sourceForPathGet( njsModule.filename ); + if( r ) + { + starter._njsSourceFileUpdateFromNjs( r, njsModule ); + return r; + } + r = starter.SourceFile({ filePath : njsModule.filename, njsModule }); + if( !r.parent ) + if( njsModule.parent ) + r.parent = starter._sourceFromNjsModule( njsModule.parent ); + return r; + } + + // + + function _njsSourceFile( sourceFile, op ) + { + let starter = this; + + sourceFile._natInclude = _natInclude; + sourceFile._natResolve = _natResolve; + + if( sourceFile.njsModule === undefined ) + sourceFile.njsModule = null; + if( op.njsModule ) + sourceFile.njsModule = op.njsModule; + + starter._njsSourceFileUpdateFromNjs( sourceFile, sourceFile.njsModule ); + + } + + // + + function _njsSourceFileUpdateFromNjs( sourceFile, njsModule ) + { + + _.assert + ( + !sourceFile.njsModule || sourceFile.njsModule === njsModule, + 'Something wrong!' + ); + + sourceFile.njsModule = njsModule; + if( sourceFile.njsModule ) + { + sourceFile.njsModule.sourceFile = sourceFile; + sourceFile.state = njsModule.loaded ? 'opened' : 'opening'; + sourceFile.exports = njsModule.exports; + } + + } + + // + + function _sourceResolveAct( parentSource, basePath, filePath ) + { + let _natResolve; + + if( parentSource ) + { + _natResolve = parentSource._natResolve; + } + else + { + _natResolve = this._natResolve; + } + + return _natResolve( filePath ); + } + + // + + function _njsSourceIncludeFromNjsAct( njsModule, childSource, sourcePath ) + { + let parentSource = njsModule.sourceFile || null; + return this._sourceIncludeResolvedCalling( parentSource, childSource, sourcePath ); + } + + // + + function _includeAct( parentSource, basePath, filePath ) + { + let starter = this; + let resolvedFilePath = this._pathResolveLocal( parentSource, basePath, filePath ); + resolvedFilePath = _.path.nativize( resolvedFilePath ); + let _natInclude = parentSource ? parentSource._natInclude : starter._natInclude; + return _natInclude( resolvedFilePath ); + // return _natInclude( filePath ); + } + + // + + function _sourceCodeModule() + { + let SourceFile = _starter_.SourceFile; + + accesor( '_cache', cacheGet, cacheSet ); + + this.exports = SourceFile; + + return SourceFile; + + function cacheGet() + { + return _starter_.sourcesMap; + } + + function cacheSet( src ) + { + _starter_.sourcesMap = src; + + if( !_starter_.sourcesMap[ 'module' ] ) + _starter_._sourceMake( 'module', '/', _sourceCodeModule ); + + return _starter_.sourcesMap; + } + + function accesor( propName, onGet, onSet ) + { + let property = + { + enumerable : true, + configurable : true, + get : onGet, + set : onSet, + } + Object.defineProperty( SourceFile, propName, property ); + } + + } + + // + + function _SetupAct() + { + let starter = this; + + starter._sourceMake( 'module', '/', _sourceCodeModule ); + + let Module = _natInclude( 'module' ); + let NjsResolveFilename = Module._resolveFilename; + Module._resolveFilename = function _resolveFilename( request, parent, isMain ) + { + // let options = arguments[ 3 ]; + let result = starter._sourceOwnResolve( parent, null, request ); + if( result === null ) + return NjsResolveFilename.apply( this, arguments ); + return result; + } + let NjsLoad = Module._load; + Module._load = function _load( request, parent, isMain ) + { + if( !parent.sourceFile ) + starter._sourceFromNjsModule( parent ); + let childSource = starter._sourceForIncludeWithNjsModule( parent, request ); + if( childSource === null ) + { + let result = NjsLoad.apply( this, arguments ); + let child = Module._cache[ NjsResolveFilename.apply( this, arguments ) ]; + if( child ) + starter._sourceFromNjsModule( child ); + return result; + } + return starter._njsSourceIncludeFromNjsAct( parent, childSource, request ); + } + } + +; + + + let Extension = + { + + _natInclude, + _natResolve, + + _njsModuleFromSource, + _sourceForIncludeWithNjsModule, + _sourceFromNjsModule, + + _njsSourceFile, + _njsSourceFileUpdateFromNjs, + _sourceResolveAct, + _njsSourceIncludeFromNjsAct, + _includeAct, + _SetupAct, + + + } + + Object.assign( _starter_, Extension ); + +; + +/* */ /* end of njs */ })(); + + +/* */ /* begin of starter */ ( function _starter_() { + + + + 'use strict'; + + const _global = _global_; + if( _global._starter_ && _global._starter_._inited ) + return; + + let _starter_ = _global_._starter_; + let _ = _starter_; + let path = _starter_.path; + let sourcesMap = _starter_.sourcesMap; + + // + + function SourceFile( o ) + { + let starter = _starter_; + let sourceFile = this; + + if( !( sourceFile instanceof SourceFile ) ) + return new SourceFile( o ); + + if( o.isScript === undefined ) + o.isScript = true; + + o.filePath = starter.path.canonizeTolerant( o.filePath ); + if( !o.dirPath ) + o.dirPath = starter.path.dir( o.filePath ); + o.dirPath = starter.path.canonizeTolerant( o.dirPath ); + + sourceFile.filePath = o.filePath; + sourceFile.dirPath = o.dirPath; + sourceFile.nakedCall = o.nakedCall; + sourceFile.isScript = o.isScript; + + sourceFile.filename = o.filePath; + sourceFile.exports = Object.create( null ); + sourceFile.parent = null; + sourceFile.children = []; + sourceFile.njsModule = o.njsModule; + sourceFile.error = null; + sourceFile.state = o.nakedCall ? 'preloaded' : 'created'; + + sourceFile.starter = starter; + // sourceFile.include = starter._sourceInclude.bind( starter, sourceFile, sourceFile.dirPath ); + sourceFile.include = include.bind( sourceFile ); + sourceFile.resolve = starter._sourceResolve.bind( starter, sourceFile, sourceFile.dirPath ); + sourceFile.include.resolve = sourceFile.resolve; + sourceFile.include.sourceFile = sourceFile; + sourceFile.isModuleDeclareFile = starter.path.name( sourceFile.dirPath ) === 'node_modules'; + + /* njs compatibility */ + + sourceFile.path = [ '/' ]; + getter( 'id', idGet ); + getter( 'loaded', loadedGet ); + + /* interpreter-specific */ + + if( starter.interpreter === 'browser' ) + starter._broSourceFile( sourceFile, o ); + else + starter._njsSourceFile( sourceFile, o ); + + /* */ + + if( starter.loggingSourceFiles ) + console.log( ` . SourceFile ${o.filePath}` ); + + + starter.sourcesMap[ _.path.nativize( o.filePath ) ] = sourceFile; + if( sourceFile.isModuleDeclareFile ) + starter.moduleMainFilesMap[ starter.path.fullName( o.filePath ) ] = sourceFile; + // starter.sourcesMap[ o.filePath ] = sourceFile; + // if( sourceFile.isModuleDeclareFile ) + // starter.moduleMainFilesMap[ starter.path.fullName( o.filePath ) ] = sourceFile; + // Object.preventExtensions( sourceFile ); + return sourceFile; + + /* - */ + + function idGet() + { + return this.filePath; + } + + function loadedGet() + { + return this.state === 'opened'; + } + + function getter( propName, onGet ) + { + let property = + { + enumerable : true, + configurable : true, + get : onGet, + } + Object.defineProperty( sourceFile, propName, property ); + } + + function include( id ) + { + let sourceFile = this; + return SourceFile._load( id, sourceFile, false ); + } + } + + SourceFile._load = function _load( request, parent, isMain ) + { + return _starter_._sourceInclude( parent, parent.dirPath, request ); + } + + SourceFile._resolveFilename = function _resolveFilename( request, parent/*, isMain, options*/ ) + { + return _starter_._sourceResolveAct( parent, parent.dirPath, request ); + } + + SourceFile.prototype = Object.create( null ); + + SourceFile.prototype.load = function load( filename ) + { + let module = this; + return _starter_._sourceIncludeResolvedCalling( null, module, module.filePath ) + } + + // + + function _sourceMake( filePath, dirPath, nakedCall ) + { + let r = SourceFile({ filePath, dirPath, nakedCall }); + return r; + } + + // + + function _sourceIncludeResolvedCalling( parentSource, childSource, sourcePath ) + { + let starter = this; + + try + { + + if( !childSource ) + throw _._err({ args : [ `Found no source file ${sourcePath}` ], level : 4 }); + + if( childSource.state === 'errored' || childSource.state === 'opening' || childSource.state === 'opened' ) + return end(); + + childSource.parent = parentSource || null; + + childSource.state = 'opening'; + childSource.nakedCall(); + childSource.state = 'opened'; + + if( Config.interpreter === 'njs' ) + starter._njsModuleFromSource( childSource ); + + } + catch( err ) + { + err = _.err( err, `\nError including source file ${ childSource ? childSource.filePath : sourcePath }` ); + if( childSource ) + { + childSource.error = err; + childSource.state = 'errored'; + } + throw err; + } + + return end(); + + function end() + { + if( !starter.requireCache[ childSource.filePath ] ) + starter.requireCache[ childSource.filePath ] = childSource; + + return childSource.exports; + } + } + + // + + function _sourceInclude( parentSource, basePath, filePath ) + { + let starter = this; + + try + { + + if( _.arrayIs( filePath ) ) + { + let result = []; + for( let f = 0 ; f < filePath.length ; f++ ) + { + let r = starter._sourceInclude( parentSource, basePath, filePath[ f ] ); + if( r === undefined ) + result.push( r ); + else + _.arrayAppendArrays( result, r ); + } + return result; + } + + if( !_starter_.withServer && _.path.isGlob( filePath ) ) /* xxx : workaround */ + { + let resolvedFilePath = starter._pathResolveLocal( parentSource, basePath, filePath ); + let filtered = _.props.keys( _.path.globShortFilterKeys( starter.sourcesMap, resolvedFilePath ) ); + if( filtered.length ) + return starter._sourceInclude( parentSource, basePath, filtered ); + } + else + { + let resolvedFilePath = this._pathResolveLocal( parentSource, basePath, filePath ); + let chachedSource = this.requireCache[ resolvedFilePath ]; + if( chachedSource ) + { + _.assert( chachedSource.state === 'errored' || chachedSource.state === 'opening' || chachedSource.state === 'opened' ) + return chachedSource.exports; + } + // let childSource = starter._sourceForInclude.apply( starter, arguments ); + let childSource = this.sourcesMap[ resolvedFilePath ]; + if( childSource ) + return starter._sourceIncludeResolvedCalling( parentSource, childSource, filePath ); + } + + return starter._includeAct( parentSource, basePath, filePath ); + } + catch( err ) + { + err = _.err( err, `\nError including source file ${ filePath }` ); + throw err; + } + + } + + // + + function _sourceResolve( parentSource, basePath, filePath ) + { + let starter = this; + let result = starter._sourceOwnResolve( parentSource, basePath, filePath ); + if( result !== null ) + return result; + + return starter._sourceResolveAct( parentSource, basePath, filePath ); + } + + // + + function _sourceOwnResolve( parentSource, basePath, filePath ) + { + let starter = this; + let childSource = starter._sourceForInclude.apply( starter, arguments ); + if( !childSource ) + return null; + return childSource.filePath; + } + + // + + function _sourceForPathGet( filePath ) + { + filePath = this.path.canonizeTolerant( filePath ); + let childSource = this.sourcesMap[ filePath ]; + if( childSource ) + return childSource; + return null; + } + + // + + function _sourceForInclude( sourceFile, basePath, filePath ) + { + let resolvedFilePath = this._pathResolveLocal( sourceFile, basePath, filePath ); + let childSource = this.sourcesMap[ resolvedFilePath ]; + if( childSource ) + return childSource; + return null; + } + + // + + function _pathResolveLocal( sourceFile, basePath, filePath ) + { + let starter = this; + + if( sourceFile && !basePath ) + basePath = sourceFile.dirPath; + + if( !basePath && !sourceFile ) + throw _.err( 'Base path is not specified, neither script file' ); + + let isAbsolute = filePath[ 0 ] === '/'; + let isDotted = _.strBegins( filePath, './' ) || _.strBegins( filePath, '../' ) || filePath === '.' || filePath === '..'; + + if( !isDotted ) + filePath = starter.path.canonizeTolerant( filePath ); + + if( isDotted && !isAbsolute ) + { + filePath = starter.path.canonizeTolerant( basePath + '/' + filePath ); + if( filePath[ 0 ] !== '/' ) + filePath = './' + filePath; + } + + if( !isDotted && !isAbsolute ) + { + if( starter.moduleMainFilesMap[ filePath ] ) + { + filePath = starter.moduleMainFilesMap[ filePath ].filePath; + } + else + { + let filePathLower = filePath.toLowerCase(); + if( starter.moduleMainFilesMap[ filePathLower ] ) + filePath = starter.moduleMainFilesMap[ filePathLower ].filePath; + } + } + + return _.path.nativize( filePath ); + } + + // + + function _Setup() + { + + if( this._inited ) + { + return; + } + + if( _starter_.catchingUncaughtErrors ) + { + _starter_.error._setupUncaughtErrorHandler2(); + _starter_.error._setupUncaughtErrorHandler9(); + } + + this._SetupAct(); + + this._inited = 1; + } + +; + + + let Extension = + { + + SourceFile, + + _sourceMake, + _sourceIncludeResolvedCalling, + _includeAct : null, + _sourceInclude, + _sourceResolveAct : null, + _sourceResolve, + _sourceOwnResolve, + _sourceForPathGet, + _sourceForInclude, + + _pathResolveLocal, + + _Setup, + + // fields + + redirectingConsole : null, + _inited : false, + + } + + for( let k in Extension ) + if( _starter_[ k ] === undefined ) + _starter_[ k ] = Extension[ k ]; + + _starter_._Setup(); + +; + +/* */ /* end of starter */ })(); + + +/* */ let _libraryFilePath_ = _starter_.path.canonizeTolerant( __filename ); +/* */ let _libraryDirPath_ = _starter_.path.canonizeTolerant( __dirname ); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wColor */ ( function wColor() { function wColor_naked() { +module.exports = require( '../wtools/amid/l1/color/entry/ColorBasic.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wColor', 'wcolor' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/node_modules/wColor' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wColor_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wColor */ })(); + +/* */ /* begin of file ColorBasic_s */ ( function ColorBasic_s() { function ColorBasic_s_naked() { ( function _ColorBasic_s_() +{ + +'use strict'; + +/** + * @summary Collection of cross-platform routines to operate colors conveniently. + * @namespace wTools.color + * @module Tools/mid/Color +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../include/Mid.s' ); + module[ 'exports' ] = _global_.wTools; +} + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/entry/ColorBasic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/entry' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ColorBasic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ColorBasic_s */ })(); + +/* */ /* begin of file Basic_s */ ( function Basic_s() { function Basic_s_naked() { ( function _Basic_s_( ) +{ + +'use strict'; + +/* Color */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../../node_modules/Tools' ); + module[ 'exports' ] = _global_.wTools; +} + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/include/Basic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Basic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Basic_s */ })(); + +/* */ /* begin of file Mid_s */ ( function Mid_s() { function Mid_s_naked() { ( function _Mid_s_( ) +{ + +'use strict'; + +/* color */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( './Basic.s' ); + require( '../l3/Color.s' ); + require( '../l3/Cmyk.s' ); + require( '../l3/Cmyka.s' ); + require( '../l3/Hwb.s' ); + require( '../l3/Hwba.s' ); + require( '../l3/Hsl.s' ); + require( '../l3/Hsla.s' ); + require( '../l3/Xyz.s' ); + require( '../l3/Xyza.s' ); + require( '../l3/Rgb.s' ); + require( '../l3/Rgba.s' ); + module[ 'exports' ] = _global_.wTools; +} + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/include/Mid.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Mid_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Mid_s */ })(); + +/* */ /* begin of file Cmyk_s */ ( function Cmyk_s() { function Cmyk_s_naked() { (function _ColorCmyk_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to convert from cmyk into rgb. + * @module Tools/mid/Color +*/ + +/** + * @summary Collection of cross-platform routines to operate colors conveniently. + * @namespace wTools.color.cmyk + * @module Tools/mid/Color +*/ + +const _ = _global_.wTools; +const Self = _.color.cmyk = _.color.cmyk || Object.create( null ); + +// -- +// implement +// -- + +function _strToRgb( dst, src ) +{ + /* + cmyk(C, M, Y, K) + */ + + _.assert( arguments.length === 2, 'Expects 2 arguments' ); + _.assert( _.strIs( src ) ); + _.assert( dst === null || _.vectorIs( dst ) ); + + let cmykColors = _.color.cmyk._formatStringParse( src ); + + _.assert + ( + cmykColors.length === 4 || cmykColors.length === 5, + `{-src-} string must contain exactly 4 or 5 numbers, but got ${cmykColors.length}` + ); + _.assert + ( + cmykColors[ 4 ] === undefined || cmykColors[ 4 ] === 100, + `alpha channel must be 100, but got ${cmykColors[ 4 ]}` + ); + + if( !_.color.cmyk._validate( cmykColors ) ) + return null; + + /* normalize ranges */ + cmykColors[ 0 ] = cmykColors[ 0 ] / 100; + cmykColors[ 1 ] = cmykColors[ 1 ] / 100; + cmykColors[ 2 ] = cmykColors[ 2 ] / 100; + cmykColors[ 3 ] = cmykColors[ 3 ] / 100; + if( cmykColors[ 4 ] ) + cmykColors[ 4 ] = cmykColors[ 4 ] / 100; + + return _.color.cmyk._longToRgb( dst, cmykColors ); + +} + +// + +function _longToRgb( dst, src ) +{ + _.assert( src.length === 4 || src.length === 5, `{-src-} length must be 4 or 5, but got : ${src.length}` ); + _.assert( src[ 4 ] === undefined || src[ 4 ] === 1, `alpha channel must be 1, but got : ${src[ 5 ]}` ); + + if( !_.color._validateNormalized( src ) ) + return null; + + let r, g, b; + + if( dst === null || _.longIs( dst ) ) + { + dst = dst || new Array( 3 ); + _.assert( dst.length === 3, `{-dst-} container length must be 3, but got : ${dst.length}` ); + + convert( src ); + + /* + TypedArray: + + For non-basic colors with r, g, b values in range ( 0, 1 ) + only instances of those constructors can be used + Float32Array, + Float64Array, + */ + + dst[ 0 ] = r; + dst[ 1 ] = g; + dst[ 2 ] = b; + + } + else if( _.vadIs( dst ) ) + { + /* optional dependency */ + + _.assert( dst.length === 3, `{-dst-} container length must be 3, but got : ${dst.length}` ); + + convert( src ); + + dst.eSet( 0, r ); + dst.eSet( 1, g ); + dst.eSet( 2, b ); + } + else _.assert( 0, '{-dts-} container must be of type Vector' ); + + return dst; + + /* - */ + + function convert( src ) + { + r = ( 1 - src[ 0 ] ) * ( 1 - src[ 3 ] ); + g = ( 1 - src[ 1 ] ) * ( 1 - src[ 3 ] ); + b = ( 1 - src[ 2 ] ) * ( 1 - src[ 3 ] ); + } + +} + +// + +function _validate ( src ) +{ + if + ( + !_.cinterval.has( [ 0, 100 ], src[ 0 ] ) + || !_.cinterval.has( [ 0, 100 ], src[ 1 ] ) + || !_.cinterval.has( [ 0, 100 ], src[ 2 ] ) + || !_.cinterval.has( [ 0, 100 ], src[ 3 ] ) + ) + return false; + + return true; +} + +// + +function _formatStringParse( src ) +{ + _.assert( /^cmyk\(\d{1,3}%,\d{1,3}%,\d{1,3}%,\d{1,3}%(,\d{1,3}%)?\)$/g.test( src ), 'Wrong source string pattern' ); + return src.match( /\d+(\.\d+)?/g ).map( ( el ) => +el ); +} + +// -- +// declare +// -- + +let Extension = +{ + + // to rgb/a + + _strToRgb, + _longToRgb, + _validate, + + _formatStringParse + +} + +_.props.supplement( _.color.cmyk, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3/Cmyk.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Cmyk_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Cmyk_s */ })(); + +/* */ /* begin of file Cmyka_s */ ( function Cmyka_s() { function Cmyka_s_naked() { (function _ColorCmyka_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to convert from cmyka ( a - alpha channel ) into rgba. + * @module Tools/mid/Color +*/ + +/** + * @summary Collection of cross-platform routines to operate colors conveniently. + * @namespace wTools.color.cmyka + * @module Tools/mid/Color +*/ + +const _ = _global_.wTools; +const Self = _.color.cmyka = _.color.cmyka || Object.create( null ); + +// -- +// implement +// -- + +function _strToRgba( dst, src ) +{ + /* + cmyka(C, M, Y, K, A) + */ + + _.assert( arguments.length === 2, 'Expects 2 arguments' ); + _.assert( _.strIs( src ) ); + _.assert( dst === null || _.vectorIs( dst ) ); + + let cmykColors = _.color.cmyka._formatStringParse( src ); + _.assert + ( + cmykColors.length === 4 || cmykColors.length === 5, + `{-src-} string must contain exactly 4 or 5 numbers, but got ${cmykColors.length}` + ); + + if( !_.color.cmyka._validate( cmykColors ) ) + return null; + + /* normalize ranges */ + cmykColors[ 0 ] = cmykColors[ 0 ] / 100; + cmykColors[ 1 ] = cmykColors[ 1 ] / 100; + cmykColors[ 2 ] = cmykColors[ 2 ] / 100; + cmykColors[ 3 ] = cmykColors[ 3 ] / 100; + if( cmykColors[ 4 ] ) + cmykColors[ 4 ] = cmykColors[ 4 ] / 100; + + return _.color.cmyka._longToRgba( dst, cmykColors ); + +} + +// + +function _longToRgba( dst, src ) +{ + + _.assert( src.length === 4 || src.length === 5, `{-src-} length must be 4 or 5, but got : ${src.length}` ); + + if( !_.color._validateNormalized( src ) ) + return null; + + let r, g, b; + let a = 1; + /* qqq : bad! + assert + alpha channel + + aaa : Added + */ + + if( dst === null || _.longIs( dst ) ) + { + dst = dst || new Array( 4 ); + + _.assert( dst.length === 4, `{-dst-} container length must be 4, but got : ${dst.length}` ); + + convert( src ); + + /* + TypedArray: + + For non-basic colors with r, g, b values range ( 0, 1 ) + only instances of those constructors can be used + Float32Array, + Float64Array, + */ + + dst[ 0 ] = r; + dst[ 1 ] = g; + dst[ 2 ] = b; + dst[ 3 ] = a; + + } + else if( _.vadIs( dst ) ) + { + /* optional dependency */ + + _.assert( dst.length === 4, `{-dst-} container length must be 4, but got : ${dst.length}` ); + + convert( src ); + + dst.eSet( 0, r ); + dst.eSet( 1, g ); + dst.eSet( 2, b ); + dst.eSet( 3, a ); + + } + else _.assert( 0, '{-dts-} container must be of type Vector' ); + + return dst; + + /* - */ + + function convert( src ) + { + r = ( 1 - src[ 0 ] ) * ( 1 - src[ 3 ] ); + g = ( 1 - src[ 1 ] ) * ( 1 - src[ 3 ] ); + b = ( 1 - src[ 2 ] ) * ( 1 - src[ 3 ] ); + if( src[ 4 ] !== undefined ) + a = src[ 4 ]; + } + +} + +// + +function _validate ( src ) +{ + if + ( + !_.cinterval.has( [ 0, 100 ], src[ 0 ] ) + || !_.cinterval.has( [ 0, 100 ], src[ 1 ] ) + || !_.cinterval.has( [ 0, 100 ], src[ 2 ] ) + || !_.cinterval.has( [ 0, 100 ], src[ 3 ] ) + || src[ 4 ] !== undefined && !_.cinterval.has( [ 0, 100 ], src[ 4 ] ) + ) + return false; + + return true; +} + +// + +function _formatStringParse( src ) +{ + _.assert( /^cmyka\(\d{1,3}%,\d{1,3}%,\d{1,3}%,\d{1,3}%(,\d{1,3}%)?\)$/g.test( src ), 'Wrong source string pattern' ); + return src.match( /\d+(\.\d+)?/g ).map( ( el ) => +el ); +} + + +// -- +// declare +// -- + +let Extension = +{ + + // to rgba + + _strToRgba, + _longToRgba, + _validate, + _formatStringParse + +} + +_.props.supplement( _.color.cmyka, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3/Cmyka.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Cmyka_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Cmyka_s */ })(); + +/* */ /* begin of file Color_s */ ( function Color_s() { function Color_s_naked() { (function _Color_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to operate colors conveniently. Color provides functions to convert color from one color space to another color space, from name to color and from color to the closest name of a color. The module does not introduce any specific storage format of color what is a benefit. Color has a short list of the most common colors. Use the module for formatted colorful output or other sophisticated operations with colors. + @module Tools/mid/Color +*/ + +/** + * @summary Collection of cross-platform routines to operate colors conveniently. + * @namespace wTools.color + * @module Tools/mid/Color +*/ + +const _ = _global_.wTools; +const Self = _.color = _.color || Object.create( null ); + +// -- +// implement +// -- + +function _fromTable( o ) +{ + let result = o.colorMap[ o.src ]; + + _.routine.assertOptions( _fromTable, o ); + + if( !result ) + result = o.def; + + if( result ) + result = result.slice(); + + return result; +} + +_fromTable.defaults = +{ + src : null, + def : null, + colorMap : null, +} + +// + +/** + * @summary Returns rgb value for color with provided `name`. + * @param {String} name Target color name. + * @param {*} def Default value. Is used if nothing was found. + * @example + * _.color.fromTable( 'black' ); + * @example + * _.color.fromTable( 'black', [ 0, 0, 0 ] ); + * @throws {Error} If no arguments provided. + * @function fromTable + * @namespace wTools.color + * @module Tools/mid/Color + */ + +// function fromTable( name, def, colorMap ) +function fromTable( o ) +{ + // let o = _.routineOptionsFromThis( fromTable, this, Self ); + + if( !_.mapIs( o ) ) + o = + { + src : arguments[ 0 ], + def : ( arguments.length > 1 ? arguments[ 1 ] : null ), + colorMap : ( arguments.length > 2 ? arguments[ 2 ] : null ), + } + + let result; + if( !o.colorMap ) + o.colorMap = this.ColorMap; + + _.routine.options_( fromTable, o ); + _.assert( arguments.length <= 3 ); + _.assert( _.strIs( o.src ) ); + + o.src = o.src.toLowerCase(); + o.src = o.src.trim(); + + return this._fromTable( o ); + // return this._fromTable( o.src, o.def, o.colorMap ); +} + +fromTable.defaults = +{ + ... _fromTable.defaults, +} + +// + +/** + * @summary Gets rgb values from bitmask `src`. + * @param {Number} src Source bitmask. + * @example + * _.color.rgbByBitmask( 0xff00ff ); + * //[1, 0, 1] + * @throws {Error} If no arguments provided. + * @function rgbByBitmask + * @namespace wTools.color + * @module Tools/mid/Color + */ + +function rgbByBitmask( src ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.numberIs( src ) ); + + return _rgbByBitmask( src ); +} + +// + +function _rgbByBitmask( src ) +{ + let result = []; + + result[ 0 ] = ( ( src >> 16 ) & 0xff ) / 255; + result[ 1 ] = ( ( src >> 8 ) & 0xff ) / 255; + result[ 2 ] = ( ( src >> 0 ) & 0xff ) / 255; + + return result; +} + +// + +function _rgbaFromNotName( src ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.numberIs( src ) || _.longIs( src ) || _.object.isBasic( src ) ); + + if( _.object.isBasic( src ) ) + { + _.map.assertHasOnly( src, { r : null, g : null, b : null, a : null } ); + let result = []; + result[ 0 ] = src.r === undefined ? 1 : src.r; + result[ 1 ] = src.g === undefined ? 1 : src.g; + result[ 2 ] = src.b === undefined ? 1 : src.b; + result[ 3 ] = src.a === undefined ? 1 : src.a; + return result; + } + + if( _.numberIs( src ) ) + { + let result = this._rgbByBitmask( src ); + return _.longGrow_( result, result, [ 0, 3 ], 1 ); + } + + let result = []; + + /* */ + + for( let r = 0 ; r < src.length ; r++ ) + result[ r ] = Number( src[ r ] ); + + if( result.length < 4 ) + result[ 3 ] = 1; + + /* */ + + return result; +} + +// + +/** + * @summary Returns rgba color values for provided entity `src`. + * @param {Number|Array|String|Object} src Source entity. + * @example + * _.color.rgbaFrom( 0xFF0080 ); + * //[ 1, 0, 0.5, 1 ] + * + * @example + * _.color.rgbaFrom( { r : 0 } ); + * //[ 0, 1, 1, 1 ] + * + * @example + * _.color.rgbaFrom( 'white' ); + * //[ 1, 1, 1, 1 ] + * + * @example + * _.color.rgbaFrom( '#ffffff ); + * //[ 1, 1, 1, 1 ] + * + * @example + * _.color.rgbaFrom( [ 1, 1, 1 ] ); + * //[ 1, 1, 1, 1 ] + * + * @throws {Error} If no arguments provided. + * @function rgbaFrom + * @namespace wTools.color + * @module Tools/mid/Color + */ + +function rgbaFrom( o ) +{ + + if( !_.mapIs( o ) ) + o = { src : arguments[ 0 ], colorMap : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options_( rgbaFrom, o ); + + let result = this.rgbaFromTry( o ); + + if( !result ) + debugger; + if( !result ) + throw _.err( `Not color : "${_.entity.exportStringDiagnosticShallow( o.src )}"` ); + + return result; + + // let result; + // + // if( !_.mapIs( o ) ) + // o = { src : arguments[ 0 ], colorMap : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + // + // _.assert( arguments.length === 1, 'Expects single argument' ); + // _.routine.options_( rgnaFrom, arguments ); + // + // if( _.numberIs( o.src ) || _.longIs( o.src ) || ( !_.mapIs( o.src ) && _.object.isBasic( o.src ) ) ) + // return this._rgbaFromNotName( o.src ); + // + // /* */ + // + // if( _.strIs( o.src ) ) + // result = this.fromTable( o ); + // + // if( result ) + // return end(); + // + // /* */ + // + // if( _.strIs( o.src ) ) + // result = _.color.hexToColor( o.src ); + // + // if( result ) + // return end(); + // + // /* */ + // + // _.assertWithoutBreakpoint( 0, 'Unknown color', _.strQuote( o.src ) ); + // + // function end() + // { + // _.assert( _.longIs( result ) ); + // if( result.length !== 4 ) + // result = _.longGrow_( result, result, [ 0, 3 ], 1 ); /* xxx : replace */ + // return result; + // } + +} + +rgbaFrom.defaults = +{ + src : null, + colorMap : null, +} + +// + +/** + * @summary Short-cut for {@link module:Tools/mid/Color.wTools.color.rgbaFrom}. + * @description Returns rgb color values for provided entity `src`. + * @param {Number|Array|String|Object} src Source entity. + * @example + * _.color.rgbFrom( 0xFF0080 ); + * //[ 1, 0, 0.5 ] + * + * @example + * _.color.rgbFrom( { r : 0 } ); + * //[ 0, 1, 1 ] + * + * @example + * _.color.rgbFrom( 'white' ); + * //[ 1, 1, 1 ] + * + * @example + * _.color.rgbFrom( '#ffffff ); + * //[ 1, 1, 1 ] + * + * @example + * _.color.rgbFrom( [ 1, 1, 1 ] ); + * //[ 1, 1, 1 ] + * + * @throws {Error} If no arguments provided. + * @function rgbFrom + * @namespace wTools.color + * @module Tools/mid/Color + */ + +function rgbFrom( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.longIs( src ) ) + return _.longSlice( src, 0, 3 ); + + let result = rgbaFrom.call( this, src ); + + return _.longSlice( result, 0, 3 ); +} + +rgbFrom.defaults = +{ + ... rgbaFrom.defaults, +} + +// rgbFrom.defaults.__proto__ = rgbaFrom.defaults; + +// + +/** + * @summary Short-cut for {@link module:Tools/mid/Color.wTools.color.rgbaFromTry}. + * @description Returns rgba color values for provided entity `src` or default value if nothing was found. + * @param {Number|Array|String|Object} src Source entity. + * @param {Array} def Default value. + * + * @example + * _.color.rgbaFromTry( 'some_color', [ 1, 0, 0.5, 1 ] ); + * //[ 1, 0, 0.5, 1 ] + * + * @throws {Error} If no arguments provided. + * @function rgbaFromTry + * @namespace wTools.color + * @module Tools/mid/Color + */ + +// function rgbaFromTry( src, def ) +function rgbaFromTry( o ) +{ + let result; + + if( !_.mapIs( o ) ) + o = { src : arguments[ 0 ] }; + + _.assert( arguments.length === 1 ); + _.routine.options_( rgbaFromTry, o ); + + if( _.numberIs( o.src ) || _.longIs( o.src ) || ( !_.mapIs( o.src ) && _.object.isBasic( o.src ) ) ) + return this._rgbaFromNotName( o.src ); + + /* */ + + if( _.strIs( o.src ) ) + result = this.fromTable( o ); + + if( result ) + return end(); + + /* */ + + if( _.strIs( o.src ) ) + result = _.color.hexToColor( o.src ); + + if( result ) + return end(); + + /* */ + + return o.def; + + function end() + { + _.assert( _.longIs( result ) ); + if( result.length !== 4 ) + result = _.longGrow_( result, result, [ 0, 3 ], 1 ); /* xxx : replace */ + return result; + } + +} + +rgbaFromTry.defaults = +{ + ... rgbaFrom.defaults, + def : null, +} + +// { +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// +// try +// { +// return rgbaFrom.call( this, src ); +// } +// catch( err ) +// { +// return def; +// } +// +// } +// +// rgbaFromTry.defaults = +// { +// } +// +// rgbaFromTry.defaults.__proto__ = rgbaFrom.defaults; + +// + +/** + * @summary Short-cut for {@link module:Tools/mid/Color.wTools.color.rgbaFrom}. + * @description Returns rgb color values for provided entity `src` or default value if nothing was found. + * @param {Number|Array|String|Object} src Source entity. + * @param {Array} def Default value. + * + * @example + * _.color.rgbFrom( 'some_color', [ 1, 0, 0.5 ] ); + * //[ 1, 0, 0.5 ] + * + * @throws {Error} If no arguments provided. + * @function rgbFromTry + * @namespace wTools.color + * @module Tools/mid/Color + */ + +function rgbFromTry( src, def ) +{ + + _.assert( arguments.length === 2, 'Expects single argument' ); + + if( _.longIs( src ) ) + return _.longSlice( src, 0, 3 ); + + let result = rgbaFrom.call( this, src ); + + if( !result ) + result = def; + + if( result !== null ) + result = _.longSlice( result, 0, 3 ); + + return result; + + // try + // { + // return rgbFrom.call( this, src ); + // } + // catch( err ) + // { + // return def; + // } + +} + +rgbFromTry.defaults = +{ + ... rgbaFrom.defaults, + def : null, +} + +// rgbFromTry.defaults = +// { +// } +// +// rgbFromTry.defaults.__proto__ = rgbaFrom.defaults; + + +function rgbaHtmlFrom( o ) +{ + + if( !_.mapIs( o ) ) + o = { src : arguments[ 0 ], colorMap : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options_( rgbaHtmlFrom, o ); + + let result = this.rgbaHtmlFromTry( o ); + + if( !result ) + debugger; + if( !result ) + throw _.err( `Not color : "${_.entity.exportStringDiagnosticShallow( o.src )}"` ); + + return result; + + // let result; + // + // if( !_.mapIs( o ) ) + // o = { src : arguments[ 0 ], colorMap : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + // + // _.assert( arguments.length === 1, 'Expects single argument' ); + // _.routine.options_( rgnaFrom, arguments ); + // + // if( _.numberIs( o.src ) || _.longIs( o.src ) || ( !_.mapIs( o.src ) && _.object.isBasic( o.src ) ) ) + // return this._rgbaFromNotName( o.src ); + // + // /* */ + // + // if( _.strIs( o.src ) ) + // result = this.fromTable( o ); + // + // if( result ) + // return end(); + // + // /* */ + // + // if( _.strIs( o.src ) ) + // result = _.color.hexToColor( o.src ); + // + // if( result ) + // return end(); + // + // /* */ + // + // _.assertWithoutBreakpoint( 0, 'Unknown color', _.strQuote( o.src ) ); + // + // function end() + // { + // _.assert( _.longIs( result ) ); + // if( result.length !== 4 ) + // result = _.longGrow_( result, result, [ 0, 3 ], 1 ); /* xxx : replace */ + // return result; + // } + +} + +rgbaHtmlFrom.defaults = +{ + src : null, + colorMap : null, +} + +// + +function rgbHtmlFrom( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.longIs( src ) ) + return _.longSlice( src, 0, 3 ); + + let result = rgbaHtmlFrom.call( this, src ); + + return _.longSlice( result, 0, 3 ); +} + +rgbHtmlFrom.defaults = +{ + ... rgbaHtmlFrom.defaults, +} + +// + +function rgbaHtmlFromTry( o ) +{ + let result; + + if( !_.mapIs( o ) ) + o = { src : arguments[ 0 ] }; + + _.assert( arguments.length === 1 ); + _.routine.options_( rgbaHtmlFromTry, o ); + + if( _.numberIs( o.src ) || _.longIs( o.src ) || ( !_.mapIs( o.src ) && _.object.isBasic( o.src ) ) ) + return this._rgbaFromNotName( o.src ); + + /* */ + + if( _.strIs( o.src ) ) + result = this.fromTable( o ); + + if( result ) + return end(); + + /* */ + + if( _.strIs( o.src ) ) + result = _.color.hexToColor( o.src ); + + if( result ) + return end(); + + if( _.strIs( o.src ) ) + result = _.color.rgbaHtmlToRgba( o.src ); + + if( result ) + return end(); + + if( _.strIs( o.src ) ) + result = _.color.hslaToRgba( o.src ); + + if( result ) + return end(); + + /* */ + + return o.def; + + function end() + { + _.assert( _.longIs( result ) ); + if( result.length !== 4 ) + result = _.longGrow_( result, result, [ 0, 3 ], 1 ); /* xxx : replace */ + return result; + } + +} + +rgbaHtmlFromTry.defaults = +{ + ... rgbaHtmlFrom.defaults, + def : null, +} + +// + +function rgbHtmlFromTry( src, def ) +{ + + _.assert( arguments.length === 2, 'Expects single argument' ); + + if( _.longIs( src ) ) + return _.longSlice( src, 0, 3 ); + + let result = rgbaHtmlFrom.call( this, src ); + + if( !result ) + result = def; + + if( result !== null ) + result = _.longSlice( result, 0, 3 ); + + return result; + + // try + // { + // return rgbFrom.call( this, src ); + // } + // catch( err ) + // { + // return def; + // } + +} + +rgbHtmlFromTry.defaults = +{ + ... rgbaHtmlFrom.defaults, + def : null, +} + +// + +function rgbaHtmlToRgba( src ) +{ + _.assert( _.strDefined( src ) ); + + let splitted = _.strSplitFast + ({ + src, + delimeter : [ '(', ')', ',' ], + preservingDelimeters : 0, + preservingEmpty : 0 + }) + + if( _.strBegins( splitted[ 0 ], 'rgb' ) ) + { + let result = + [ + parseInt( splitted[ 1 ] ) / 255, + parseInt( splitted[ 2 ] ) / 255, + parseInt( splitted[ 3 ] ) / 255, + 1 + ] + + if( splitted[ 0 ] === 'rgba' ) + result[ 3 ] = Number( splitted[ 4 ] ) + + return result; + } + + return null; +} + + +// + +function _colorDistance( c1, c2 ) +{ + _.assert( _.longIs( c1 ) ); + _.assert( _.longIs( c2 ) ); + + let a = c1.slice(); + let b = c2.slice(); + + // function _definedIs( src ) + // { + // return src !== undefined && src !== null && !isNaN( src ) + // } + + for( let i = 0 ; i < 4 ; i++ ) + { + if( !_.numberIsFinite( a[ i ] ) ) + // a[ i ] = _definedIs( b[ i ] ) ? b[ i ] : 1; + a[ i ] = 1; + + if( !_.numberIsFinite( b[ i ] ) ) + // b[ i ] = _definedIs( a[ i ] ) ? a[ i ] : 1; + b[ i ] = 1; + } + + // a[ 3 ] = _definedIs( a[ 3 ] ) ? a[ i ] : 1; + // b[ 3 ] = _definedIs( b[ 3 ] ) ? b[ i ] : 1; + + return Math.pow( a[ 0 ] - b[ 0 ], 2 ) + + Math.pow( a[ 1 ] - b[ 1 ], 2 ) + + Math.pow( a[ 2 ] - b[ 2 ], 2 ) + + Math.pow( a[ 3 ] - b[ 3 ], 2 ) +} + +// + +function _colorNameNearest( color, map ) +{ + let self = this; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( arguments.length === 1 ) + map = _.color.ColorMap; + + _.assert( _.object.isBasic( map ) ); + + if( _.strIs( color ) ) + { + _.assertWithoutBreakpoint( map[ color ], 'Unknown color', _.strQuote( color ) ); + + if( _.objectLike( map[ color ] ) ) + { + _.assert( map[ color ].name ); + return self._colorNameNearest( map[ color ].name, map ); + } + + return color; + } + + color = this._rgbaFromNotName( color ); + + _.assert( color.length === 4 ); + + for( let r = 0 ; r < 4 ; r++ ) + { + color[ r ] = Number( color[ r ] ); + if( color[ r ] < 0 ) + color[ r ] = 0; + else if( color[ r ] > 1 ) + color[ r ] = 1; + } + + // if( color[ 3 ] === undefined ) + // color[ 3 ] = 1; + + /* */ + + let names = Object.keys( map ); + let nearest = names[ 0 ]; + let max = this._colorDistance( map[ names[ 0 ] ], color ); + + if( max === 0 ) + return nearest; + + for( let i = 1; i <= names.length - 1; i++ ) + { + let d = this._colorDistance( map[ names[ i ] ], color ); + if( d < max ) + { + max = d; + nearest = names[ i ]; + } + + if( d === 0 ) + return names[ i ]; + } + + return nearest; +} + +// + +/** + * @summary Returns name of color that is nearest to provided `color`. + * @param {Number|Array|String|Object} color Source color. + * + * @example + * _.color.colorNameNearest( [ 1, 1, 1, 0.8 ] ); + * //'white' + * + * @example + * _.color.colorNameNearest( [ 1, 1, 1, 0.3 ] ); + * //'transparent' + * + * @throws {Error} If no arguments provided. + * @function colorNameNearest + * @namespace wTools.color + * @module Tools/mid/Color + */ + +function colorNameNearest( color ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.strIs( color ) ) + { + let color2 = _.color.hexToColor( color ); + if( color2 ) + color = color2; + } + + try + { + return self._colorNameNearest( color ); + } + catch( err ) + { + return; + } + +} + +// // +// +// function _colorNearest( o ) +// { +// let self = this; +// +// _.routine.options_( _colorNearest, o ); +// _.assert( arguments.length === 1, 'Expects single argument' ); +// +// if( _.strIs( o.color ) ) +// { +// let _color = _.color.hexToColor( o.color ); +// if( _color ) +// o.color = _color; +// } +// +// try +// { +// let name = self._colorNameNearest( o.color, o.colorMap ); +// return o.colorMap[ name ]; +// } +// catch( err ) +// { +// return; +// } +// } +// +// _colorNearest.defaults = +// { +// color : null, +// colorMap : null +// } + +// + +/** + * @summary Returns value of color that is nearest to provided `color`. + * @param {Number|Array|String|Object} color Source color. + * + * @example + * _.color.colorNearest( [ 1, 1, 1, 0.8 ] ); + * //[ 1, 1, 1, 1 ] + * + * @throws {Error} If no arguments provided. + * @function colorNameNearest + * @namespace wTools.color + * @module Tools/mid/Color + */ + +function colorNearest( color ) +{ + let self = this; + + let name = self.colorNameNearest( color ); + if( name ) + return self.ColorMap[ name ]; +} + +// + +/** + * @summary Returns hex value for provided color `rgb`. + * @param {Number|Array|String|Object} color Source color. + * @param {Array} def Default value. + * + * @example + * _.color.colorToHex( [ 1, 0, 1 ] ); + * //'#ff00ff' + * + * @throws {Error} If no arguments provided. + * @function colorToHex + * @namespace wTools.color + * @module Tools/mid/Color + */ + +function colorToHex( rgb, def ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ) + + if( _.arrayIs( rgb ) ) + { + return '#' + ( ( 1 << 24 ) + ( Math.floor( rgb[ 0 ]*255 ) << 16 ) + ( Math.floor( rgb[ 1 ]*255 ) << 8 ) + Math.floor( rgb[ 2 ]*255 ) ) + .toString( 16 ).slice( 1 ); + } + else if( _.numberIs( rgb ) ) + { + let hex = Math.floor( rgb ).toString( 16 ); + return '#' + _.strDup( '0', 6 - hex.length ) + hex; + } + else if( _.object.isBasic( rgb ) ) + { + return '#' + ( ( 1 << 24 ) + ( Math.floor( rgb.r*255 ) << 16 ) + ( Math.floor( rgb.g*255 ) << 8 ) + Math.floor( rgb.b*255 ) ) + .toString( 16 ).slice( 1 ); + } + else if( _.strIs( rgb ) ) + { + if( !rgb.length ) + return def; + else if( rgb[ 0 ] === '#' ) + return rgb; + else + return '#' + rgb; + } + + return def; +} + +// + +/** + * @summary Returns rgb value for provided `hex` value. + * @param {String} hex Source color. + * + * @example + * _.color.colorToHex( '#ff00ff' ); + * //[ 1, 0, 1 ] + * + * @throws {Error} If no arguments provided. + * @function hexToColor + * @namespace wTools.color + * @module Tools/mid/Color + */ + +function hexToColor( hex ) +{ + return _.color.rgba.fromHexStr( hex ); +} + +// + +function colorToRgbHtml( src ) +{ + let result = ''; + + _.assert( _.strIs( src ) || _.object.isBasic( src ) || _.arrayIs( src ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + + if( _.strIs( src ) ) + return src; + + if( _.object.isBasic( src ) ) + src = [ src.r, src.g, src.b, src.a ]; + + if( _.arrayIs( src ) ) + { + for( let i = 0; i < 3; i++ ) + _.assert( src[ i ] >= 0 && src[ i ] <= 1 ) + + result += 'rgb( '; + result += String( Math.floor( src[ 0 ]*255 ) ) + ', '; + result += String( Math.floor( src[ 1 ]*255 ) ) + ', '; + result += String( Math.floor( src[ 2 ]*255 ) ); + result += ' )'; + } + else result = src; + + //console.log( 'colorHtmlToRgbHtml', result ); + + return result; +} + +// + +function colorToRgbaHtml( src ) +{ + let result = ''; + + _.assert( _.strIs( src ) || _.object.isBasic( src ) || _.arrayIs( src ) || _.numberIs( src ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.strIs( src ) ) + return src; + + if( _.object.isBasic( src ) ) + src = [ src.r, src.g, src.b, src.a ]; + + if( _.arrayIs( src ) ) + { + for( let i = 0; i < 3; i++ ) + _.assert( src[ i ] >= 0 && src[ i ] <= 1 ) + + result += 'rgba( '; + result += String( Math.floor( src[ 0 ]*255 ) ) + ', '; + result += String( Math.floor( src[ 1 ]*255 ) ) + ', '; + result += String( Math.floor( src[ 2 ]*255 ) ); + if( src[ 3 ] !== undefined ) + result += ', ' + String( src[ 3 ] ); + else + result += ', ' + '1'; + result += ' )'; + } + else if( _.numberIs( src ) ) + { + result = colorToRgbaHtml + ({ + r : ( ( src >> 16 ) & 0xff ) / 255, + g : ( ( src >> 8 ) & 0xff ) / 255, + b : ( ( src ) & 0xff ) / 255 + }); + } + else result = src; + + return result; +} + +// + +function mulSaturation( rgb, factor ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( factor >= 0 ); + + let hsl = rgbToHsl( rgb ); + + hsl[ 1 ] *= factor; + + let result = hslToRgb( hsl ); + + if( rgb.length === 4 ) + result[ 3 ] = rgb[ 3 ]; + + return result; +} + +// + +function brighter( rgb, factor ) +{ + if( factor === undefined ) + factor = 0.1; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( factor >= 0 ); + + return mulSaturation( rgb, 1 + factor ); +} + +// + +/* + ( 1+factor ) * c2 = c1 + ( 1-efactor ) * c1 = c2 + + ( 1-efactor ) * ( 1+factor ) = 1 + 1+factor-efactor-efactor*factor = 1 + factor-efactor-efactor*factor = 0 + -efactor( 1+factor ) = factor + efactor = - factor / ( 1+factor ) +*/ + +function paler( rgb, factor ) +{ + if( factor === undefined ) + factor = 0.1; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( 0 <= factor && factor <= 1 ); + + let efactor = factor / ( 1+factor ); + + return mulSaturation( rgb, 1 - efactor ); +} + +// -- +// int +// -- + +function colorWidthForExponential( width ) +{ + + return 1 + 63 * width; + +} + +// + +function rgbWithInt( srcInt ) +{ + let result = []; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.numberIs( srcInt ), 'rgbWithInt :', 'Expects srcInt' ); + + /* eval degree */ + + let degree = 1; + let left = srcInt; + + if( left >= 6 ) + { + + left -= 6; + degree = 2; + let n = 6; + let d = 0; + + while( left >= n ) + { + left -= n; + degree += 1; + d += 1; + n *= degree; + n /= d; + } + + } + + /* compose set of elements */ + + let set = [ 0.1 ]; + let e = 0.95; + if( degree >= 2 ) e = 0.8; + do + { + set.push( e ); + //e /= 2; + + if( set.length === 2 ) + { + e = 0.5; + } + else if( set.length === 3 ) + { + e = 0.35; + } + else if( set.length === 4 ) + { + e = 0.75; + } + else + { + e *= 0.5; + } + + } + while( set.length <= degree ); + let last = set.length - 1; + + /* fill routine */ + + function fillWithElements( i1, i2, i3 ) + { + result[ left ] = set[ i1 ]; + result[ ( left+1 )%3 ] = set[ i2 ]; + result[ ( left+2 )%3 ] = set[ i3 ]; + + return result; + } + + /* fill result vector */ + + if( degree === 1 ) + { + + if( left < 3 ) + return fillWithElements( last, 0, 0 ); + left -= 3; + + if( left < 3 ) + return fillWithElements( 0, last, last ); + left -= 3; + + } + + /* */ + + for( let c1 = set.length - 2 ; c1 >= 0 ; c1-- ) + { + + for( let c2 = c1 - 1 ; c2 >= 0 ; c2-- ) + { + + if( left < 3 ) + return fillWithElements( last, c1, c2 ); + left -= 3; + + if( left < 3 ) + return fillWithElements( last, c2, c1 ); + left -= 3; + + } + + } + + /* */ + + throw _.err( 'rgbWithInt :', 'No color for', srcInt ); +} + +// + +function _rgbWithInt( srcInt ) +{ + let result; + + _.assert( _.numberIs( srcInt ), 'rgbWithInt :', 'Expects srcInt' ); + + let c = 9; + + srcInt = srcInt % c; + srcInt -= 0.3; + if( srcInt < 0 ) srcInt += c; + //result = hslToRgb([ srcInt / 11, 1, 0.5 ]); + + result = hslToRgb([ srcInt / c, 1, 0.5 ]); + + return result; +} + +// -- +// hsl +// -- + +function hslToRgb( hsl, result ) +{ + result = result || []; + let h = hsl[ 0 ]; + let s = hsl[ 1 ]; + let l = hsl[ 2 ]; + + if( s === 0 ) /* Yevhen : achromatic, r = g = b = l, not 1 */ + { + result[ 0 ] = l; + result[ 1 ] = l; + result[ 2 ] = l; + return result; + } + + function get( a, b, h ) + { + + if( h < 0 ) h += 1; + if( h > 1 ) h -= 1; + + if( h < 1 / 6 )return b + ( a - b ) * 6 * h; + if( h < 1 / 2 )return a; + if( h < 2 / 3 )return b + ( a - b ) * 6 * ( 2 / 3 - h ); + + return b; + } + + let a = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); + let b = ( 2 * l ) - a; + + result[ 0 ] = get( a, b, h + 1 / 3 ); + result[ 1 ] = get( a, b, h ); + result[ 2 ] = get( a, b, h - 1 / 3 ); + + return result; +} + +// + +function hslaToRgba( hsla, result ) +{ + +} + +// + +function rgbToHsl( rgb, result ) +{ + result = result || []; + let hue, saturation, lightness; + let r = rgb[ 0 ]; + let g = rgb[ 1 ]; + let b = rgb[ 2 ]; + + let max = Math.max( r, g, b ); + const min = Math.min( r, g, b ); + + lightness = ( min + max ) / 2.0; + + if( min === max ) + { + + hue = 0; + saturation = 0; + + } + else + { + + let diff = max - min; + + if( lightness <= 0.5 ) + saturation = diff / ( max + min ); + else + saturation = diff / ( 2 - max - min ); + + switch( max ) + { + case r : hue = ( g - b ) / diff + ( g < b ? 6 : 0 ); break; + case g : hue = ( b - r ) / diff + 2; break; + case b : hue = ( r - g ) / diff + 4; break; + default : break + } + + hue /= 6; + + } + + result[ 0 ] = hue; + result[ 1 ] = saturation; + result[ 2 ] = lightness; + + return result; +} + +// + +function rgbaToHsla( rgba, result ) +{ + +} + +// + +// function colorToHslHtml( rgb ) +// { + +// } + +// // + +// function colorToHslaHtml( rgba ) +// { + +// } + +// -- +// random +// -- + +function randomHsl( s, l ) +{ + + _.assert( arguments.length <= 2 ); + + if( s === undefined ) + s = 1.0; + if( l === undefined ) + l = 0.5; + + let hsl = [ Math.random(), s, l ]; + + return hsl; +} + +// + +function randomRgbWithSl( s, l ) +{ + + _.assert( arguments.length <= 2 ); + + if( s === undefined ) + s = 1.0; + if( l === undefined ) + l = 0.5; + + let rgb = hslToRgb([ Math.random(), s, l ]); + + return rgb; +} + +// -- +// etc +// -- + +function gammaToLinear( dst ) +{ + + if( Object.isFrozen( dst ) ) + debugger; + + _.assert( dst.length === 3 || dst.length === 4 ); + + dst[ 0 ] = dst[ 0 ]*dst[ 0 ]; + dst[ 1 ] = dst[ 1 ]*dst[ 1 ]; + dst[ 2 ] = dst[ 2 ]*dst[ 2 ]; + + return dst; +} + +// + +function linearToGamma( dst ) +{ + + _.assert( dst.length === 3 || dst.length === 4 ); + + dst[ 0 ] = _.math.sqrt( dst[ 0 ] ); + dst[ 1 ] = _.math.sqrt( dst[ 1 ] ); + dst[ 2 ] = _.math.sqrt( dst[ 2 ] ); + + return dst; +} + +// -- +// str +// -- + +function strColorStyle( style ) +{ + return _.ct.styleObjectFor( style ); +} + +// + +function strStrip( srcStr ) +{ + return _.ct.strip( srcStr ); +} + +// -- +// etc +// -- + +function _validateNormalized( src ) +{ + for( let i = 0; i < src.length; i++ ) + { + if( !_.cinterval.has( [ 0, 1 ], src[ i ] ) ) + return false; + } + return true; +} + +// -- +// let +// -- + +let ColorMap = +{ + + 'invisible' : [ 0.0, 0.0, 0.0, 0.0 ], + 'transparent' : [ 1.0, 1.0, 1.0, 0.5 ], + + 'cyan' : [ 0.0, 1.0, 1.0 ], + 'magenta' : [ 1.0, 0.0, 1.0 ], + 'maroon' : [ 0.5, 0.0, 0.0 ], + 'dark green' : [ 0.0, 0.5, 0.0 ], + 'navy' : [ 0.0, 0.0, 0.5 ], + 'olive' : [ 0.5, 0.5, 0.0 ], + 'teal' : [ 0.0, 0.5, 0.5 ], + 'bright green' : [ 0.5, 1.0, 0.0 ], + 'spring green' : [ 0.0, 1.0, 0.5 ], + 'pink' : [ 1.0, 0.0, 0.5 ], + 'dark orange' : [ 1.0, 0.5, 0.0 ], + 'azure' : [ 0.0, 0.5, 1.0 ], + 'dark blue' : [ 0.0, 0.0, 0.63 ], + 'brown' : [ 0.65, 0.16, 0.16 ], + +} + +// + +let ColorMapGreyscale = +{ + + 'white' : [ 1.0, 1.0, 1.0 ], + 'smoke' : [ 0.9, 0.9, 0.9 ], + 'silver' : [ 0.75, 0.75, 0.75 ], + 'gray' : [ 0.5, 0.5, 0.5 ], + 'dim' : [ 0.35, 0.35, 0.35 ], + 'black' : [ 0.0, 0.0, 0.0 ], + +} + +// + +let ColorMapDistinguishable = +{ + + 'yellow' : [ 1.0, 1.0, 0.0 ], + 'purple' : [ 0.5, 0.0, 0.5 ], + 'orange' : [ 1.0, 0.65, 0.0 ], + 'bright blue' : [ 0.68, 0.85, 0.9 ], + 'red' : [ 1.0, 0.0, 0.0 ], + 'buff' : [ 0.94, 0.86, 0.51 ], + 'gray' : [ 0.5, 0.5, 0.5 ], + 'green' : [ 0.0, 1.0, 0.0 ], + 'purplish pink' : [ 0.96, 0.46, 0.56 ], + 'blue' : [ 0.0, 0.0, 1.0 ], + 'yellowish pink' : [ 1.0, 0.48, 0.36 ], + 'violet' : [ 0.5, 0.0, 1.0 ], + 'orange yellow' : [ 1.0, 0.56, 0.0 ], + 'purplish red' : [ 0.7, 0.16, 0.32 ], + 'greenish yellow' : [ 0.96, 0.78, 0.0 ], + 'reddish brown' : [ 0.5, 0.1, 0.05 ], + 'yellow green' : [ 0.57, 0.6, 0.0 ], + 'yellowish brown' : [ 0.34, 0.2, 0.08 ], + 'reddish orange' : [ 0.95, 0.23, 0.07 ], + 'olive green' : [ 0.14, 0.17, 0.09 ], + +} + +// -- +// declare +// -- + +let Extension = +{ + + // + + _fromTable, + fromTable, + + rgbByBitmask, + _rgbByBitmask, + + _rgbaFromNotName, + + rgbaFrom, //xxx: merge with rgbaHtml* or rename + rgbFrom, //xxx: merge with rgbaHtml* or rename + + rgbaFromTry, //xxx: merge with rgbaHtml* or rename + rgbFromTry, //xxx: merge with rgbaHtml* or rename + + rgbaHtmlFrom, //qqq: cover + rgbHtmlFrom, //qqq: cover + + rgbaHtmlFromTry, //qqq: cover + rgbHtmlFromTry, //qqq: cover + + rgbaHtmlToRgba, + + _colorDistance, + + _colorNameNearest, + colorNameNearest, + + // _colorNearest, + colorNearest, + + colorToHex, + hexToColor, + + colorToRgbHtml, + colorToRgbaHtml, + + mulSaturation, + brighter, + paler, + + // int + + colorWidthForExponential, + rgbWithInt, + _rgbWithInt, + + // hsl + + hslToRgb, //qqq:extend with support of hsl( h, s, l ), cover + hslaToRgba, //qqq:implement,extend with support of hsla( h, s, l, a ), cover + rgbToHsl, + rgbaToHsla, //qqq:implement,cover + + // colorToHslHtml, //qqq:implement,cover + // colorToHslaHtml, //qqq:implement,cover + + // random + + randomHsl, + randomRgb : randomRgbWithSl, + randomRgbWithSl, + + // etc + + gammaToLinear, + linearToGamma, + + // str + + /* xxx : remove */ + strBg : _.ct.bg, + strFg : _.ct.fg, + strFormat : _.ct.format, + strFormatEach : _.ct.format, + + strEscape : _.ct.escape, + strUnescape : _.ct.unescape, + strColorStyle, + + strStrip, + + // etc + + _validateNormalized, + + // let + + ColorMap, + ColorMapGreyscale, + ColorMapDistinguishable, + // ColorMapShell, + +} + +_.props.supplement( _.color, Extension ); +_.props.supplement( _.color.ColorMap, ColorMap ); +_.props.supplement( _.color.ColorMapGreyscale, ColorMapGreyscale ); +_.props.supplement( _.color.ColorMapDistinguishable, ColorMapDistinguishable ); + +_.props.supplement( _.color.ColorMap, ColorMapGreyscale ); +_.props.supplement( _.color.ColorMap, ColorMapDistinguishable ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3/Color.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Color_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Color_s */ })(); + +/* */ /* begin of file Hsl_s */ ( function Hsl_s() { function Hsl_s_naked() { (function _ColorHsl_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to convert from hsl into rgb. + * @module Tools/mid/Color +*/ + +/** + * @summary Collection of cross-platform routines to operate colors conveniently. + * @namespace wTools.color.hsl + * @module Tools/mid/Color +*/ + +const _ = _global_.wTools; +const Self = _.color.hsl = _.color.hsl || Object.create( null ); + +// -- +// implement +// -- + +function _strToRgb( dst, src ) +{ + /* + hsl(H, S, L) + */ + + _.assert( arguments.length === 2, 'Expects 2 arguments' ); + _.assert( _.strIs( src ) ); + _.assert( dst === null || _.vectorIs( dst ) ); + + let hslColors = _.color.hsl._formatStringParse( src ); + + _.assert + ( + hslColors.length === 3 || hslColors.length === 4, + `{-src-} string must contain exactly 3 or 4 numbers, but got ${hslColors.length}` + ); + _.assert + ( + hslColors[ 3 ] === undefined || hslColors[ 3 ] === 100, + `alpha channel must be 100, but got ${hslColors[ 3 ]}` + ); + + if( !_.color.hsl._validate( hslColors ) ) + return null; + + /* normalize ranges */ + hslColors[ 0 ] = hslColors[ 0 ] / 360; + hslColors[ 1 ] = hslColors[ 1 ] / 100; + hslColors[ 2 ] = hslColors[ 2 ] / 100; + if( hslColors[ 3 ] ) + hslColors[ 3 ] = hslColors[ 3 ] / 100; + + return _.color.hsl._longToRgb( dst, hslColors ); + +} + +// + +function _longToRgb( dst, src ) +{ + _.assert( src.length === 3 || src.length === 4, `{-src-} length must be 3 or 4, but got : ${src.length}` ); + _.assert( src[ 3 ] === undefined || src[ 3 ] === 1, `alpha channel must be 1, but got : ${src[ 3 ]}` ); + + if( !_.color._validateNormalized( src ) ) + return null; + + let r, g, b; + + if( dst === null || _.longIs( dst ) ) + { + dst = dst || new Array( 3 ); + _.assert( dst.length === 3, `{-dst-} container length must be 3, but got : ${dst.length}` ); + + convert( src ); + + /* + TypedArray: + + For non-basic colors with r, g, b values in range ( 0, 1 ) + only instances of those constructors can be used + Float32Array, + Float64Array, + */ + + dst[ 0 ] = r; + dst[ 1 ] = g; + dst[ 2 ] = b; + + } + else if( _.vadIs( dst ) ) + { + /* optional dependency */ + + _.assert( dst.length === 3, `{-dst-} container length must be 3, but got : ${dst.length}` ); + + convert( src ); + + dst.eSet( 0, r ); + dst.eSet( 1, g ); + dst.eSet( 2, b ); + } + else _.assert( 0, '{-dts-} container must be of type Vector' ); + + return dst; + + /* - */ + + function convert( src ) + { + [ r, g, b ] = _.color.hslToRgb( src ); + } + + +} + +// + +function _validate ( src ) +{ + if + ( + !_.cinterval.has( [ 0, 360 ], src[ 0 ] ) + || !_.cinterval.has( [ 0, 100 ], src[ 1 ] ) + || !_.cinterval.has( [ 0, 100 ], src[ 2 ] ) + ) + return false; + + return true; +} + +// + +function _formatStringParse( src ) +{ + _.assert( /^hsl\(\d{1,3}, ?\d{1,3}%, ?\d{1,3}%(, ?\d{1,3}%)?\)$/g.test( src ), 'Wrong source string pattern' ); + return src.match( /\d+(\.\d+)?/g ).map( ( el ) => +el ); +} + +// -- +// declare +// -- + +let Extension = +{ + + // to rgb/a + + _strToRgb, + _longToRgb, + _validate, + + _formatStringParse + +} + +_.props.supplement( _.color.hsl, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3/Hsl.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Hsl_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Hsl_s */ })(); + +/* */ /* begin of file Hsla_s */ ( function Hsla_s() { function Hsla_s_naked() { (function _ColorHsla_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to convert from hsla into rgb. + * @module Tools/mid/Color +*/ + +/** + * @summary Collection of cross-platform routines to operate colors conveniently. + * @namespace wTools.color.hsla + * @module Tools/mid/Color +*/ + +const _ = _global_.wTools; +const Self = _.color.hsla = _.color.hsla || Object.create( null ); + +// -- +// implement +// -- + +function _strToRgba( dst, src ) +{ + /* + hsla(H, S, L, A) + */ + + _.assert( arguments.length === 2, 'Expects 2 arguments' ); + _.assert( _.strIs( src ) ); + _.assert( dst === null || _.vectorIs( dst ) ); + + let hslaColors = _.color.hsla._formatStringParse( src ); + + _.assert + ( + hslaColors.length === 3 || hslaColors.length === 4, + `{-src-} string must contain exactly 3 or 4 numbers, but got ${hslaColors.length}` + ); + + if( !_.color.hsl._validate( hslaColors ) ) + return null; + + /* normalize ranges */ + hslaColors[ 0 ] = hslaColors[ 0 ] / 360; + hslaColors[ 1 ] = hslaColors[ 1 ] / 100; + hslaColors[ 2 ] = hslaColors[ 2 ] / 100; + if( hslaColors[ 3 ] ) + hslaColors[ 3 ] = hslaColors[ 3 ] / 100; + + return _.color.hsla._longToRgba( dst, hslaColors ); + +} + +// + +function _longToRgba( dst, src ) +{ + _.assert( src.length === 3 || src.length === 4, `{-src-} length must be 3 or 4, but got : ${src.length}` ); + + if( !_.color._validateNormalized( src ) ) + return null; + + let r, g, b; + let a = 1; + + if( dst === null || _.longIs( dst ) ) + { + dst = dst || new Array( 4 ); + _.assert( dst.length === 4, `{-dst-} container length must be 4, but got : ${dst.length}` ); + + convert( src ); + + /* + TypedArray: + + For non-basic colors with r, g, b values in range ( 0, 1 ) + only instances of those constructors can be used + Float32Array, + Float64Array, + */ + + dst[ 0 ] = r; + dst[ 1 ] = g; + dst[ 2 ] = b; + dst[ 3 ] = a; + + } + else if( _.vadIs( dst ) ) + { + /* optional dependency */ + + _.assert( dst.length === 4, `{-dst-} container length must be 4, but got : ${dst.length}` ); + + convert( src ); + + dst.eSet( 0, r ); + dst.eSet( 1, g ); + dst.eSet( 2, b ); + dst.eSet( 3, a ); + } + else _.assert( 0, '{-dts-} container must be of type Vector' ); + + return dst; + + /* - */ + + function convert( src ) + { + [ r, g, b ] = _.color.hslToRgb([ src[ 0 ], src[ 1 ], src[ 2 ] ]); + if( src[ 3 ] !== undefined ) + a = src[ 3 ]; + + } + + +} + +// + +function _validate ( src ) +{ + if + ( + !_.cinterval.has( [ 0, 360 ], src[ 0 ] ) + || !_.cinterval.has( [ 0, 100 ], src[ 1 ] ) + || !_.cinterval.has( [ 0, 100 ], src[ 2 ] ) + || src[ 3 ] !== undefined && !_.cinterval.has( [ 0, 100 ], src[ 3 ] ) + ) + return false; + + return true; +} + +// + +function _formatStringParse( src ) +{ + _.assert( /^hsla\(\d{1,3}, ?\d{1,3}%, ?\d{1,3}%(, ?\d{1,3}%)?\)$/g.test( src ), 'Wrong source string pattern' ); + return src.match( /\d+(\.\d+)?/g ).map( ( el ) => +el ); +} + +// -- +// declare +// -- + +let Extension = +{ + + // to rgb/a + + _strToRgba, + _longToRgba, + _validate, + + _formatStringParse + +} + +_.props.supplement( _.color.hsla, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3/Hsla.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Hsla_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Hsla_s */ })(); + +/* */ /* begin of file Hwb_s */ ( function Hwb_s() { function Hwb_s_naked() { (function _ColorHwb_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to convert from hwb into rgb. + * @module Tools/mid/Color +*/ + +/** + * @summary Collection of cross-platform routines to operate colors conveniently. + * @namespace wTools.color.hwb + * @module Tools/mid/Color +*/ + +const _ = _global_.wTools; +const Self = _.color.hwb = _.color.hwb || Object.create( null ); + +// -- +// implement +// -- + +function _strToRgb( dst, src ) +{ + /* + hwb(H, W, B) + */ + + _.assert( arguments.length === 2, 'Expects 2 arguments' ); + _.assert( _.strIs( src ) ); + _.assert( dst === null || _.vectorIs( dst ) ); + + let hwbColors = _.color.hwb._formatStringParse( src ); + + _.assert + ( + hwbColors.length === 3 || hwbColors.length === 4, + `{-src-} string must contain exactly 3 or 4 numbers, but got ${hwbColors.length}` + ); + _.assert + ( + hwbColors[ 3 ] === undefined || hwbColors[ 3 ] === 100, + `alpha channel must be 100, but got ${hwbColors[ 3 ]}` + ); + + if( !_.color.hwb._validate( hwbColors ) ) + return null; + + /* normalize ranges */ + hwbColors[ 0 ] = hwbColors[ 0 ] / 360; + hwbColors[ 1 ] = hwbColors[ 1 ] / 100; + hwbColors[ 2 ] = hwbColors[ 2 ] / 100; + if( hwbColors[ 3 ] ) + hwbColors[ 3 ] = hwbColors[ 3 ] / 100; + + return _.color.hwb._longToRgb( dst, hwbColors ); + +} + +// + +function _longToRgb( dst, src ) +{ + _.assert( src.length === 3 || src.length === 4, `{-src-} length must be 3 or 4, but got : ${src.length}` ); + _.assert( src[ 3 ] === undefined || src[ 3 ] === 1, `alpha channel must be 1, but got : ${src[ 3 ]}` ); + + if( !_.color._validateNormalized( src ) ) + return null; + + let r, g, b; + + if( dst === null || _.longIs( dst ) ) + { + dst = dst || new Array( 3 ); + _.assert( dst.length === 3, `{-dst-} container length must be 3, but got : ${dst.length}` ); + + convert( src ); + + /* + TypedArray: + + For non-basic colors with r, g, b values in range ( 0, 1 ) + only instances of those constructors can be used + Float32Array, + Float64Array, + */ + + dst[ 0 ] = r; + dst[ 1 ] = g; + dst[ 2 ] = b; + + } + else if( _.vadIs( dst ) ) + { + /* optional dependency */ + + _.assert( dst.length === 3, `{-dst-} container length must be 3, but got : ${dst.length}` ); + + convert( src ); + + dst.eSet( 0, r ); + dst.eSet( 1, g ); + dst.eSet( 2, b ); + } + else _.assert( 0, '{-dts-} container must be of type Vector' ); + + return dst; + + /* - */ + + function convert( src ) + { + let h = src[ 0 ]; + let wh = src[ 1 ]; + let bl = src[ 2 ]; + let ratio = wh + bl; + let i, v, f, n; + + /* wh + bl cannot be > 1 */ + if( ratio > 1 ) + { + wh /= ratio; + bl /= ratio; + } + + i = Math.floor( 6 * h ); + v = 1 - bl; + f = 6 * h - i; + + if( ( i & 0x01 ) !== 0 ) + { + f = 1 - f; + } + + /* linear interpolation */ + n = wh + f * ( v - wh ); + + switch( i ) + { + case 6 : + case 0 : r = v; g = n; b = wh; break; + case 1 : r = n; g = v; b = wh; break; + case 2 : r = wh; g = v; b = n; break; + case 3 : r = wh; g = n; b = v; break; + case 4 : r = n; g = wh; b = v; break; + case 5 : r = v; g = wh; b = n; break; + default : break; + } + } + + +} + +// + +function _validate ( src ) +{ + if + ( + !_.cinterval.has( [ 0, 360 ], src[ 0 ] ) + || !_.cinterval.has( [ 0, 100 ], src[ 1 ] ) + || !_.cinterval.has( [ 0, 100 ], src[ 2 ] ) + ) + return false; + + return true; +} + +// + +function _formatStringParse( src ) +{ + _.assert( /^hwb\(\d{1,3}, ?\d{1,3}%, ?\d{1,3}%(, ?\d{1,3}%)?\)$/g.test( src ), 'Wrong source string pattern' ); + return src.match( /\d+(\.\d+)?/g ).map( ( el ) => +el ); +} + +// -- +// declare +// -- + +let Extension = +{ + + // to rgb/a + + _strToRgb, + _longToRgb, + _validate, + + _formatStringParse + +} + +_.props.supplement( _.color.hwb, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3/Hwb.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Hwb_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Hwb_s */ })(); + +/* */ /* begin of file Hwba_s */ ( function Hwba_s() { function Hwba_s_naked() { (function _ColorHwba_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to convert from hwb into rgb. + * @module Tools/mid/Color +*/ + +/** + * @summary Collection of cross-platform routines to operate colors conveniently. + * @namespace wTools.color.hwba + * @module Tools/mid/Color +*/ + +const _ = _global_.wTools; +const Self = _.color.hwba = _.color.hwba || Object.create( null ); + +// -- +// implement +// -- + +function _strToRgba( dst, src ) +{ + /* + hwba(H, W, B, A) + */ + + _.assert( arguments.length === 2, 'Expects 2 arguments' ); + _.assert( _.strIs( src ) ); + _.assert( dst === null || _.vectorIs( dst ) ); + + let hwbColors = _.color.hwba._formatStringParse( src ); + + _.assert + ( + hwbColors.length === 3 || hwbColors.length === 4, + `{-src-} string must contain exactly 3 or 4 numbers, but got ${hwbColors.length}` + ); + + if( !_.color.hwb._validate( hwbColors ) ) + return null; + + /* normalize ranges */ + hwbColors[ 0 ] = hwbColors[ 0 ] / 360; + hwbColors[ 1 ] = hwbColors[ 1 ] / 100; + hwbColors[ 2 ] = hwbColors[ 2 ] / 100; + if( hwbColors[ 3 ] ) + hwbColors[ 3 ] = hwbColors[ 3 ] / 100; + + return _.color.hwba._longToRgba( dst, hwbColors ); + +} + +// + +function _longToRgba( dst, src ) +{ + _.assert( src.length === 3 || src.length === 4, `{-src-} length must be 4 or 5, but got : ${src.length}` ); + + if( !_.color._validateNormalized( src ) ) + return null; + + let r, g, b; + let a = 1; + + if( dst === null || _.longIs( dst ) ) + { + dst = dst || new Array( 4 ); + _.assert( dst.length === 4, `{-dst-} container length must be 4, but got : ${dst.length}` ); + + convert( src ); + + /* + TypedArray: + + For non-basic colors with r, g, b values in range ( 0, 1 ) + only instances of those constructors can be used + Float32Array, + Float64Array, + */ + + dst[ 0 ] = r; + dst[ 1 ] = g; + dst[ 2 ] = b; + dst[ 3 ] = a; + + } + else if( _.vadIs( dst ) ) + { + /* optional dependency */ + + _.assert( dst.length === 4, `{-dst-} container length must be 4, but got : ${dst.length}` ); + + convert( src ); + + dst.eSet( 0, r ); + dst.eSet( 1, g ); + dst.eSet( 2, b ); + dst.eSet( 3, a ); + } + else _.assert( 0, '{-dts-} container must be of type Vector' ); + + return dst; + + /* - */ + + function convert( src ) + { + let h = src[ 0 ]; + let wh = src[ 1 ]; + let bl = src[ 2 ]; + let alpha = src[ 3 ]; + let ratio = wh + bl; + let i, v, f, n; + + /* wh + bl cannot be > 1 */ + if( ratio > 1 ) + { + wh /= ratio; + bl /= ratio; + } + + i = Math.floor( 6 * h ); + v = 1 - bl; + f = 6 * h - i; + + if( ( i & 0x01 ) !== 0 ) + { + f = 1 - f; + } + + /* linear interpolation */ + n = wh + f * ( v - wh ); + + switch( i ) + { + case 6 : + case 0 : r = v; g = n; b = wh; break; + case 1 : r = n; g = v; b = wh; break; + case 2 : r = wh; g = v; b = n; break; + case 3 : r = wh; g = n; b = v; break; + case 4 : r = n; g = wh; b = v; break; + case 5 : r = v; g = wh; b = n; break; + default : break; + } + + if( alpha !== undefined ) + a = alpha; + } + + +} + +// + +function _validate ( src ) +{ + if + ( + !_.cinterval.has( [ 0, 360 ], src[ 0 ] ) + || !_.cinterval.has( [ 0, 100 ], src[ 1 ] ) + || !_.cinterval.has( [ 0, 100 ], src[ 2 ] ) + || src[ 3 ] !== undefined && !_.cinterval.has( [ 0, 100 ], src[ 3 ] ) + ) + return false; + + return true; +} + +// + +function _formatStringParse( src ) +{ + _.assert( /^hwba\(\d{1,3}, ?\d{1,3}%, ?\d{1,3}%(, ?\d{1,3}%)?\)$/g.test( src ), 'Wrong source string pattern' ); + return src.match( /\d+(\.\d+)?/g ).map( ( el ) => +el ); +} + +// -- +// declare +// -- + +let Extension = +{ + + // to rgb/a + + _strToRgba, + _longToRgba, + _validate, + + _formatStringParse + +} + +_.props.supplement( _.color.hwba, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3/Hwba.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Hwba_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Hwba_s */ })(); + +/* */ /* begin of file Rgb_s */ ( function Rgb_s() { function Rgb_s_naked() { (function _ColorRgb_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to convert from hex into rgb. + * @module Tools/mid/Color +*/ + +/** + * @summary Collection of cross-platform routines to operate colors conveniently. + * @namespace wTools.color.rgb + * @module Tools/mid/Color +*/ + +const _ = _global_.wTools; +let Self = _.color.rgb = _.color.rgb || Object.create( null ); + +// -- +// implement +// -- + +function fromHexStr( hex ) +{ + let result = _.color.rgba.fromHexStr( hex ); + + if( result === null ) + return null; + + _.assert( result[ 3 ] === undefined || result[ 3 ] === 1 ); + + if( result[ 3 ] ) + result.pop(); + + return result; +} + +// + +function fromRgbStr( rgb ) +{ + /* + -- 'R:10 G:20 B:30' + -- '(R10 / G20 / B30)' + */ + + let isWithColons = /r ?: ?\d+ ?g ?: ?\d+ ?b ?: ?\d+( ?a ?: ?\d+)?/gi.test( rgb ); + let isWithSpaces = /\(r\d+ ?\/ ?g\d+ ?\/ ?b\d+( ?\/ ?a\d+)?\)/gi.test( rgb ); + + if( isWithColons && isWithSpaces ) + return null; + + let colors = rgb.match( /\d+/g ).map( ( el ) => +el ); + + if( !_.color.rgb._validate( colors ) ) + return null; + + if( colors[ 3 ] ) + { + _.assert( colors[ 3 ] === 100, 'Alpha channel must be 100' ); + colors.pop(); + } + + return colors.map( ( el ) => el / 255 ); + +} + +// + +function _validate ( src ) +{ + if + ( + !_.cinterval.has( [ 0, 255 ], src[ 0 ] ) + || !_.cinterval.has( [ 0, 255 ], src[ 1 ] ) + || !_.cinterval.has( [ 0, 255 ], src[ 2 ] ) + ) + return false; + + return true; +} + +// -- +// declare +// -- + +let Extension = +{ + + // to rgb/a + + fromHexStr, + fromRgbStr, + + _validate + +} + +_.props.supplement( _.color.rgb, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3/Rgb.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Rgb_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Rgb_s */ })(); + +/* */ /* begin of file Rgba_s */ ( function Rgba_s() { function Rgba_s_naked() { (function _ColorRgba_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to convert from hex into rgba. + * @module Tools/mid/Color +*/ + +/** + * @summary Collection of cross-platform routines to operate colors conveniently. + * @namespace wTools.color.rgba + * @module Tools/mid/Color +*/ + +const _ = _global_.wTools; +let Self = _.color.rgba = _.color.rgba || Object.create( null ); + +// -- +// implement +// -- + +function fromHexStr( hex ) +{ + let result; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( hex ) ); + + result = /^#?([a-f\d])([a-f\d])([a-f\d])$/i.exec( hex ); + if( result ) + { + result = + [ + parseInt( result[ 1 ], 16 ) / 15, + parseInt( result[ 2 ], 16 ) / 15, + parseInt( result[ 3 ], 16 ) / 15, + ] + return result; + } + + result = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])$/i.exec( hex ); + if( result ) + { + result = + [ + parseInt( result[ 1 ], 16 ) / 15, + parseInt( result[ 2 ], 16 ) / 15, + parseInt( result[ 3 ], 16 ) / 15, + parseInt( result[ 4 ], 16 ) / 15, + ] + return result; + } + + result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec( hex ); + if( result ) + { + result = + [ + parseInt( result[ 1 ], 16 ) / 255, + parseInt( result[ 2 ], 16 ) / 255, + parseInt( result[ 3 ], 16 ) / 255, + ] + return result; + } + + result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec( hex ); + if( result ) + { + result = + [ + parseInt( result[ 1 ], 16 ) / 255, + parseInt( result[ 2 ], 16 ) / 255, + parseInt( result[ 3 ], 16 ) / 255, + parseInt( result[ 4 ], 16 ) / 255, + ] + return result; + } + + return null; +} + +// + +function fromRgbaStr( rgb ) +{ + /* + -- 'R:10 G:20 B:30 A:40' + -- '(R10 / G20 / B30 / A40)' + */ + + let isWithColons = /r ?: ?\d+ ?g ?: ?\d+ ?b ?: ?\d+( ?a ?: ?\d+)?/gi.test( rgb ); + let isWithSpaces = /\(r\d+ ?\/ ?g\d+ ?\/ ?b\d+( ?\/ ?a\d+)?\)/gi.test( rgb ); + + if( isWithColons && isWithSpaces ) + return null; + + let colors = rgb.match( /\d+/g ).map( ( el ) => +el ); + + if( !_.color.rgba._validate( colors ) ) + return null; + + colors[ 0 ] /= 255; + colors[ 1 ] /= 255; + colors[ 2 ] /= 255; + + if( colors[ 3 ] ) + colors[ 3 ] /= 100; + else + colors.push( 1 ); + + return colors; + +} + +// + +function _validate ( src ) +{ + if + ( + !_.cinterval.has( [ 0, 255 ], src[ 0 ] ) + || !_.cinterval.has( [ 0, 255 ], src[ 1 ] ) + || !_.cinterval.has( [ 0, 255 ], src[ 2 ] ) + || src[ 3 ] !== undefined && !_.cinterval.has( [ 0, 100 ], src[ 3 ] ) + ) + return false; + + return true; +} + + +// -- +// declare +// -- + +let Extension = +{ + + // to rgba/a + + fromHexStr, + fromRgbaStr, + _validate + +} + +_.props.supplement( _.color.rgba, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3/Rgba.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Rgba_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Rgba_s */ })(); + +/* */ /* begin of file Xyz_s */ ( function Xyz_s() { function Xyz_s_naked() { (function _ColorXyz_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to convert from xyz into rgb. + * @module Tools/mid/Color +*/ + +/** + * @summary Collection of cross-platform routines to operate colors conveniently. + * @namespace wTools.color.xyz + * @module Tools/mid/Color +*/ + +const _ = _global_.wTools; +let Self = _.color.xyz = _.color.xyz || Object.create( null ); + +// -- +// implement +// -- + +function _strToRgb( dst, src ) +{ + /* + xyz(X, Y, Z) + */ + + _.assert( arguments.length === 2, 'Expects 2 arguments' ); + _.assert( _.strIs( src ) ); + _.assert( dst === null || _.vectorIs( dst ) ); + + let xyzColors = _.color.xyz._formatStringParse( src ); + + _.assert + ( + xyzColors.length === 3 || xyzColors.length === 4, + `{-src-} string must contain exactly 3 or 4 numbers, but got ${xyzColors.length}` + ); + _.assert + ( + xyzColors[ 3 ] === undefined || xyzColors[ 3 ] === 100, + `alpha channel must be 100, but got ${xyzColors[ 3 ]}` + ); + + if( !_.color.xyz._validate( xyzColors ) ) + return null; + + /* normalize ranges */ + xyzColors[ 0 ] = xyzColors[ 0 ] / 100; + xyzColors[ 1 ] = xyzColors[ 1 ] / 100; + xyzColors[ 2 ] = xyzColors[ 2 ] / 100; + if( xyzColors[ 3 ] ) + xyzColors[ 3 ] = xyzColors[ 3 ] / 100; + + return _.color.xyz._longToRgb( dst, xyzColors ); + +} + +// + +function _longToRgb( dst, src ) +{ + _.assert( src.length === 3 || src.length === 4, `{-src-} length must be 3 or 4, but got : ${src.length}` ); + _.assert( src[ 3 ] === undefined || src[ 3 ] === 1, `alpha channel must be 1, but got : ${src[ 3 ]}` ); + + /* + Values greater than 1.0 are allowed and must not be clamped; they represent colors brighter than diffuse white. + https://drafts.csswg.org/css-color/#valdef-color-xyz + */ + // if( !_.color._validateNormalized( src ) ) + // return null; + if( src[ 0 ] < 0 || src[ 1 ] < 0 || src[ 2 ] < 0 ) + return null; + + let r, g, b; + + if( dst === null || _.longIs( dst ) ) + { + dst = dst || new Array( 3 ); + _.assert( dst.length === 3, `{-dst-} container length must be 3, but got : ${dst.length}` ); + + convert( src ); + + /* + TypedArray: + + For non-basic colors with r, g, b values in range ( 0, 1 ) + only instances of those constructors can be used + Float32Array, + Float64Array, + */ + + dst[ 0 ] = r; + dst[ 1 ] = g; + dst[ 2 ] = b; + + } + else if( _.vadIs( dst ) ) + { + /* optional dependency */ + + _.assert( dst.length === 3, `{-dst-} container length must be 3, but got : ${dst.length}` ); + + convert( src ); + + dst.eSet( 0, r ); + dst.eSet( 1, g ); + dst.eSet( 2, b ); + } + else _.assert( 0, '{-dts-} container must be of type Vector' ); + + return dst; + + /* - */ + + function convert( src ) + { + let x = src[ 0 ]; + let y = src[ 1 ]; + let z = src[ 2 ]; + + r = adj( x * 3.2406 + y * -1.5372 + z * -0.4986 ); + g = adj( x * -0.9689 + y * 1.8758 + z * 0.0415 ); + b = adj( x * 0.0557 + y * -0.2040 + z * 1.0570 ); + + function adj( channel ) /* gamma correction */ + { + if( Math.abs( channel ) < 0.0031308 ) + { + return 12.92 * channel; + } + return 1.055 * Math.pow( channel, 0.41666 ) - 0.055; + } + } + + +} + +// + +function _validate ( src ) +{ + if + ( + src[ 0 ] < 0 + || src[ 1 ] < 0 + || src[ 2 ] < 0 + ) + return false; + + return true; +} + +// + +function _formatStringParse( src ) +{ + _.assert( /^xyz\(\d+(\.\d+)?, ?\d+(\.\d+)?, ?\d+(\.\d+)?(, ?\d{1,3}%)?\)$/g.test( src ), 'Wrong source string pattern' ); + return src.match( /\d+(\.\d+)?/g ).map( ( el ) => +el ); +} + +// -- +// declare +// -- + +let Extension = +{ + + // to rgb/a + + _strToRgb, + _longToRgb, + _validate, + + _formatStringParse + +} + +_.props.supplement( _.color.xyz, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3/Xyz.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Xyz_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Xyz_s */ })(); + +/* */ /* begin of file Xyza_s */ ( function Xyza_s() { function Xyza_s_naked() { (function _ColorXyza_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to convert from xyza into rgb. + * @module Tools/mid/Color +*/ + +/** + * @summary Collection of cross-platform routines to operate colors conveniently. + * @namespace wTools.color.xyza + * @module Tools/mid/Color +*/ + +const _ = _global_.wTools; +let Self = _.color.xyza = _.color.xyza || Object.create( null ); + +// -- +// implement +// -- + +function _strToRgba( dst, src ) +{ + /* + xyza(H, S, L, A) + */ + + _.assert( arguments.length === 2, 'Expects 2 arguments' ); + _.assert( _.strIs( src ) ); + _.assert( dst === null || _.vectorIs( dst ) ); + + let xyzaColors = _.color.xyza._formatStringParse( src ); + + _.assert + ( + xyzaColors.length === 3 || xyzaColors.length === 4, + `{-src-} string must contain exactly 3 or 4 numbers, but got ${xyzaColors.length}` + ); + + if( !_.color.xyza._validate( xyzaColors ) ) + return null; + + /* normalize ranges */ + xyzaColors[ 0 ] = xyzaColors[ 0 ] / 100; + xyzaColors[ 1 ] = xyzaColors[ 1 ] / 100; + xyzaColors[ 2 ] = xyzaColors[ 2 ] / 100; + if( xyzaColors[ 3 ] ) + xyzaColors[ 3 ] = xyzaColors[ 3 ] / 100; + + return _.color.xyza._longToRgba( dst, xyzaColors ); + +} + +// + +function _longToRgba( dst, src ) +{ + _.assert( src.length === 3 || src.length === 4, `{-src-} length must be 3 or 4, but got : ${src.length}` ); + + /* + Values greater than 1.0 are allowed and must not be clamped; they represent colors brighter than diffuse white. + https://drafts.csswg.org/css-color/#valdef-color-xyz + */ + // if( !_.color._validateNormalized( src ) ) + // return null; + if + ( + src[ 0 ] < 0 + || src[ 1 ] < 0 + || src[ 2 ] < 0 + || src[ 3 ] !== undefined && !_.cinterval.has( [ 0, 100 ], src[ 3 ] ) + ) + return null; + + let r, g, b; + let a = 1; + + if( dst === null || _.longIs( dst ) ) + { + dst = dst || new Array( 4 ); + _.assert( dst.length === 4, `{-dst-} container length must be 4, but got : ${dst.length}` ); + + convert( src ); + + /* + TypedArray: + + For non-basic colors with r, g, b values in range ( 0, 1 ) + only instances of those constructors can be used + Float32Array, + Float64Array, + */ + + dst[ 0 ] = r; + dst[ 1 ] = g; + dst[ 2 ] = b; + dst[ 3 ] = a; + + } + else if( _.vadIs( dst ) ) + { + /* optional dependency */ + + _.assert( dst.length === 4, `{-dst-} container length must be 4, but got : ${dst.length}` ); + + convert( src ); + + dst.eSet( 0, r ); + dst.eSet( 1, g ); + dst.eSet( 2, b ); + dst.eSet( 3, a ); + } + else _.assert( 0, '{-dts-} container must be of type Vector' ); + + return dst; + + /* - */ + + function convert( src ) + { + let x = src[ 0 ]; + let y = src[ 1 ]; + let z = src[ 2 ]; + if( src[ 3 ] !== undefined ) + a = src[ 3 ]; + + r = adj( x * 3.2406 + y * -1.5372 + z * -0.4986 ); + g = adj( x * -0.9689 + y * 1.8758 + z * 0.0415 ); + b = adj( x * 0.0557 + y * -0.2040 + z * 1.0570 ); + + function adj( channel ) /* gamma correction */ + { + if( Math.abs( channel ) < 0.0031308 ) + { + return 12.92 * channel; + } + return 1.055 * Math.pow( channel, 0.41666 ) - 0.055; + } + } + + +} + +// + +function _validate ( src ) +{ + if + ( + src[ 0 ] < 0 + || src[ 1 ] < 0 + || src[ 2 ] < 0 + || ( src[ 3 ] !== undefined && !_.cinterval.has( [ 0, 100 ], src[ 3 ] ) ) + ) + return false; + + return true; +} + +// + +function _formatStringParse( src ) +{ + _.assert( /^xyza\(\d+(\.\d+)?, ?\d+(\.\d+)?, ?\d+(\.\d+)?(, ?\d{1,3}%)?\)$/g.test( src ), 'Wrong source string pattern' ); + return src.match( /\d+(\.\d+)?/g ).map( ( el ) => +el ); +} + +// -- +// declare +// -- + +let Extension = +{ + + // to rgb/a + + _strToRgba, + _longToRgba, + _validate, + + _formatStringParse + +} + +_.props.supplement( _.color.xyza, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3/Xyza.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor/proto/wtools/amid/l1/color/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Xyza_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Xyza_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor256/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor256/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wColor256 */ ( function wColor256() { function wColor256_naked() { +module.exports = require( '../wtools/amid/l1/color/entry/Color256.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wColor256', 'wcolor256' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor256/proto/node_modules/wColor256' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor256/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wColor256_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wColor256 */ })(); + +/* */ /* begin of file Color256_s */ ( function Color256_s() { function Color256_s_naked() { ( function _Color256_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to operate colors conveniently. Extends basic implementation Color by additional color names. Color provides functions to convert color from one color space to another color space, from name to color and from color to the closest name of a color. The module does not introduce any specific storage format of color what is a benefit. Color has a short list of the most common colors. Use the module for formatted colorful output or other sophisticated operations with colors. + @module Tools/mid/Color256 +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../include/Color256.s' ); + module[ 'exports' ] = _global_.wTools; +} + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor256/proto/wtools/amid/l1/color/entry/Color256.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor256/proto/wtools/amid/l1/color/entry' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Color256_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Color256_s */ })(); + +/* */ /* begin of file Basic_s */ ( function Basic_s() { function Basic_s_naked() { ( function _Basic_s_( ) +{ + +'use strict'; + +/* Color */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../../node_modules/Tools' ); + module[ 'exports' ] = _global_.wTools; +} + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor256/proto/wtools/amid/l1/color/include/Basic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor256/proto/wtools/amid/l1/color/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Basic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Basic_s */ })(); + +/* */ /* begin of file Color256_s */ ( function Color256_s() { function Color256_s_naked() { ( function _Color256_s_( ) +{ + +'use strict'; + +/* color */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( './Basic.s' ); + _.include( 'wColor' ); + require( '../l5/Color256.s' ); + module[ 'exports' ] = _global_.wTools; +} + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor256/proto/wtools/amid/l1/color/include/Color256.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor256/proto/wtools/amid/l1/color/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Color256_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Color256_s */ })(); + +/* */ /* begin of file Color256_s */ ( function Color256_s() { function Color256_s_naked() { (function _Color256_s_() { + +'use strict'; + +const _ = _global_.wTools; +const Self = _.color = _.color || Object.create( null ); + +// -- +// var +// -- + +let ColorMapShell = +{ + 'white' : [ 1.0, 1.0, 1.0 ], + 'black' : [ 0.0, 0.0, 0.0 ], + 'green' : [ 0.0, 1.0, 0.0 ], + 'red' : [ 1.0, 0.0, 0.0 ], + 'yellow' : [ 1.0, 1.0, 0.0 ], + 'blue' : [ 0.0, 0.0, 1.0 ], + 'cyan' : [ 0.0, 1.0, 1.0 ], + 'magenta' : [ 1.0, 0.0, 1.0 ], + + 'bright black' : [ 0.5, 0.5, 0.5 ], + + 'dark yellow' : [ 0.5, 0.5, 0.0 ], + 'dark red' : [ 0.5, 0.0, 0.0 ], + 'dark magenta' : [ 0.5, 0.0, 0.5 ], + 'dark blue' : [ 0.0, 0.0, 0.5 ], + 'dark cyan' : [ 0.0, 0.5, 0.5 ], + 'dark green' : [ 0.0, 0.5, 0.0 ], + 'dark white' : [ 0.75, 0.75, 0.75 ], + + 'bright white' : [ 1.0, 1.0, 1.0 ], /* white */ + 'bright green' : [ 0.0, 1.0, 0.0 ], /* green */ + 'bright red' : [ 1.0, 0.0, 0.0 ], /* red */ + 'bright yellow' : [ 1.0, 1.0, 0.0 ], /* yellow */ + 'bright blue' : [ 0.0, 0.0, 1.0 ], /* blue */ + 'bright cyan' : [ 0.0, 1.0, 1.0 ], /* cyan */ + 'bright magenta' : [ 1.0, 0.0, 1.0 ], /* magenta */ + + 'dark black' : [ 0.0, 0.0, 0.0 ], /* black */ + 'silver' : [ 0.75, 0.75, 0.75 ] /* dark white */ +} + +// + +var ColorMap = +{ + "aquamarine" : [ 0.5,1.0,0.83 ], + "light blue" : [ 0.94,1.0,1.0 ], + "beige" : [ 0.96,0.96,0.86 ], + "bisque" : [ 1.0,0.89,0.77 ], + "chocolate" : [ 0.82,0.41,0.12 ], + "coral" : [ 1.0,0.5,0.3 ], + "cornsilk" : [ 1.0,0.97,0.86 ], + "crimson" : [ 0.86,0.08,0.23 ], + "gainsboro" : [ 0.86,0.86,0.86 ], + "gold" : [ 1.0,0.84,0.0 ], + "honeydew" : [ 0.94,1.0,0.94 ], + "indigo" : [ 0.29,0.0,0.51 ], + "ivory" : [ 1.0,1.0,0.94 ], + "khaki" : [ 0.94,0.90,0.55 ], + "lavender" : [ 0.90,0.90,0.98 ], + "linen" : [ 0.98,0.94,0.90 ], + "moccasin" : [ 1.0,0.89,0.71 ], + "orchid" : [ 0.85,0.44,0.84 ], + "peru" : [ 0.80,0.52,0.25 ], + "plum" : [ 0.87,0.63,0.87 ], + "salmon" : [ 0.98,0.50,0.45 ], + "sienna" : [ 0.63,0.32,0.17 ], + "snow" : [ 1.0,0.98,0.98 ], + "tan" : [ 0.82,0.70,0.55 ], + "thistle" : [ 0.85,0.75,0.85 ], + "tomato" : [ 1.0,0.39,0.28 ], + "turquoise" : [ 0.25,0.88,0.81 ], + "wheat" : [ 0.96,0.87,0.70 ], + /**/ + "moderate pink" : [ 0.93,0.56,0.53 ], + "dark pink" : [ 0.78,0.41,0.39 ], + "pale pink" : [ 1.00,0.80,0.73 ], + "grayish pink" : [ 0.81,0.61,0.56 ], + "pinkish white " : [ 0.98,0.86,0.78 ], + "pinkish gray " : [ 0.78,0.65,0.59 ], + "vivid red" : [ 0.76,0.00,0.13 ], + "strong red" : [ 0.75,0.13,0.20 ], + "deep red" : [ 0.48,0.00,0.11 ], + "very deep red" : [ 0.31,0.00,0.08 ], + "moderate red" : [ 0.67,0.20,0.23 ], + "dark red" : [ 0.41,0.11,0.14 ], + "very dark red" : [ 0.20,0.04,0.09 ], + "light grayish red" : [ 0.69,0.45,0.40 ], + "grayish red" : [ 0.55,0.28,0.26 ], + "dark grayish red" : [ 0.28,0.16,0.16 ], + "blackish red" : [ 0.12,0.05,0.07 ], + "reddish gray" : [ 0.55,0.42,0.38 ], + "dark reddish gray" : [ 0.32,0.24,0.21 ], + "reddish black" : [ 0.12,0.07,0.07 ], + "vivid yellowish pink" : [ 1.00,0.52,0.36 ], + "deep yellowish pink" : [ 0.96,0.29,0.27 ], + "light yellowish pink" : [ 1.00,0.70,0.55 ], + "moderate yellowish pink" : [ 0.93,0.58,0.45 ], + "dark yellowish pink" : [ 0.80,0.42,0.36 ], + "pale yellowish pink" : [ 1.00,0.78,0.66 ], + "grayish yellowish pink" : [ 0.83,0.61,0.52 ], + "brownish pink" : [ 0.80,0.60,0.48 ], + "strong reddish orange" : [ 1.00,0.73,0.38 ], + "deep reddish orange" : [ 0.66,0.11,0.07 ], + "moderate reddish orange" : [ 0.83,0.33,0.22 ], + "dark reddish orange" : [ 0.61,0.18,0.12 ], + "grayish reddish orange" : [ 0.72,0.36,0.26 ], + "deep reddish brown" : [ 0.29,0.00,0.02 ], + "light reddish brown" : [ 0.67,0.40,0.32 ], + "moderate reddish brown" : [ 0.44,0.18,0.15 ], + "dark reddish brown" : [ 0.20,0.06,0.07 ], + "light grayish reddish brown" : [ 0.59,0.42,0.34 ], + "grayish reddish brown" : [ 0.37,0.22,0.19 ], + "dark grayish reddish brown" : [ 0.22,0.12,0.11 ], + "vivid orange" : [ 1.00,0.41,0.00 ], + "brilliant orange" : [ 1.00,0.72,0.25 ], + "strong orange" : [ 1.00,0.44,0.10 ], + "deep orange" : [ 0.76,0.30,0.04 ], + "light orange" : [ 1.00,0.63,0.38 ], + "moderate orange" : [ 0.91,0.47,0.24 ], + "brownish orange" : [ 0.69,0.32,0.14 ], + "strong brown" : [ 0.46,0.20,0.07 ], + "deep brown" : [ 0.30,0.13,0.05 ], + "light brown" : [ 0.66,0.40,0.25 ], + "moderate brown" : [ 0.40,0.22,0.14 ], + "dark brown" : [ 0.21,0.09,0.05 ], + "light grayish brown" : [ 0.58,0.42,0.33 ], + "grayish brown" : [ 0.35,0.24,0.19 ], + "dark grayish brown" : [ 0.20,0.13,0.10 ], + "light brownish gray" : [ 0.55,0.43,0.36 ], + "brownish gray" : [ 0.31,0.24,0.20 ], + "brownish black" : [ 0.08,0.06,0.04 ], + "brilliant orange yellow" : [ 1.00,0.69,0.18 ], + "strong orange yellow" : [ 1.00,0.56,0.05 ], + "deep orange yellow" : [ 0.84,0.43,0.00 ], + "light orange yellow" : [ 1.00,0.73,0.38 ], + "moderate orange yellow" : [ 0.97,0.58,0.24 ], + "dark orange yellow" : [ 0.76,0.46,0.16 ], + "pale orange yellow" : [ 1.00,0.79,0.53 ], + "strong yellowish brown" : [ 0.58,0.31,0.05 ], + "light yellowish brown" : [ 0.73,0.55,0.33 ], + "moderate yellowish brown" : [ 0.49,0.32,0.18 ], + "dark yellowish brown" : [ 0.25,0.15,0.07 ], + "light grayish yellowish brown" : [ 0.71,0.53,0.39 ], + "grayish yellowish brown" : [ 0.47,0.35,0.25 ], + "dark grayish yellowish brown" : [ 0.24,0.17,0.12 ], + "vivid yellow" : [ 1.00,0.70,0.00 ], + "brilliant yellow" : [ 1.00,0.81,0.25 ], + "strong yellow" : [ 0.90,0.62,0.12 ], + "deep yellow" : [ 0.71,0.47,0.00 ], + "light yellow" : [ 1.00,0.83,0.37 ], + "moderate yellow" : [ 0.84,0.62,0.25 ], + "dark yellow" : [ 0.69,0.49,0.17 ], + "pale yellow" : [ 1.00,0.86,0.55 ], + "grayish yellow" : [ 0.81,0.64,0.38 ], + "dark grayish yellow" : [ 0.64,0.49,0.27 ], + "yellowish white" : [ 1.00,0.89,0.72 ], + "yellowish gray" : [ 0.79,0.66,0.52 ], + "light olive brown" : [ 0.58,0.36,0.04 ], + "moderate olive brown" : [ 0.39,0.25,0.06 ], + "dark olive brown" : [ 0.19,0.13,0.07 ], + "vivid greenish yellow" : [ 0.96,0.78,0.00 ], + "brilliant greenish yellow" : [ 1.00,0.86,0.20 ], + "strong greenish yellow" : [ 0.80,0.66,0.09 ], + "deep greenish yellow" : [ 0.62,0.51,0.00 ], + "light greenish yellow" : [ 1.00,0.87,0.35 ], + "moderate greenish yellow" : [ 0.77,0.64,0.24 ], + "dark greenish yellow" : [ 0.61,0.51,0.15 ], + "pale greenish yellow" : [ 1.00,0.87,0.52 ], + "grayish greenish yellow" : [ 0.77,0.65,0.37 ], + "light olive" : [ 0.52,0.42,0.13 ], + "moderate olive" : [ 0.37,0.29,0.06 ], + "dark olive" : [ 0.21,0.17,0.07 ], + "light grayish olive" : [ 0.55,0.45,0.29 ], + "grayish olive" : [ 0.32,0.27,0.17 ], + "dark grayish olive" : [ 0.17,0.15,0.09 ], + "light olive gray" : [ 0.53,0.45,0.35 ], + "olive gray" : [ 0.30,0.26,0.20 ], + "olive black" : [ 0.07,0.10,0.06 ], + "brilliant yellow green" : [ 0.81,0.82,0.23 ], + "strong yellow green" : [ 0.50,0.56,0.09 ], + "deep yellow green" : [ 0.26,0.37,0.09 ], + "light yellow green" : [ 0.86,0.83,0.42 ], + "moderate yellow green" : [ 0.55,0.54,0.25 ], + "pale yellow green" : [ 0.94,0.84,0.60 ], + "grayish yellow green" : [ 0.56,0.52,0.36 ], + "strong olive green" : [ 0.04,0.27,0.00 ], + "deep olive green" : [ 0.08,0.14,0.00 ], + "moderate olive green" : [ 0.26,0.29,0.11 ], + "grayish olive green" : [ 0.28,0.27,0.18 ], + "dark grayish olive green" : [ 0.15,0.15,0.10 ], + "vivid yellowish green" : [ 0.22,0.60,0.19 ], + "brilliant yellowish green" : [ 0.55,0.80,0.37 ], + "strong yellowish green" : [ 0.28,0.52,0.19 ], + "deep yellowish green" : [ 0.00,0.33,0.12 ], + "very deep yellowish green" : [ 0.00,0.16,0.00 ], + "very light yellowish green" : [ 0.78,0.87,0.56 ], + "light yellowish green" : [ 0.00,0.48,0.65 ], + "moderate yellowish green" : [ 0.40,0.50,0.29 ], + "dark yellowish green" : [ 0.19,0.29,0.15 ], + "very dark yellowish green" : [ 0.07,0.15,0.07 ], + "vivid green" : [ 0.00,0.49,0.20 ], + "brilliant green" : [ 0.28,0.65,0.42 ], + "strong green" : [ 0.00,0.42,0.24 ], + "deep green" : [ 0.00,0.27,0.14 ], + "very light green" : [ 0.60,0.78,0.58 ], + "light green" : [ 0.44,0.61,0.43 ], + "moderate green" : [ 0.22,0.40,0.27 ], + "dark green" : [ 0.13,0.23,0.15 ], + "very dark green" : [ 0.09,0.15,0.11 ], + "very pale green" : [ 0.85,0.87,0.73 ], + "pale green" : [ 0.55,0.57,0.48 ], + "grayish green" : [ 0.34,0.37,0.31 ], + "dark grayish green" : [ 0.19,0.22,0.19 ], + "blackish green" : [ 0.08,0.09,0.07 ], + "greenish white" : [ 0.96,0.90,0.80 ], + "light greenish gray" : [ 0.73,0.69,0.59 ], + "greenish gray" : [ 0.48,0.46,0.40 ], + "dark greenish gray" : [ 0.27,0.26,0.23 ], + "greenish black" : [ 0.09,0.08,0.07 ], + "vivid bluish green" : [ 0.00,0.51,0.43 ], + "brilliant bluish green" : [ 0.00,0.61,0.46 ], + "strong bluish green" : [ 0.00,0.43,0.36 ], + "deep bluish green" : [ 0.00,0.22,0.17 ], + "very light bluish green" : [ 0.63,0.84,0.71 ], + "light bluish green" : [ 0.40,0.62,0.52 ], + "moderate bluish green" : [ 0.18,0.40,0.34 ], + "dark bluish green" : [ 0.00,0.23,0.20 ], + "very dark bluish green" : [ 0.00,0.11,0.09 ], + "vivid greenish blue" : [ 0.00,0.48,0.65 ], + "brilliant greenish blue" : [ 0.16,0.55,0.61 ], + "strong greenish blue" : [ 0.00,0.40,0.49 ], + "deep greenish blue" : [ 0.00,0.48,0.65 ], + "very light greenish blue" : [ 0.64,0.78,0.75 ], + "light greenish blue" : [ 0.39,0.60,0.62 ], + "moderate greenish blue" : [ 0.19,0.38,0.42 ], + "dark greenish blue" : [ 0.00,0.22,0.25 ], + "very dark greenish blue" : [ 0.01,0.13,0.15 ], + "vivid blue,ultramarine" : [ 0.00,0.49,0.68 ], + "brilliant blue,celestial blue" : [ 0.26,0.52,0.71 ], + "strong blue,bright blue" : [ 0.00,0.33,0.54 ], + "deep blue,royal blue" : [ 0.00,0.18,0.33 ], + "very light blue" : [ 0.65,0.74,0.84 ], + "sky blue" : [ 0.42,0.57,0.69 ], + "moderate blue,cerulean blue" : [ 0.22,0.34,0.47 ], + "dark blue,navy blue" : [ 0.00,0.13,0.22 ], + "very pale blue,cloud blue" : [ 0.76,0.79,0.79 ], + "pale blue,alice blue" : [ 0.57,0.57,0.57 ], + "grayish blue,slate blue" : [ 0.29,0.33,0.36 ], + "dark grayish blue" : [ 0.17,0.20,0.22 ], + "blackish blue" : [ 0.09,0.10,0.12 ], + "bluish white" : [ 0.98,0.87,0.81 ], + "light bluish gray" : [ 0.75,0.68,0.63 ], + "bluish gray" : [ 0.49,0.45,0.43 ], + "dark bluish gray" : [ 0.27,0.27,0.27 ], + "bluish black" : [ 0.08,0.09,0.10 ], + "vivid purplish blue" : [ 0.13,0.08,0.37 ], + "brilliant purplish blue" : [ 0.38,0.39,0.61 ], + "strong purplish blue" : [ 0.28,0.26,0.54 ], + "deep purplish blue" : [ 0.10,0.08,0.25 ], + "very light purplish blue" : [ 0.73,0.67,0.78 ], + "light purplish blue" : [ 0.51,0.49,0.64 ], + "moderate purplish blue" : [ 0.26,0.24,0.39 ], + "dark purplish blue" : [ 0.10,0.09,0.16 ], + "very pale purplish blue" : [ 0.80,0.73,0.77 ], + "pale purplish blue" : [ 0.54,0.50,0.56 ], + "grayish purplish blue" : [ 0.25,0.24,0.32 ], + "vivid violet" : [ 0.53,0.29,0.68 ], + "brilliant violet" : [ 0.46,0.36,0.60 ], + "strong violet" : [ 0.33,0.22,0.48 ], + "deep violet" : [ 0.14,0.04,0.21 ], + "very light violet" : [ 0.93,0.75,0.95 ], + "light violet" : [ 0.53,0.42,0.60 ], + "moderate violet" : [ 0.33,0.22,0.39 ], + "dark violet" : [ 0.13,0.07,0.17 ], + "very pale violet" : [ 0.85,0.69,0.75 ], + "pale violet" : [ 0.58,0.48,0.55 ], + "grayish violet" : [ 0.27,0.22,0.29 ], + "vivid purple" : [ 0.58,0.20,0.57 ], + "brilliant purple" : [ 0.87,0.50,0.80 ], + "strong purple" : [ 0.50,0.24,0.46 ], + "deep purple" : [ 0.33,0.10,0.31 ], + "very deep purple" : [ 0.20,0.04,0.21 ], + "very light purple" : [ 0.89,0.66,0.75 ], + "light purple" : [ 0.73,0.50,0.64 ], + "moderate purple" : [ 0.50,0.28,0.44 ], + "dark purple" : [ 0.28,0.16,0.25 ], + "very dark purple" : [ 0.14,0.05,0.13 ], + "very pale purple" : [ 0.90,0.73,0.76 ], + "pale purple" : [ 0.68,0.52,0.55 ], + "grayish purple" : [ 0.45,0.32,0.36 ], + "dark grayish purple" : [ 0.27,0.18,0.21 ], + "blackish purple" : [ 0.11,0.06,0.09 ], + "purplish white" : [ 0.98,0.86,0.78 ], + "light purplish gray" : [ 0.78,0.66,0.62 ], + "purplish gray" : [ 0.53,0.44,0.42 ], + "dark purplish gray" : [ 0.34,0.25,0.26 ], + "purplish black" : [ 0.11,0.07,0.09 ], + "vivid reddish purple" : [ 0.49,0.00,0.35 ], + "strong reddish purple" : [ 0.60,0.21,0.42 ], + "deep reddish purple" : [ 0.39,0.07,0.29 ], + "very deep reddish purple" : [ 0.28,0.03,0.21 ], + "light reddish purple" : [ 0.73,0.42,0.54 ], + "moderate reddish purple" : [ 0.55,0.27,0.40 ], + "dark reddish purple" : [ 0.31,0.15,0.23 ], + "very dark reddish purple" : [ 0.15,0.04,0.12 ], + "pale reddish purple" : [ 0.67,0.46,0.50 ], + "grayish reddish purple" : [ 0.49,0.30,0.36 ], + "brilliant purplish pink" : [ 1.00,0.59,0.73 ], + "deep purplish pink" : [ 0.92,0.32,0.52 ], + "light purplish pink" : [ 1.00,0.66,0.69 ], + "moderate purplish pink" : [ 0.89,0.50,0.56 ], + "dark purplish pink" : [ 0.78,0.40,0.45 ], + "pale purplish pink" : [ 0.99,0.74,0.73 ], + "grayish purplish pink" : [ 0.80,0.57,0.58 ], + "vivid purplish red" : [ 0.84,0.15,0.36 ], + "deep purplish red" : [ 0.44,0.00,0.21 ], + "very deep purplish red" : [ 0.28,0.00,0.15 ], + "moderate purplish red" : [ 0.65,0.22,0.33 ], + "dark purplish red" : [ 0.36,0.12,0.19 ], + "very dark purplish red" : [ 0.16,0.03,0.10 ], + "light grayish purplish red" : [ 0.70,0.44,0.44 ], + "grayish purplish red" : [ 0.55,0.28,0.32 ], + "light gray" : [ 0.76,0.66,0.58 ], + "medium gray" : [ 0.51,0.44,0.40 ], + "dark gray" : [ 0.29,0.26,0.24 ], +} + +// -- +// declare +// -- + +var Extension = +{ + + ColorMapShell, + ColorMap, + +} + +// + +_.props.supplement( _.color, Extension ); +_.props.supplement( _.color.ColorMap, ColorMap ); +_.props.supplement( _.color.ColorMap, ColorMapShell ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor256/proto/wtools/amid/l1/color/l5/Color256.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wColor256/proto/wtools/amid/l1/color/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Color256_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Color256_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wConsequence/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wConsequence/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wConsequence */ ( function wConsequence() { function wConsequence_naked() { +module.exports = require( '../wtools/abase/l9/consequence/Namespace.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wConsequence', 'wconsequence' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wConsequence/proto/node_modules/wConsequence' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wConsequence/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wConsequence_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wConsequence */ })(); + +/* */ /* begin of file Consequence_s */ ( function Consequence_s() { function Consequence_s_naked() { ( function _Consequence_s_() +{ + +'use strict'; + +/* + += Concepts + +Consequence :: +Resource :: +Error of resource :: +Argument of resource :: +Competitor :: +Procedure :: + +*/ + +/* + += Principles + +1. Methods of Consequence should call callback instantly and synchronously if all necessary data provided, otherwise, Consequence should call callback asynchronously. +2. Handlers of keeping methods cannot return undefined. It is often a sign of a bug. +3. A resource of Consequence cannot have both an error and an argument but must have either one. + +*/ + +/* + += Groups + +1. then / except / finally +2. give / keep + +*/ + +const _global = _global_; +const _ = _global_.wTools; +let Deasync = null; + +_.assert( !_.Consequence, 'Consequence included several times' ); + +// relations + +let KindOfResource = +{ + ErrorOnly : 1, + ArgumentOnly : 2, + Both : 3, + BothWithCompetitor : 4, +} + +// + +/** + + */ + +/** + * Function that accepts result of wConsequence value computation. Used as parameter in methods such as finallyGive(), finally(), etc. + * @param {*} err Error object, or any other type, that represent or describe an error reason. If during resolving + * value no exception occurred, it will be set to null; + * @param {*} value resolved by wConsequence value; + * @callback Competitor + * @class wConsequence + * @namespace Tools + * @module Tools/base/Consequence + */ + +/** + * @classdesc Class wConsequence creates objects that used for asynchronous computations. It represent the queue of results that + * can computation asynchronously, and has a wide range of tools to implement this process. + * @class wConsequence + * @module Tools/base/Consequence + */ + +/** + * Creates instance of wConsequence + * @param {Object|Function|wConsequence} [o] initialization options + * @example + * let con = new _.Consequence(); + * con.take( 'hello' ).finallyGive( function( err, value) { console.log( value ); } ); // hello + * + * let con = _.Consequence(); + * con.finallyGive( function( err, value) { console.log( value ); } ).take('world'); // world + * @constructor wConsequence + * @class wConsequence + * @module Tools/base/Consequence + * @returns {wConsequence} + */ + +/* heavy optimization */ + +class wConsequence extends _.CallableObject +{ + constructor() + { + let self = super(); + Self.prototype.init.apply( self, arguments ); + // return self; /* Dmytro : eslint rule mark it as error. The removing of the line does not affect the behavior of module */ + } +} + +let wConsequenceProxy = new Proxy +( + wConsequence, + { + apply : function apply( original, context, args ) + { + let o = args[ 0 ]; + + if( o ) + if( o instanceof Self ) + { + o = _.mapOnly_( null, o, Self.FieldsOfCopyableGroups ); + } + + if( Config.debug ) + { + if( o === undefined ) + { + o = Object.create( null ); + args[ 0 ] = o; + } + } + + return new original( ... args ); + }, + + set : function set( original, name, value ) + { + return Reflect.set( ... arguments ); + }, + } +); + +const Parent = null; +const Self = wConsequenceProxy; + +wConsequence.shortName = 'Consequence'; + +// -- +// inter +// -- + +/** + * Initialises instance of wConsequence + * @param {Object|wConsequence} [o] initialization options + * @private + * @method init + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function init( o ) +{ + let self = this; + + if( o ) + { + if( !Config.debug ) + { + delete o.tag; + delete o.capacity; + } + if( o instanceof Self ) + { + o = _.mapOnly_( null, o, self.FieldsOfCopyableGroups ); + } + else + { + _.map.assertHasOnly( o, self.FieldsOfCopyableGroups ); + } + if( o._resources ) + o._resources = o._resources.slice(); + _.props.extend( self, o ); + } + + if( RestrictsDebug.id === 0 ) + { + self.Counter += 1; + self.id = self.Counter; + } + + _.assert( arguments.length === 0 || arguments.length === 1 ); +} + +// + +function is( src ) +{ + _.assert( arguments.length === 1 ); + return _.consequenceIs( src ); +} + +// -- +// basic +// -- + +/** + * Method appends resolved value and error competitor to wConsequence competitors sequence. That competitor accept only one + value or error reason only once, and don't pass result of it computation to next competitor (unlike Promise 'finally'). + if finallyGive() called without argument, an empty competitor will be appended. + After invocation, competitor will be removed from competitors queue. + Returns current wConsequence instance. + * @example + function gotHandler1( error, value ) + { + console.log( 'competitor 1: ' + value ); + }; + + function gotHandler2( error, value ) + { + console.log( 'competitor 2: ' + value ); + }; + + let con1 = new _.Consequence(); + + con1.finallyGive( gotHandler1 ); + con1.take( 'hello' ).take( 'world' ); + + // prints only " competitor 1: hello ", + + let con2 = new _.Consequence(); + + con2.finallyGive( gotHandler1 ).finallyGive( gotHandler2 ); + con2.take( 'foo' ); + + // prints only " competitor 1: foo " + + let con3 = new _.Consequence(); + + con3.finallyGive( gotHandler1 ).finallyGive( gotHandler2 ); + con3.take( 'bar' ).take( 'baz' ); + + // prints + // competitor 1: bar + // competitor 2: baz + // + * @param {Competitor|wConsequence} [competitor] callback, that accepts resolved value or exception reason. + * @returns {wConsequence} + * @see {@link Competitor} competitor callback + * @throws {Error} if passed more than one argument. + * @method finallyGive + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function finallyGive( competitorRoutine ) +{ + let self = this; + let times = 1; + + _.assert + ( + arguments.length === 1, + () => `Expects none or single argument, but got ${arguments.length} arguments` + ); + + if( _.numberIs( competitorRoutine ) ) + { + times = competitorRoutine; + competitorRoutine = function(){}; + } + + self._competitorAppend + ({ + competitorRoutine, + keeping : false, + kindOfResource : Self.KindOfResource.Both, + times, + stack : 2, + }); + + self.__handleResourceSoon( false ); + + return self; +} + +finallyGive.having = +{ + consequizing : 1, +} + +// + +function finallyKeep( competitorRoutine ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + self._competitorAppend + ({ + competitorRoutine, + keeping : true, + kindOfResource : Self.KindOfResource.Both, + stack : 2, + times : 1, + }); + + self.__handleResourceSoon( false ); + return self; +} + +finallyKeep.having = +{ + consequizing : 1, +} + +// + +function thenGive( competitorRoutine ) +{ + let self = this; + let times = 1; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.numberIs( competitorRoutine ) ) /* qqq : cover */ + { + times = competitorRoutine; + competitorRoutine = function(){}; + } + + self._competitorAppend + ({ + competitorRoutine, + times, + keeping : false, + kindOfResource : Self.KindOfResource.ArgumentOnly, + stack : 2, + }); + + self.__handleResourceSoon( false ); + return self; +} + +thenGive.having = +{ + consequizing : 1, +} + +// + +/** + * Method pushed `competitor` callback into wConsequence competitors queue. That callback will + trigger only in that case if accepted error parameter will be null. Else accepted error will be passed to the next + competitor in queue. After handling accepted value, competitor pass result to the next competitor, like finally + method. + * @returns {wConsequence} + * @throws {Error} if passed more than one arguments + * @see {@link module:Tools/base/Consequence.wConsequence#finallyGive} finally method + * @method thenKeep + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function thenKeep( competitorRoutine ) +{ + let self = this; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( arguments.length === 2 ) + return self._promiseThen( arguments[ 0 ], arguments[ 1 ] ); + + self._competitorAppend + ({ + competitorRoutine, + keeping : true, + kindOfResource : Self.KindOfResource.ArgumentOnly, + stack : 2, + }); + + self.__handleResourceSoon( false ); + return self; +} + +thenKeep.having = +{ + consequizing : 1, +} + +// + +function catchGive( competitorRoutine ) +{ + let self = this; + let times = 1; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.numberIs( competitorRoutine ) ) + { + times = competitorRoutine; + competitorRoutine = function(){}; + } + + self._competitorAppend + ({ + competitorRoutine, + times, + keeping : false, + kindOfResource : Self.KindOfResource.ErrorOnly, + stack : 2, + }); + + self.__handleResourceSoon( false ); + return self; +} + +catchGive.having = +{ + consequizing : 1, +} + +// + +/** + * catchKeep method pushed `competitor` callback into wConsequence competitors queue. That callback will + trigger only in that case if accepted error parameter will be defined and not null. Else accepted parameters will + be passed to the next competitor in queue. + + * @param {Competitor|wConsequence} competitor callback, that accepts exception reason and value . + * @returns {wConsequence} + * @throws {Error} if passed more than one arguments + * @see {@link module:Tools/base/Consequence.wConsequence#finallyGive} finally method + * @method catchKeep + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function catchKeep( competitorRoutine ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + self._competitorAppend + ({ + competitorRoutine, + keeping : true, + kindOfResource : Self.KindOfResource.ErrorOnly, + stack : 2, + }); + + self.__handleResourceSoon( false ); + + return self; +} + +catchKeep.having = +{ + consequizing : 1, +} + +// -- +// promise +// -- + +function _promiseThen( resolve, reject ) +{ + let self = this; + + _.assert( arguments.length === 2 ); + _.assert( _.routineIs( resolve ) && _.routineIs( reject ) ); + _.assert( resolve.length === 1 && reject.length === 1 ); + + return self.finallyGive( ( err, got ) => + { + if( err ) + reject( err ); + else + resolve( got ); + }) + +} + +// + +function _promise( o ) +{ + let self = this; + let keeping = o.keeping; + let kindOfResource = o.kindOfResource; + let procedure = self.procedure( 3 ).nameElse( 'promise' ); + self.procedureDetach(); + + _.routine.assertOptions( _promise, arguments ); + + let result = new Promise( function( resolve, reject ) + { + self.procedure( procedure ); + + self._competitorAppend + ({ + keeping : 0, + competitorRoutine, + kindOfResource : self.KindOfResource.Both, + stack : 3, + }); + + self.__handleResourceSoon( false ); + + function competitorRoutine( err, arg ) + { + if( err ) + { + if( kindOfResource === self.KindOfResource.Both || kindOfResource === self.KindOfResource.ErrorOnly ) + reject( err ); + } + else + { + if( kindOfResource === self.KindOfResource.Both || kindOfResource === self.KindOfResource.ErrorOnly ) + resolve( arg ); + } + if( keeping ) + self.take( err, arg ); + }; + + }); + + return result; +} + +_promise.defaults = +{ + keeping : null, + kindOfResource : null, +} + +_promise.having = +{ + consequizing : 1, +} + +// + +function finallyPromiseGive() +{ + let self = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + return self._promise + ({ + keeping : 0, + kindOfResource : self.KindOfResource.Both, + }); +} + +finallyPromiseGive.having = Object.create( _promise.having ); + +// + +/** + * Method accepts competitor for resolved value/error. This competitor method finally adds to wConsequence competitors sequence. + After processing accepted value, competitor return value will be pass to the next competitor in competitors queue. + Returns current wConsequence instance. + + * @example + function gotHandler1( error, value ) + { + console.log( 'competitor 1: ' + value ); + value++; + return value; + }; + + function gotHandler3( error, value ) + { + console.log( 'competitor 3: ' + value ); + }; + + let con1 = new _.Consequence(); + + con1.finally( gotHandler1 ).finally( gotHandler1 ).finallyGive(gotHandler3); + con1.take( 4 ).take( 10 ); + + // prints: + // competitor 1: 4 + // competitor 1: 5 + // competitor 3: 6 + + * @param {Competitor|wConsequence} competitor callback, that accepts resolved value or exception reason. + * @returns {wConsequence} + * @throws {Error} if missed competitor. + * @throws {Error} if passed more than one argument. + * @see {@link Competitor} competitor callback + * @see {@link module:Tools/base/Consequence.wConsequence#finallyGive} finallyGive method + * @method finally + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function finallyPromiseKeep() +{ + let self = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + return self._promise + ({ + keeping : 1, + kindOfResource : self.KindOfResource.Both, + }); +} + +finallyPromiseKeep.having = Object.create( _promise.having ); + +// + +function thenPromiseGive() +{ + let self = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + return self._promise + ({ + keeping : 0, + kindOfResource : self.KindOfResource.ArgumentOnly, + }); +} + +thenPromiseGive.having = Object.create( _promise.having ); + +// + +function thenPromiseKeep() +{ + let self = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + return self._promise + ({ + keeping : 1, + kindOfResource : self.KindOfResource.ArgumentOnly, + }); +} + +thenPromiseKeep.having = Object.create( _promise.having ); + +// + +function catchPromiseGive() +{ + let self = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + return self._promise + ({ + keeping : 0, + kindOfResource : self.KindOfResource.ErrorOnly, + }); +} + +catchPromiseGive.having = Object.create( _promise.having ); + +// + +function catchPromiseKeep() +{ + let self = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + return self._promise + ({ + keeping : 1, + kindOfResource : self.KindOfResource.ErrorOnly, + }); +} + +catchPromiseKeep.having = Object.create( _promise.having ); + +// -- +// deasync +// -- + +function _deasync( o ) +{ + let self = this; + let procedure = self.procedure( 3 ).nameElse( 'deasync' ); + let keeping = o.keeping; + let result = Object.create( null ); + let ready = false; + + _.routine.assertOptions( _deasync, arguments ); + _.assert + ( + o.kindOfResource === 0 + || o.kindOfResource === self.KindOfResource.Both + || o.kindOfResource === self.KindOfResource.ArgumentOnly + || o.kindOfResource === self.KindOfResource.ErrorOnly + ); + + self._competitorAppend + ({ + competitorRoutine, + kindOfResource : self.KindOfResource.Both, + keeping : 0, + stack : 3, + }); + + self.__handleResourceSoon( false ); + + if( Deasync === null ) + Deasync = require( 'wdeasync' ); /* yyy */ + Deasync.loopWhile( () => !ready ) + + if( result.error ) + if( o.kindOfResource === self.KindOfResource.Both || o.kindOfResource === self.KindOfResource.ErrorOnly ) + throw result.error; + else + return new _.Consequence().error( result.error ); + + if( o.kindOfResource === self.KindOfResource.Both || o.kindOfResource === self.KindOfResource.ArgumentOnly ) + return result.argument; + else + return new _.Consequence().take( result.argument ); + + return self; + + function competitorRoutine( error, argument ) + { + result.error = error; + result.argument = argument; + ready = true; + if( keeping ) + self.take( error, argument ); + }; + +} + +_deasync.defaults = +{ + keeping : null, + kindOfResource : null, +} + +_deasync.having = +{ + consequizing : 1, +} + +// + +function deasync() +{ + let self = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + return self._deasync + ({ + keeping : 1, + kindOfResource : 0, + }); +} + +deasync.having = Object.create( _deasync.having ); + +// -- +// advanced +// -- + +function _first( src, stack ) +{ + let self = this; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.consequenceIs( src ) ) + { + src.finally( self ); + } + else if( _.routineIs( src ) ) + { + let result; + + try + { + result = src(); + if( result === undefined ) + throw self.ErrNoReturn( src ); + } + catch( err ) + { + result = new _.Consequence().error( self.__handleError( err ) ); + } + + if( _.consequenceIs( result ) ) + { + result.finally( self ); + } + else if( _.promiseLike( result ) ) + { + result.finally( Self.From( result ) ); + } + else + { + self.take( result ); + } + + } + else _.assert( 0, 'Method first expects consequence of routine, but got', _.entity.strType( src ) ); + + return self; +} + +// + +/** + * If type of `src` is function, the first method run it on begin, if the result of `src` invocation is instance of + wConsequence, the current wConsequence will be wait for it resolving, else method added result to resources sequence + of the current instance. + * If `src` is instance of wConsequence, the current wConsequence delegates to it his first corespondent. + * Returns current wConsequence instance. + * @example + * function handleGot1(err, val) + { + if( err ) + { + console.log( 'handleGot1 error: ' + err ); + } + else + { + console.log( 'handleGot1 value: ' + val ); + } + }; + + let con = new _.Consequence(); + + con.first( function() + { + return 'foo'; + }); + + con.take( 100 ); + con.finallyGive( handleGot1 ); + // prints: handleGot1 value: foo +* + function handleGot1(err, val) + { + if( err ) + { + console.log( 'handleGot1 error: ' + err ); + } + else + { + console.log( 'handleGot1 value: ' + val ); + } + }; + + let con = new _.Consequence(); + + con.first( function() + { + return _.Consequence().take(3); + }); + + con.take(100); + con.finallyGive( handleGot1 ); + * @param {wConsequence|Function} src wConsequence or routine. + * @returns {wConsequence} + * @throws {Error} if `src` has unexpected type. + * @method first + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function first( src ) +{ + let self = this; + return self._first( src, null ); +} + +first.having = +{ + consequizing : 1, +} + +// + +/** + * Returns new _.Consequence instance. If on cloning moment current wConsequence has uncaught resolved values in queue + the first of them would be handled by new _.Consequence. Else pass accepted + * @example + function gotHandler1( error, value ) + { + console.log( 'competitor 1: ' + value ); + value++; + return value; + }; + + function gotHandler2( error, value ) + { + console.log( 'competitor 2: ' + value ); + }; + + let con1 = new _.Consequence(); + con1.take(1).take(2).take(3); + let con2 = con1.split(); + con2.finallyGive( gotHandler2 ); + con2.finallyGive( gotHandler2 ); + con1.finallyGive( gotHandler1 ); + con1.finallyGive( gotHandler1 ); + + // prints: + // competitor 2: 1 // only first value copied into cloned wConsequence + // competitor 1: 1 + // competitor 1: 2 + + * @returns {wConsequence} + * @throws {Error} if passed any argument. + * @method splitKeep + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function splitKeep( first ) +{ + let self = this; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + let result = new Self(); + + if( first ) // xxx : remove, maybe argument? + { + result.finally( first ); + self.give( function( err, arg ) + { + result.take( err, arg ); + this.take( err, arg ); + }); + } + else + { + self.finally( result ); + } + + return result; +} + +splitKeep.having = +{ + consequizing : 1, +} + +// + +function splitGive( first ) +{ + let self = this; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + let result = new Self(); + + if( first ) // xxx : remove, maybe argument? + { + result.finally( first ); + self.give( function( err, arg ) + { + result.take( err, arg ); + }); + } + else + { + self.finallyGive( result ); + } + + return result; +} + +splitGive.having = +{ + consequizing : 1, +} + +// + +/** + * Works like finallyGive() method, but value that accepts competitor, passes to the next taker in takers queue without + modification. + * @example + * + function gotHandler1( error, value ) + { + console.log( 'competitor 1: ' + value ); + value++; + return value; + } + + function gotHandler2( error, value ) + { + console.log( 'competitor 2: ' + value ); + } + + function gotHandler3( error, value ) + { + console.log( 'competitor 3: ' + value ); + } + + let con1 = new _.Consequence(); + con1.take(1).take(4); + + // prints: + // competitor 1: 1 + // competitor 2: 1 + // competitor 3: 4 + + * @param {Competitor|wConsequence} competitor callback, that accepts resolved value or exception + reason. + * @returns {wConsequence} + * @throws {Error} if passed more than one arguments + * @see {@link module:Tools/base/Consequence.wConsequence#finallyGive} finallyGive method + * @method tap + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function tap( competitorRoutine ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + self._competitorAppend + ({ + competitorRoutine, + keeping : false, + tapping : true, + kindOfResource : Self.KindOfResource.Both, + stack : 2, + }); + + self.__handleResourceSoon( false ); + return self; +} + +tap.having = +{ + consequizing : 1, +} + +// + +/** + * Creates and adds to corespondents sequence error competitor. If handled resource contains error, corespondent logs it. + * @returns {wConsequence} + * @throws {Error} If called with any argument. + * @method catchLog + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function catchLog() +{ + let self = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + self._competitorAppend + ({ + competitorRoutine : errorLog, + keeping : true, + kindOfResource : Self.KindOfResource.ErrorOnly, + stack : 2, + }); + + self.__handleResourceSoon( false ); + return self; + + /* - */ + + function errorLog( err ) + { + err = _.err( err ); + logger.error( _.errOnce( err ) ); + return null; + } + +} + +catchLog.having = +{ + consequizing : 1, +} + +// + +/** + * Creates and adds to corespondents sequence error competitor. If handled resource contains error, corespondent logs it. + * @returns {wConsequence} + * @throws {Error} If called with any argument. + * @method catchBrief + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function catchBrief() +{ + let self = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + self._competitorAppend + ({ + competitorRoutine : errorLog, + keeping : true, + kindOfResource : Self.KindOfResource.ErrorOnly, + stack : 2, + }); + + self.__handleResourceSoon( false ); + return self; + + /* - */ + + function errorLog( err ) + { + err = _.errBrief( err ); + logger.error( _.errOnce( err ) ); + return null; + } + +} + +catchBrief.having = +{ + consequizing : 1, +} + +// + +function syncMaybe() +{ + let self = this; + + if( self._resources.length === 1 ) + { + let resource = self._resources[ 0 ]; + if( resource.error === undefined ) + { + // _.assert( resource.error === undefined ); /* Dmytro : has no sense for this condition */ + _.assert( resource.argument !== undefined ); + return resource.argument; + } + else + { + // _.assert( resource.argument === undefined ); /* Dmytro : has no sense for this condition */ + _.assert( resource.error !== undefined ); + throw _.err( resource.error ); + } + // if( resource.error !== undefined ) + // { + // _.assert( resource.argument === undefined ); + // throw _.err( resource.error ); + // } + // else + // { + // _.assert( resource.error === undefined ); + // return resource.argument; + // } + } + + return self; +} + +// + +function sync() +{ + let self = this; + + _.assert( self._resources.length <= 1, () => 'Cant return resource of consequence because it has ' + self._resources.length + ' of such!' ); + _.assert( self._resources.length >= 1, () => 'Cant return resource of consequence because it has none of such!' ); + + return self.syncMaybe(); +} + +// -- +// experimental +// -- + +function _competitorFinally( competitorRoutine ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + self._competitorAppend + ({ + competitorRoutine, + keeping : true, + kindOfResource : Self.KindOfResource.BothWithCompetitor, + stack : 2, + }); + + self.__handleResourceSoon( false ); + return self; +} + +// + +function wait() +{ + let self = this; + let result = new _.Consequence(); + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + self.finallyGive( function __wait( err, arg ) + { + if( err ) + self.error( err ); + else + self.take( result ); + }); + + self.take( null ); + + return result; +} + +// + +function participateGive( con ) +{ + let self = this; + + _.assert( _.consequenceIs( con ) ); + _.assert( arguments.length === 1 ); + + con.finallyGive( 1 ); + self.finallyGive( con ); + // con.take( self ); + + return con; +} + +// + +function participateKeep( con ) +{ + let self = this; + + _.assert( _.consequenceIs( con ) ); + _.assert( arguments.length === 1 ); + + con.finallyGive( 1 ); + self.finallyKeep( con ); + + return con; +} + +// + +function ErrNoReturn( routine ) +{ + let err = _.err( `Callback of then of consequence should return something, but callback::${routine.name} returned undefined` ) + err = _.err( routine.toString(), '\n', err ); + return err; +} + +// -- +// put +// -- + +function _put( o ) +{ + let self = this; + let key = o.key; + let container = o.container; + let keeping = o.keeping; + + _.assert( !_.primitiveIs( o.container ), 'Expects one or two argument, container for resource or key and container' ); + _.assert( o.key === null || _.numberIs( o.key ) || _.strIs( o.key ), () => 'Key should be number or string, but it is ' + _.entity.strType( o.key ) ); + + if( o.key !== null ) + { + self._competitorAppend + ({ + keeping, + kindOfResource : o.kindOfResource, + competitorRoutine : o.kindOfResource === Self.KindOfResource.ArgumentOnly ? __onPutWithKeyArgumentOnly : __onPutWithKey, + stack : 4, /* delta : 4 to not include info about `routine.unite` in the stack */ + }); + self.__handleResourceSoon( false ); + return self; + } + else if( _.argumentsArray.like( o.container ) ) + { + self._competitorAppend + ({ + keeping, + kindOfResource : o.kindOfResource, + competitorRoutine : o.kindOfResource === Self.KindOfResource.ArgumentOnly ? __onPutToArrayArgumentOnly : __onPutToArray, + stack : 4, /* delta : 4 to not include info about `routine.unite` in the stack */ + }); + self.__handleResourceSoon( false ); + return self; + } + else + { + _.assert( 0, 'Expects key for to put to objects or fixed-size long' ); + } + + /* */ + + function __onPutWithKey( err, arg ) + { + if( err === undefined ) + container[ key ] = arg; + else + container[ key ] = err; + + // if( err !== undefined ) + // container[ key ] = err; + // else + // container[ key ] = arg; + + if( !keeping ) + return; + if( err ) + throw err; + return arg; + } + + /* */ + + function __onPutWithKeyArgumentOnly( arg ) /* ArgumentOnly competitor should expect single argument */ + { + container[ key ] = arg; + + if( !keeping ) + return; + + return arg; + } + + /* */ + + function __onPutToArray( err, arg ) + { + _.assert( 0, 'not tested' ); + + if( err === undefined ) + container.push( arg ); + else + container.push( err ); + + // if( err !== undefined ) + // container.push( err ); + // else + // container.push( arg ); + + if( !keeping ) + return; + if( err ) + throw err; + return arg; + } + + /* */ + + function __onPutToArrayArgumentOnly( arg ) /* ArgumentOnly competitor should expect single argument */ + { + _.assert( 0, 'not tested' ); + + container.push( arg ); + + if( !keeping ) + return; + return arg; + } + +} + +_put.defaults = +{ + key : null, + container : null, + kindOfResource : null, + keeping : null, +} + +// + +function put_head( routine, args ) +{ + let self = this; + let o = Object.create( null ); + + if( args[ 1 ] === undefined ) + { + o = { container : args[ 0 ] } + } + else + { + o = { container : args[ 0 ], key : args[ 1 ] } + } + + _.assert( args.length === 1 || args.length === 2, 'Expects one or two argument, container for resource or key and container' ); + _.routine.options_( routine, o ); + + return o; +} + +// + +let putGive = _.routine.uniteCloning_replaceByUnite({ head : put_head, body : _put, name : 'putGive' }); +var defaults = putGive.defaults; +defaults.kindOfResource = KindOfResource.Both; +defaults.keeping = false; + +let putKeep = _.routine.uniteCloning_replaceByUnite({ head : put_head, body : _put, name : 'putKeep' }); +var defaults = putKeep.defaults; +defaults.kindOfResource = KindOfResource.Both; +defaults.keeping = true; + +let thenPutGive = _.routine.uniteCloning_replaceByUnite({ head : put_head, body : _put, name : 'thenPutGive' }); +var defaults = thenPutGive.defaults; +defaults.kindOfResource = KindOfResource.ArgumentOnly; +defaults.keeping = false; + +let thenPutKeep = _.routine.uniteCloning_replaceByUnite({ head : put_head, body : _put, name : 'thenPutKeep' }); +var defaults = thenPutKeep.defaults; +defaults.kindOfResource = KindOfResource.ArgumentOnly; +defaults.keeping = true; + +// -- +// time +// -- + +/** + * Works like finally, but when competitor accepts resource from resources sequence, execution of competitor will be + delayed. The result of competitor execution will be passed to the competitor that is first in competitor queue + on execution end moment. + + * @example + * + function gotHandler1( error, value ) + { + console.log( 'competitor 1: ' + value ); + value++; + return value; + } + + function gotHandler2( error, value ) + { + console.log( 'competitor 2: ' + value ); + } + + let con = new _.Consequence(); + + con.delay( 500, gotHandler1 ).finallyGive( gotHandler2 ); + con.take( 90 ); + // prints: + // competitor 1: 90 + // competitor 2: 91 + + * @param {number} time delay in milliseconds + * @param {Competitor|wConsequence} competitor callback, that accepts exception reason and value. + * @returns {wConsequence} + * @throws {Error} if missed arguments. + * @throws {Error} if passed extra arguments. + * @see {@link module:Tools/base/Consequence.wConsequence#finally} finally method + * @method delay + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +// + +function delay_head( routine, args ) +{ + // let o = { time : args[ 0 ], callback : args[ 1 ] }; + let o = { time : args[ 0 ] }; + _.routine.options_( routine, o ); + _.assert( arguments.length === 2 ); + _.assert( args.length === 1, 'Expects single argument' ); + _.assert( _.numberIs( o.time ) ); + return o; +} + +// + +/* qqq : rewrite method _delay with routine _.time.begin() instead of routine _.time.out() */ + +function _delay( o ) +{ + let self = this; + let time = o.time; + + /* */ + + let competitorRoutine; + if( o.kindOfResource === Self.KindOfResource.Both ) + competitorRoutine = __delayFinally; + else if( o.kindOfResource === Self.KindOfResource.ArgumentOnly ) + competitorRoutine = __delayThen; + else if( o.kindOfResource === Self.KindOfResource.ErrorOnly ) + competitorRoutine = __delayCatch; + else _.assert( 0 ); + + /* */ + + self._competitorAppend + ({ + keeping : false, + competitorRoutine, + kindOfResource : o.kindOfResource, + stack : 4, /* delta : 4 to not include info about `routine.unite` in the stack */ + }); + + self.__handleResourceSoon( false ); + + return self; + + /**/ + + /* qqq for Dmytro : ! */ + function __delayFinally( err, arg ) + { + // console.log( '__delayFinally:1' ); + _.time.begin( o.time, () => + { + // console.log( '__delayFinally:2' ); + self.take( err, arg ) + }); + } + + /**/ + + function __delayCatch( err ) + { + _.time.begin( o.time, () => self.take( undefined, err ) ); + } + + /**/ + + function __delayThen( arg ) + { + _.time.begin( o.time, () => self.take( arg ) ); + } + + /**/ + +} + +_delay.defaults = +{ + time : null, + kindOfResource : null, +} + +_delay.having = +{ + consequizing : 1, +} + +let finallyDelay = _.routine.uniteCloning_replaceByUnite({ head : delay_head, body : _delay, name : 'finallyDelay' }); +var defaults = finallyDelay.defaults; +defaults.kindOfResource = KindOfResource.Both; + +let thenDelay = _.routine.uniteCloning_replaceByUnite({ head : delay_head, body : _delay, name : 'thenDelay' }); +var defaults = thenDelay.defaults; +defaults.kindOfResource = KindOfResource.ArgumentOnly; + +let exceptDelay = _.routine.uniteCloning_replaceByUnite({ head : delay_head, body : _delay, name : 'exceptDelay' }); +var defaults = exceptDelay.defaults; +defaults.kindOfResource = KindOfResource.ErrorOnly; + +// + +function timeLimit_head( routine, args ) +{ + let o = { time : args[ 0 ], callback : args[ 1 ] }; + if( o.callback === undefined ) + o.callback = _.nothing; + _.routine.options_( routine, o ); + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + _.assert( _.numberIs( o.time ) ); + return o; +} + +// + +function _timeLimit( o ) +{ + let self = this; + let time = o.time; + let callback = o.callback; + let callbackConsequence = callback; + let error = o.error; + let timeOutConsequence = new _.Consequence(); + let done = false; + let timer; + let procedure = self.procedureDetach() || _.Procedure( 3 ); /* delta : 3 to not include info about `routine.unite` in the stack */ + + _.assert( arguments.length === 1 ); + _.assert( callback !== undefined && callback !== _.nothing, 'Expects callback or consequnce to time limit it' ); + + if( !_.consequenceIs( callbackConsequence ) ) + { + if( _.routineIs( callbackConsequence ) ) + callbackConsequence = new _.Consequence(); + else + callback = callbackConsequence = _.Consequence.From( callbackConsequence ); + + // if( !_.routineIs( callbackConsequence ) ) + // callback = callbackConsequence = _.Consequence.From( callbackConsequence ); + // else + // callbackConsequence = new _.Consequence(); + } + + let c = self._competitorAppend + ({ + keeping : false, + competitorRoutine : _timeLimitCallback, + kindOfResource : KindOfResource.Both, + stack : 4, /* delta : 4 to not include info about `routine.unite` in the stack */ + }); + + self.procedure( () => procedure.clone() ).nameElse( 'timeLimit' ); + self.orKeeping([ callbackConsequence, timeOutConsequence ]); + self.procedure( () => procedure.clone() ).nameElse( 'timeLimit' ); + self.tap( () => + { + done = true; + if( timer ) + _.time.cancel( timer ); + }); + + self.__handleResourceSoon( false ); + + return self; + + /* */ + + function _timeLimitCallback( err, arg ) + { + + if( err ) + { + _.assert( !done, 'not tested' ); + procedure.finit(); + if( !done ) + timeOutConsequence.error( err ); + return; + } + + _.assert( !done, 'not tested' ); + if( !_.consequenceIs( callback ) ) + { + callback = _.Consequence.Try( () => callback() ) + // callback.procedure( () => procedure.clone() ); /* yyy */ + callback.finally( callbackConsequence ); + } + + timer = _.time.begin( o.time, procedure, () => + { + if( done ) + return; + if( error ) + timeOutConsequence.error( _.time._errTimeOut({ procedure, reason : 'time limit', consequnce : self }) ); + else + timeOutConsequence.take( _.time.out ); + }) + + } + + /* */ + +} + +_timeLimit.defaults = +{ + time : null, + callback : null, + error : 0, +} + +_timeLimit.having = +{ + consequizing : 1, +} + +let timeLimit = _.routine.uniteCloning_replaceByUnite({ head : timeLimit_head, body : _timeLimit, name : 'timeLimit' }); +var defaults = timeLimit.defaults; +defaults.kindOfResource = KindOfResource.Both; +defaults.error = 0; + +let timeLimitError = _.routine.uniteCloning_replaceByUnite({ head : timeLimit_head, body : _timeLimit, name : 'timeLimitError' }); +var defaults = timeLimitError.defaults; +defaults.kindOfResource = KindOfResource.Both; +defaults.error = 1; + +// + +function timeLimitSplit( time ) +{ + let self = this; + let result = new _.Consequence(); + self._procedure = new _.Procedure( 1 ); /* create a procedure to later detach it in `_timeLimit` to have a proper _sourcePath */ + + _.assert( arguments.length === 1 ); + + result._timeLimit + ({ + time, + callback : self, + kindOfResource : KindOfResource.Both, + error : 0, + }); + + result.take( null ); + + return result; +} + +// + +function timeLimitErrorSplit( time ) +{ + let self = this; + let result = new _.Consequence(); + self._procedure = new _.Procedure( 1 ); /* create a procedure to later detach it in `_timeLimit` to have a proper _sourcePath */ + + _.assert( arguments.length === 1 ); + + result._timeLimit + ({ + time, + callback : self, + kindOfResource : KindOfResource.Both, + error : 1, + }); + + result.take( null ); + + return result; +} + +// + +function TimeLimit( timeLimit, consequence ) +{ + let result = new _.Consequence({ _procedure : new _.Procedure( 1 ) }).take( null ) /* create a procedure to later detach it in `_timeLimit` to have a proper _sourcePath */ + .timeLimit( timeLimit, consequence ); + return result; +} + +// + +function TimeLimitError( timeLimit, consequence ) +{ + let result = new _.Consequence({ _procedure : new _.Procedure( 1 ) }).take( null ) /* create a procedure to later detach it in `_timeLimit` to have a proper _sourcePath */ + .timeLimitError( timeLimit, consequence ); + return result; +} + +// -- +// and +// -- + +function and_head( routine, args ) +{ + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { competitors : args[ 0 ] }; + + _.routine.options_( routine, o ); + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 ); + + return o; +} + +// + +function _and( o ) +{ + let self = this; + let errs = []; + let args = []; + let anyErr; + let competitors = o.competitors; + let keeping = o.keeping; + let accumulative = o.accumulative; + let waitingResource = o.waitingResource; + let waitingOthers = o.waitingOthers; + let procedure = self.procedure( o.stack, 2 ).nameElse( '_and' ); /* aaa2 : cover procedure.sourcePath of each derived routine */ /* Dmytro : covered */ /* delta : 2 to not include info about `routine.unite` in the stack */ + let escaped = 0; + let errOwner = {}; + + _.routine.assertOptions( _and, arguments ); + + /* */ + + if( _.argumentsArray.like( competitors ) ) + competitors = _.longSlice( competitors ); + else + competitors = [ competitors ]; + + if( waitingResource ) + competitors.push( self ); + else + competitors.unshift( self ); + + let left = competitors.length; + let first = waitingResource ? 0 : 1; + let last = waitingResource ? competitors.length-1 : competitors.length; + let indexOfSelf = waitingResource ? competitors.length-1 : 0; + + /* */ + + if( Config.debug && self.Diagnostics ) + competitorsCheck(); + + /* */ + + if( waitingResource ) + self.finallyGive( start ); + else + start(); + + escaped = 1; + return self; + + /* - */ + + function start( err, arg ) + { + + callbacksStart(); + + if( waitingResource ) + { + got2({ index : indexOfSelf, competitor : self, err, arg }); + } + else + self.finallyGive( ( err, arg ) => + { + got2({ index : indexOfSelf, competitor : self, err, arg }); + }); + + } + + /* - */ + + function callbacksStart() + { + let competitors2 = []; + + for( let c = first ; c < last ; c++ ) (function( c ) + { + let competitor = competitors[ c ]; + let originalCompetitor = competitor; + let wasRoutine = false; + + if( !_.consequenceIs( competitor ) && _.routineIs( competitor ) ) + try + { + wasRoutine = true; + competitor = competitors[ c ] = competitor(); + } + catch( err ) + { + competitor = competitors[ c ] = new _.Consequence().error( _.err( err ) ); + } + + // if( _.promiseLike( competitor ) ) + // competitor = competitors[ c ] = _.Consequence.From( competitor ); + + _.assert + ( + competitor !== undefined + , () => `Expects defined value, but got ${_.entity.strType( competitor )}` + + `${ _.routineIs( originalCompetitor ) ? '\n' + originalCompetitor.toString() : ''}` + ); + + if( waitingResource ) + { + + if( !_.consequenceIs( competitor ) ) /* xxx : teach And to accept non-consequence and cover */ + { + got2({ index : c, competitor : null, err : undefined, arg : competitor }); + return; + } + else if( _.longHas( competitors2, competitor ) ) + { + return; + } + + } + else + { + + if( _.consequenceIs( competitor ) ) + { + if( _.longHas( competitors2, competitor ) ) + return; + } + else + { + got2({ index : c, competitor : null, err : undefined, arg : competitor }); + return; + } + + } + + /* + accounting of dependencies of routines + consequences have already been accounted + */ + + competitors2.push( competitor ); + + if( wasRoutine ) + if( _.consequenceIs( competitor ) ) + if( Config.debug && self.Diagnostics ) + { + competitor.assertNoDeadLockWith( self ); + _.assert( !_.longHas( self._dependsOf, competitor ) ); + _.arrayAppendOnceStrictly( self._dependsOf, competitor ); + } + + competitor.procedure({ _stack : procedure.stack() }).nameElse( 'and' ); + competitor.finallyGive( ( err, arg ) => got2({ index : c, competitor, err, arg }) ); + + + })( c ); + + } + + /* */ + + function got2( op ) + { + + _.assert( _.consequenceIs( op.competitor ) || op.competitor === null ); + + if( op.err && !anyErr ) + anyErr = op.err; + + if( _.consequenceIs( op.competitor ) && op.index === undefined ) + for( let c = 0 ; c < competitors.length ; c++ ) + { + let competitor2 = competitors[ c ]; + if( competitor2 === op.competitor ) + op.index = c; + } + + _.assert( op.competitor === competitors[ op.index ] || op.competitor === null ); + + if( _.consequenceIs( op.competitor ) ) + for( let c = 0 ; c < competitors.length ; c++ ) + { + let competitor2 = competitors[ c ]; + if( competitor2 === op.competitor ) + account({ ... op, index : c }); + } + else + { + account( op ); + } + + if( Config.debug && self.Diagnostics ) + if( op.competitor !== self && _.consequenceIs( op.competitor ) ) + { + _.arrayRemoveElementOnceStrictly( self._dependsOf, op.competitor ); + } + + if( !waitingOthers && op.competitor !== self && _.consequenceIs( op.competitor ) ) + { + op.competitor.take( op.err, op.arg ); + } + + _.assert( left >= 0 ); + if( left === 0 ) + { + if( escaped && waitingResource ) + _.time.soon( done ); + else + done(); + } + + } + + /* */ + + function account( op ) + { + _.assert( op.index >= 0 ) + if( op.err ) + { + op.err = _.errSuspend( op.err, errOwner, true ); + // _.assert( op.err.suspended === errOwner ); + } + errs[ op.index ] = op.err; + args[ op.index ] = op.arg; + left -= 1; + } + + /* */ + + function done() + { + let competitors2 = []; + + for( let i = first ; i < last ; i++ ) + { + let err = errs[ i ]; + if( err ) + err = _.errSuspend( err, errOwner, false ); + } + + if( keeping && waitingOthers ) + for( let i = first ; i < last ; i++ ) + if( competitors[ i ] ) + { + let competitor = competitors[ i ]; + if( _.longHas( competitors2, competitor ) ) + continue; + if( !_.consequenceIs( competitor ) ) + continue; + + let err = errs[ i ]; + // if( err ) + // err = _.errSuspend( err, errOwner, false ); + + competitor.take( err, args[ i ] ); + competitors2.push( competitor ); + } + + if( accumulative ) + args = _.arrayFlatten( args ); + + if( anyErr ) + { + anyErr = _.errSuspend( anyErr, errOwner, false ); + } + + if( anyErr ) + self.error( anyErr ); + else + self.take( args ); + + } + + /* */ + + function competitorsCheck() + { + let competitors2 = []; + let convertedPromises; + + for( let s = first ; s < last ; s++ ) + { + let competitor = competitors[ s ]; + + // if( _.promiseLike( competitor ) ) /* Dmytro : base implementation */ + // competitor = competitors[ s ] = _.Consequence.From( competitor ); + + if( _.promiseLike( competitor ) ) /* Dmytro : needs conversion, because it allows append competitor in queue */ + competitor = promiseConvert( competitor, s, convertedPromises ); + + // _.assert /* Dmytro : allows to accept any type of competitors */ + // ( + // _.consequenceIs( competitor ) || _.routineIs( competitor ) || competitor === null, + // () => 'Consequence.and expects consequence, routine, promise or null, but got ' + _.entity.strType( competitor ) + // ); + + if( !_.consequenceIs( competitor ) ) + continue; + if( _.longHas( competitors2, competitor ) ) + continue; + + competitor.assertNoDeadLockWith( self ); + _.arrayAppendOnceStrictly( self._dependsOf, competitor ); + competitors2.push( competitor ); + } + + } + + /* */ + + function promiseConvert( competitor, s, convertedPromises ) + { + + if( !convertedPromises ) + convertedPromises = new HashMap(); /* Dmytro : provide fast search, contains links and indexes, temporary container */ + + let index = convertedPromises.get( competitor ); + if( index === undefined ) + { + convertedPromises.set( competitor, s ); + competitor = competitors[ s ] = _.Consequence.From( competitor ); + } + else + { + competitor = competitors[ s ] = competitors[ index ]; + } + + return competitor; + } + +} + +_and.defaults = +{ + competitors : null, + keeping : 0, + accumulative : 0, + waitingResource : 1, + waitingOthers : 1, + stack : 2, +} + +var having = _and.having = Object.create( null ); +having.consequizing = 1; +having.andLike = 1; + +// + +/** + * Method andTake() takes each resource, which is received by competitors {-competitors-}. The competitors does not + * resolve resources. If Consequence-owner is ready to resolve its own resource and any of handled Consequences + * receives not resource, then it will wait until all passed competitors will receive resource. Finally, + * Consequence-owner resolve all received resources and its own resource. + * + * @example + * let track = []; + * let conOwner = new _.Consequence(); + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * conOwner.andTake([ con1, con2 ]); + * + * conOwner.take( 100 ); + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * con1.cancel(); + * con2.cancel(); + * + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // [ 'con1 take', 'con2 take' ] + * // Value : [ 'value1', 'value2', 100 ] + * + * Basic parameter set : + * @param { Array } competitors - Array of competitors of any type. + * Alternative parameter set : + * @param { Map } o - Options map. + * @param { Array } o.competitors - Array of competitors of any type. + * @returns { Consequence } - Returns Consequence-owner when all handled Consequences will be resolved. + * @throws { Error } If arguments.length is 0. + * @throws { Error } If arguments.length is greater than 1. + * @throws { Error } If {-competitors-} has not valid type. + * @throws { Error } If {-o-} has not valid type. + * @throws { Error } If {-o.competitors-} has not valid type. + * @throws { Error } If {-o-} has extra properties. + * @method andTake + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +let andTake = _.routine.uniteCloning_replaceByUnite({ head : and_head, body : _and, name : 'andTake' }); +var defaults = andTake.defaults; +defaults.keeping = false; + +// + +/** + * Method andKeep() copies each resource, which is received by competitors {-competitors-} to own resources. + * Each handled competitor resolve its resources. If Consequence-owner is ready to resolve its own resource + * and any of handled Consequences resolve not resource, then it will wait until all passed competitors will + * receive and resolve resource. Finally, Consequence-owner resolve all received resources and its own resource. + * + * @example + * let track = []; + * let conOwner = new _.Consequence(); + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * conOwner.andKeep([ con1, con2 ]); + * + * conOwner.take( 100 ); + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // con1 competitor executed with value : value1 and error : undefined + * // con2 competitor executed with value : value2 and error : undefined + * // [ 'con1 take', 'con1 tap', 'con2 take', 'con2 tap' ] + * // Value : [ 'value1', 'value2', 100 ] + * + * Basic parameter set : + * @param { Array } competitors - Array of competitors of any type. + * Alternative parameter set : + * @param { Map } o - Options map. + * @param { Array } o.competitors - Array of competitors of any type. + * @returns { Consequence } - Returns Consequence-owner when all handled Consequences will be resolved. + * @throws { Error } If arguments.length is 0. + * @throws { Error } If arguments.length is greater than 1. + * @throws { Error } If {-competitors-} has not valid type. + * @throws { Error } If {-o-} has not valid type. + * @throws { Error } If {-o.competitors-} has not valid type. + * @throws { Error } If {-o-} has extra properties. + * @method andKeep + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +let andKeep = _.routine.uniteCloning_replaceByUnite({ head : and_head, body : _and, name : 'andKeep' }); +var defaults = andKeep.defaults; +defaults.keeping = true; + +// + +/* aaa : jsdoc, please */ /* Dmytro : documented */ + +/** + * Method andImmediate() copies each resource, which resolved by competitors {-competitors-} to own resources. + * If Consequence-owner is ready to resolve its own resource and any of handled Consequences has unresolved resource, + * then it will wait until all passed competitors will be resolved. Finally, Consequence-owner resolve own resources. + * If any of competitors was rejected, then Consequence-owner resolve not own resource and get only rejected error. + * + * @example + * let track = []; + * let conOwner = new _.Consequence(); + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * conOwner.andImmediate([ con1, con2 ]); + * + * conOwner.take( 100 ); + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * con1.cancel(); + * con2.cancel(); + * + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // con1 competitor executed with value : value1 and error : undefined + * // con2 competitor executed with value : value2 and error : undefined + * // [ 'con1 take', 'con1 tap', 'con2 take', 'con2 tap' ] + * // Value : [ 'value1', 'value2', 100 ] + * + * Basic parameter set : + * @param { Array } competitors - Array of competitors of any type. + * Alternative parameter set : + * @param { Map } o - Options map. + * @param { Array } o.competitors - Array of competitors of any type. + * @returns { Consequence } - Returns Consequence-owner when all handled Consequences will be resolved. + * @throws { Error } If arguments.length is 0. + * @throws { Error } If arguments.length is greater than 1. + * @throws { Error } If {-competitors-} has not valid type. + * @throws { Error } If {-o-} has not valid type. + * @throws { Error } If {-o.competitors-} has not valid type. + * @throws { Error } If {-o-} has extra properties. + * @method andImmediate + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +let andImmediate = _.routine.uniteCloning_replaceByUnite({ head : and_head, body : _and, name : 'andKeep' }); +var defaults = andImmediate.defaults; +defaults.keeping = true; +defaults.waitingOthers = false; + +// + +/* aaa : jsdoc, please */ /* Dmytro : documented */ + +/** + * Method andKeepAccumulative() copies each resource, which received by competitors {-competitors-} to own resources. + * If Consequence-owner is ready to resolve its own resource and any of handled Consequences received no resource, + * then it will wait until all passed competitors will have resource. Finally, competitors resolve own resources in order + * of receiving and Consequence-owner resolve all resources. + * + * @example + * let track = []; + * let conOwner = new _.Consequence(); + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * conOwner.andKeepAccumulative([ con1, con2 ]); + * + * conOwner.take( 100 ); + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * con1.cancel(); + * con2.cancel(); + * + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // con1 competitor executed with value : value1 and error : undefined + * // con2 competitor executed with value : value2 and error : undefined + * // [ 'con1 take', 'con1 tap', 'con2 take', 'con2 tap' ] + * // Value : [ 'value1', 'value2', 100 ] + * + * Basic parameter set : + * @param { Array } competitors - Array of competitors of any type. + * Alternative parameter set : + * @param { Map } o - Options map. + * @param { Array } o.competitors - Array of competitors of any type. + * @returns { Consequence } - Returns Consequence-owner when all handled Consequences will be resolved. + * @throws { Error } If arguments.length is 0. + * @throws { Error } If arguments.length is greater than 1. + * @throws { Error } If {-competitors-} has not valid type. + * @throws { Error } If {-o-} has not valid type. + * @throws { Error } If {-o.competitors-} has not valid type. + * @throws { Error } If {-o-} has extra properties. + * @method andKeepAccumulative + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +let andKeepAccumulative = _.routine.uniteCloning_replaceByUnite({ head : and_head, body : _and, name : 'andKeepAccumulative' }); +var defaults = andKeepAccumulative.defaults; +defaults.keeping = true; +defaults.accumulative = true; + +// + +/** + * Method alsoTake() calls passed callback without waiting for resource and takes result of the call into an array. + * To convert serial code to parallel replace methods {then}/{finally} by methods {also*}, without need to change + * structure of the code, what methods {and*} require. + * First element of returned array has a resource which the Consequence-owner have had before call of ${also} + * or the first which the Consequence will get later. + * + * @example + * let track = []; + * let conOwner = new _.Consequence(); + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * conOwner.alsoTake([ con1, con2 ]); + * + * conOwner.take( 100 ); + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * con1.cancel(); + * con2.cancel(); + * + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // [ 'con1 take', 'con2 take' ] + * // Value : [ 100, 'value1', 'value2' ] + * + * Basic parameter set : + * @param { Array } competitors - Array of competitors of any type. + * Alternative parameter set : + * @param { Map } o - Options map. + * @param { Array } o.competitors - Array of competitors of any type. + * @returns { Consequence } - Returns Consequence-owner when all handled Consequences will be resolved. + * @throws { Error } If arguments.length is 0. + * @throws { Error } If arguments.length is greater than 1. + * @throws { Error } If {-competitors-} has not valid type. + * @throws { Error } If {-o-} has not valid type. + * @throws { Error } If {-o.competitors-} has not valid type. + * @throws { Error } If {-o-} has extra properties. + * @method alsoTake + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + + +let alsoTake = _.routine.uniteCloning_replaceByUnite({ head : and_head, body : _and, name : 'alsoTake' }); +var defaults = alsoTake.defaults; +defaults.keeping = false; +defaults.accumulative = true; +defaults.waitingResource = false; + +// + +/** + * Method alsoKeep() calls passed callback without waiting for resource and copies result of the call into an array. + * To convert serial code to parallel replace methods {then}/{finally} by methods {also*}, without need to change + * structure of the code, what methods {and*} require. + * First element of returned array has a resource which the Consequence-owner have had before call of ${also} + * or the first which the Consequence will get later. + * + * @example + * let track = []; + * let conOwner = new _.Consequence(); + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * conOwner.alsoKeep([ con1, con2 ]); + * + * conOwner.take( 100 ); + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // con1 competitor executed with value : value1 and error : undefined + * // con2 competitor executed with value : value2 and error : undefined + * // [ 'con1 take', 'con2 take', 'con1.tap', 'con2.tap' ] + * // Value : [ 100, 'value1', 'value2' ] + * + * Basic parameter set : + * @param { Array } competitors - Array of competitors of any type. + * Alternative parameter set : + * @param { Map } o - Options map. + * @param { Array } o.competitors - Array of competitors of any type. + * @returns { Consequence } - Returns Consequence-owner when all handled Consequences will be resolved. + * @throws { Error } If arguments.length is 0. + * @throws { Error } If arguments.length is greater than 1. + * @throws { Error } If {-competitors-} has not valid type. + * @throws { Error } If {-o-} has not valid type. + * @throws { Error } If {-o.competitors-} has not valid type. + * @throws { Error } If {-o-} has extra properties. + * @method alsoKeep + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +let alsoKeep = _.routine.uniteCloning_replaceByUnite({ head : and_head, body : _and, name : 'alsoKeep' }); +var defaults = alsoKeep.defaults; +defaults.keeping = true; +defaults.accumulative = true; +defaults.waitingResource = false; + +// + +/* aaa : jsdoc please */ /* Dmytro : documented */ + +/** + * Method alsoImmediate() calls passed callback without waiting for resource and immediatelly receive resource from the result. + * The resource copies to array. To convert serial code to parallel replace methods {then}/{finally} by methods {also*}, without + * need to change * structure of the code, what methods {and*} require. + * First element of returned array has a resource which the Consequence-owner have had before call of ${also} + * or the first which the Consequence will get later. + * + * @example + * let track = []; + * let conOwner = new _.Consequence(); + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * conOwner.alsoImmediate([ con1, con2 ]); + * + * conOwner.take( 100 ); + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // con1 competitor executed with value : value1 and error : undefined + * // con2 competitor executed with value : value2 and error : undefined + * // [ 'con1 take', 'con1.tap', 'con2 take', 'con2.tap' ] + * // Value : [ 100, 'value1', 'value2' ] + * + * Basic parameter set : + * @param { Array } competitors - Array of competitors of any type. + * Alternative parameter set : + * @param { Map } o - Options map. + * @param { Array } o.competitors - Array of competitors of any type. + * @returns { Consequence } - Returns Consequence-owner when all handled Consequences will be resolved. + * @throws { Error } If arguments.length is 0. + * @throws { Error } If arguments.length is greater than 1. + * @throws { Error } If {-competitors-} has not valid type. + * @throws { Error } If {-o-} has not valid type. + * @throws { Error } If {-o.competitors-} has not valid type. + * @throws { Error } If {-o-} has extra properties. + * @method alsoImmediate + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +let alsoImmediate = _.routine.uniteCloning_replaceByUnite({ head : and_head, body : _and, name : 'alsoImmediate' }); +var defaults = alsoImmediate.defaults; +defaults.keeping = true; +defaults.accumulative = true; +defaults.waitingResource = false; +defaults.waitingOthers = false; + +// + +/* aaa : jsdoc please */ /* Dmytro : documented */ + +/** + * Static routine AndTake() takes each resource, which is received by competitors provided in arguments. The competitors + * does not resolve resources. The routine returns resulted Consequence when all passed competitors will receive resource. + * + * @example + * let track = []; + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * let conOwner = _.Consequence.AndTake( con1, con2 ); + * + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * con1.cancel(); + * con2.cancel(); + * + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // [ 'con1 take', 'con2 take' ] + * // Value : [ 'value1', 'value2' ] + * + * @param { * } ... arguments - Unlimited number of competitors of any type in arguments. + * @returns { Consequence } - Returns new Consequence when all passed competitors will be resolved. + * @throws { Error } If routine calls by instance of Consequence. + * @static + * @function AndTake + * @module Tools/base/Consequence + * @namespace wTools.Consequence + * @class wConsequence + */ + +function AndTake() +{ + _.assert( !_.instanceIs( this ) ) + let result = _.Consequence().take( null ); + result.procedure( 1 ); + result.andTake( arguments ); + result.procedure( 1 ).nameElse( 'AndTake' ); + result.then( ( arg ) => + { + _.assert( arg[ arg.length - 1 ] === null ); + arg.splice( arg.length - 1, 1 ); + return arg; + }); + return result; +} + +// + +/* aaa : cover that procedures of AndTake and AndKeep has correct sourcePath */ /* Dmytro : covered */ + +/* qqq : jsdoc please */ /* Dmytro : documented */ + +/** + * Static routine AndKeep() copies each resource, which is received by competitors provided in arguments. The competitors + * resolve resources. The routine returns resulted Consequence when all passed competitors will receive resource. + * + * @example + * let track = []; + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * let conOwner = _.Consequence.AndKeep( con1, con2 ); + * + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // con1 competitor executed with value : value1 and error : undefined + * // con2 competitor executed with value : value2 and error : undefined + * // [ 'con1 take', 'con1.tap', 'con2 take', 'con2.tap' ] + * // Value : [ 'value1', 'value2' ] + * + * @param { * } ... arguments - Unlimited number of competitors of any type in arguments. + * @returns { Consequence } - Returns new Consequence when all passed competitors will be resolved. + * @throws { Error } If routine calls by instance of Consequence. + * @static + * @function AndKeep + * @module Tools/base/Consequence + * @namespace wTools.Consequence + * @class wConsequence + */ + +function AndKeep() +{ + _.assert( !_.instanceIs( this ) ) + let result = _.Consequence().take( null ); + result.procedure( 1 ); + result.andKeep( arguments ); + result.procedure( 1 ).nameElse( 'AndKeep' ); + result.then( ( arg ) => + { + _.assert( arg[ arg.length - 1 ] === null ); + arg.splice( arg.length - 1, 1 ); + return arg; + }); + return result; +} + +// + +/* aaa : jsdoc please */ /* Dmytro : documented */ + +/* aaa : cover please */ /* Dmytro : covered */ + +/** + * Static routine AndImmediate() copies each resource, which is received by competitors provided in arguments. The competitors + * resolve resources immediatelly after receiving. The routine returns resulted Consequence when all passed competitors will + * receive resource. + * + * @example + * let track = []; + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * let conOwner = _.Consequence.AndImmediate( con1, con2 ); + * + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // con1 competitor executed with value : value1 and error : undefined + * // con2 competitor executed with value : value2 and error : undefined + * // [ 'con1 take', 'con1.tap', 'con2 take', 'con2.tap' ] + * // Value : [ 'value1', 'value2' ] + * + * @param { * } ... arguments - Unlimited number of competitors of any type in arguments. + * @returns { Consequence } - Returns new Consequence when all passed competitors will be resolved. + * @throws { Error } If routine calls by instance of Consequence. + * @static + * @function AndImmediate + * @module Tools/base/Consequence + * @namespace wTools.Consequence + * @class wConsequence + */ + +function AndImmediate() +{ + _.assert( !_.instanceIs( this ) ) + let result = _.Consequence().take( null ); + result.procedure( 1 ); + result.andImmediate( arguments ); + result.procedure( 1 ).nameElse( 'AndImmediate' ); + result.then( ( arg ) => + { + _.assert( arg[ arg.length - 1 ] === null ); + arg.splice( arg.length - 1, 1 ); + return arg; + }); + return result; +} + +// -- +// or +// -- + +/* aaa2 : write head similar _and has and use it in or* routines */ /* Dmytro : implemented, used */ + +function or_head( routine, args ) +{ + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { competitors : args[ 0 ] }; + + _.routine.options_( routine, o ); + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 ); + + return o; +} + +// + +function _or( o ) +{ + let self = this; + let count = 0; + let procedure = self.procedure( o.stack, 2 ).nameElse( '_or' ); /* aaa2 : cover procedure.sourcePath of each derived routine */ /* Dmytro : covered */ /* delta : 2 to not include info about `routine.unite` in the stack */ + let competitors = o.competitors; + let competitorRoutines = []; + + _.routine.assertOptions( _or, arguments ); + + if( _.argumentsArray.like( competitors ) ) + competitors = _.longSlice( competitors ); + else + competitors = [ competitors ]; + + /* aaa2 : implement tests : arguments are promises */ /* Dmytro : implemented */ + + for( let c = competitors.length-1 ; c >= 0 ; c-- ) + { + let competitorRoutine = competitors[ c ]; + if( _.promiseLike( competitorRoutine ) ) + competitors[ c ] = competitorRoutine = _.Consequence.From( competitorRoutine ); + // competitorRoutine = _.Consequence.From( competitorRoutine ); /* Dmytro : competitor should be a Consequence, see below */ + _.assert( _.consequenceIs( competitorRoutine ) || competitorRoutine === null ); + if( competitorRoutine === null ) + competitors.splice( c, 1 ); + } + + /* */ + + if( o.waitingResource ) + { + self.thenGive( function( arg ) + { + _init(); + }); + } + else + { + competitors.unshift( self ); + _init(); + } + + return self; + + /* - */ + + function _init() + { + + for( let c = 0 ; c < competitors.length ; c++ ) + { + let competitor = competitors[ c ]; + + _.assert( _.consequenceIs( competitor ) ); + + let competitorRoutine = competitorRoutines[ c ] = _.routineJoin( undefined, _got, [ c ] ); + competitor.procedure({ _stack : procedure.stack() }).nameElse( 'orVariant' ); + competitor.finallyGive( competitorRoutine ); + + if( count ) + break; + } + + } + + /* - */ + + function _got( index, err, arg ) + { + + count += 1; + + _.assert( count === 1 ); + + for( let c = 0 ; c < competitors.length ; c++ ) + { + let competitor = competitors[ c ]; + let competitorRoutine = competitorRoutines[ c ]; + _.assert( !!competitor ); + if( competitorRoutine ) + if( competitor.competitorOwn( competitorRoutine ) ) + competitor.competitorsCancel( competitorRoutine ); + } + + if( o.keeping ) + if( o.waitingResource || index !== 0 ) + competitors[ index ].take( err, arg ); + + if( count === 1 ) + self.take( err, arg ); + + } + + /* - */ + +} + +_or.defaults = +{ + competitors : null, + keeping : null, + waitingResource : null, + stack : 2, +} + +/* xxx : implement option::cenceling for consequence? */ +/* xxx : remove map having? */ + +_or.having = +{ + consequizing : 1, + orLike : 1, +} + +// + +// function afterOrTaking( competitors ) +// { +// let self = this; +// _.assert( arguments.length === 1, 'Expects single argument' ); +// return self._or +// ({ +// competitors, +// keeping : false, +// waitingResource : true, +// stack : 2, +// }); +// } + +/** + * Method afterOrTaking() takes first received resource and resolve it - any of resource received by competitors {-competitors-}. + * The competitor, which is received resource does not resolve it. + * If Consequence-owner receives resource before any of competitors {-competitors-} receives resource, then Consequence- + * owner resolves resource received by another competitor after it receives resource. + * If Consequence-owner receives no resource after all competitors {-competitors-} receive resources, then Consequence- + * owner waits for resource. + * + * @example + * let track = []; + * let conOwner = new _.Consequence(); + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * conOwner.afterOrKeeping([ con1, con2 ]); + * + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * con1.cancel(); + * + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // [ 'con1 take' ] + * // Value : 'value1' + * // con2 competitor executed with value : value2 and error : undefined + * + * Basic parameter set : + * @param { Array } competitors - Array of competitors. A competitor can be a Consequences, a Promise or Null. + * Alternative parameter set : + * @param { Map } o - Options map. + * @param { Array } o.competitors - Array of competitors. A competitor can be a Consequences, a Promise or Null. + * @returns { Consequence } - Returns Consequence-owner when any of competitors received its resource. + * @throws { Error } If arguments.length is 0. + * @throws { Error } If arguments.length is greater than 1. + * @throws { Error } If {-competitors-} has not valid type. + * @throws { Error } If any of elements of {-competitors-} has not valid type. + * @throws { Error } If {-o-} has not valid type. + * @throws { Error } If {-o.competitors-} has not valid type. + * @throws { Error } If any of elements of {-o.competitors-} has not valid type. + * @throws { Error } If {-o-} has extra properties. + * @method afterOrKeeping + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +let afterOrTaking = _.routine.uniteCloning_replaceByUnite({ head : or_head, body : _or, name : 'afterOrTaking' }); + +afterOrTaking.defaults = Object.create( _or.defaults ); +afterOrTaking.defaults.keeping = false; +afterOrTaking.defaults.waitingResource = true; + +afterOrTaking.having = Object.create( _or.having ); + +// + +// function afterOrKeeping( competitors ) +// { +// let self = this; +// _.assert( arguments.length === 1, 'Expects single argument' ); +// return self._or +// ({ +// competitors, +// keeping : true, +// waitingResource : true, +// stack : 2, +// }); +// } + +/** + * Method afterOrKeeping() takes first received resource and resolve it - any of resource received by competitors {-competitors-}. + * The competitor, which is received resource resolves it. + * If Consequence-owner receives resource before any of competitors {-competitors-} receives resource, then Consequence- + * owner resolves resource received by another competitor after it receives resource. + * If Consequence-owner receives no resource after all competitors {-competitors-} receive resources, then Consequence- + * owner waits for resource. + * + * @example + * let track = []; + * let conOwner = new _.Consequence(); + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * conOwner.afterOrKeeping([ con1, con2 ]); + * + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // con1 competitor executed with value : value1 and error : undefined + * // [ 'con1 take', 'con1.tap' ] + * // Value : 'value1' + * // con2 competitor executed with value : value2 and error : undefined + * + * Basic parameter set : + * @param { Array } competitors - Array of competitors. A competitor can be a Consequences, a Promise or Null. + * Alternative parameter set : + * @param { Map } o - Options map. + * @param { Array } o.competitors - Array of competitors. A competitor can be a Consequences, a Promise or Null. + * @returns { Consequence } - Returns Consequence-owner when any of competitors received its resource. + * @throws { Error } If arguments.length is 0. + * @throws { Error } If arguments.length is greater than 1. + * @throws { Error } If {-competitors-} has not valid type. + * @throws { Error } If any of elements of {-competitors-} has not valid type. + * @throws { Error } If {-o-} has not valid type. + * @throws { Error } If {-o.competitors-} has not valid type. + * @throws { Error } If any of elements of {-o.competitors-} has not valid type. + * @throws { Error } If {-o-} has extra properties. + * @method afterOrKeeping + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +let afterOrKeeping = _.routine.uniteCloning_replaceByUnite({ head : or_head, body : _or, name : 'afterOrKeeping' }); + +afterOrKeeping.defaults = Object.create( _or.defaults ); +afterOrKeeping.defaults.keeping = true; +afterOrKeeping.defaults.waitingResource = true; + +afterOrKeeping.having = Object.create( _or.having ); + +/* +con0.orKeepingSplit([ con1, con2 ]) -> _.Consequence.Or( con0, con1, con2 ); +*/ + +// // +// +// function orKeepingSplit( competitors ) +// { +// let self = this; +// _.assert( arguments.length === 1, 'Expects single argument' ); +// +// if( _.argumentsArray.like( competitors ) ) +// competitors = _.longSlice( competitors ); +// else +// competitors = [ competitors ]; +// +// competitors.unshift( self ); +// +// let con = new Self().take( null ); +// +// con.procedure( 2 ).nameElse( 'orKeepingSplit' ); +// con.afterOrKeeping( competitors ); +// +// return con; +// } +// +// orKeepingSplit.having = Object.create( _or.having ); + +// + +// function orTaking( competitors ) +// { +// let self = this; +// _.assert( arguments.length === 1, 'Expects single argument' ); +// return self._or +// ({ +// competitors, +// keeping : false, +// waitingResource : false, +// stack : 2, +// }); +// } + +/** + * Method orTaking() takes first received resource and resolve it - its own resource or any of resource received by + * competitors {-competitors-}. The competitor, which is received resource does not resolve it. + * If Consequence-owner receives resource before any of competitors {-competitors-} receives resource, then Consequence- + * owner resolves received resource immediately. + * + * @example + * let track = []; + * let conOwner = new _.Consequence(); + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * conOwner.orTaking([ con1, con2 ]); + * + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * con1.cancel(); + * + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // [ 'con1 take' ] + * // Value : 'value1' + * // con2 competitor executed with value : value2 and error : undefined + * + * Basic parameter set : + * @param { Array } competitors - Array of competitors. A competitor can be a Consequences, a Promise or Null. + * Alternative parameter set : + * @param { Map } o - Options map. + * @param { Array } o.competitors - Array of competitors. A competitor can be a Consequences, a Promise or Null. + * @returns { Consequence } - Returns Consequence-owner when any of competitors received its resource. + * @throws { Error } If arguments.length is 0. + * @throws { Error } If arguments.length is greater than 1. + * @throws { Error } If {-competitors-} has not valid type. + * @throws { Error } If any of elements of {-competitors-} has not valid type. + * @throws { Error } If {-o-} has not valid type. + * @throws { Error } If {-o.competitors-} has not valid type. + * @throws { Error } If any of elements of {-o.competitors-} has not valid type. + * @throws { Error } If {-o-} has extra properties. + * @method orTaking + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +let orTaking = _.routine.uniteCloning_replaceByUnite({ head : or_head, body : _or, name : 'orTaking' }); + +orTaking.defaults = Object.create( _or.defaults ); +orTaking.defaults.keeping = false; +orTaking.defaults.waitingResource = false; + +orTaking.having = Object.create( _or.having ); + +// + +// function orKeeping( competitors ) +// { +// let self = this; +// _.assert( arguments.length === 1, 'Expects single argument' ); +// return self._or +// ({ +// competitors, +// keeping : true, +// waitingResource : false, +// stack : 2, +// }); +// } + +/** + * Method orKeeping() resolve first received resource - its own resource or any of resource received by + * competitors {-competitors-}. The competitor, which is received resource resolves it immediately. + * If Consequence-owner receives resource before any of competitors {-competitors-} receives resource, then Consequence- + * owner resolves received resource immediately. + * + * @example + * let track = []; + * let conOwner = new _.Consequence(); + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * conOwner.orKeeping([ con1, con2 ]); + * + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // con1 competitor executed with value : value1 and error : undefined + * // [ 'con1 take', 'con1 tap' ] + * // Value : 'value1' + * // con2 competitor executed with value : value2 and error : undefined + * + * Basic parameter set : + * @param { Array } competitors - Array of competitors. A competitor can be a Consequences, a Promise or Null. + * Alternative parameter set : + * @param { Map } o - Options map. + * @param { Array } o.competitors - Array of competitors. A competitor can be a Consequences, a Promise or Null. + * @returns { Consequence } - Returns Consequence-owner when any of competitors resolve its resource. + * @throws { Error } If arguments.length is 0. + * @throws { Error } If arguments.length is greater than 1. + * @throws { Error } If {-competitors-} has not valid type. + * @throws { Error } If any of elements of {-competitors-} has not valid type. + * @throws { Error } If {-o-} has not valid type. + * @throws { Error } If {-o.competitors-} has not valid type. + * @throws { Error } If any of elements of {-o.competitors-} has not valid type. + * @throws { Error } If {-o-} has extra properties. + * @method orKeeping + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +let orKeeping = _.routine.uniteCloning_replaceByUnite({ head : or_head, body : _or, name : 'orKeeping' }); + +orKeeping.defaults = Object.create( _or.defaults ); +orKeeping.defaults.keeping = true; +orKeeping.defaults.waitingResource = false; + +orKeeping.having = Object.create( _or.having ); + +// + +/** + * Static routine OrTake() takes first received resource from any of passed competitors and resolve it. + * The competitor, which received a resource, does not resolve resource. + * + * @example + * let track = []; + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * let conOwner = _.Consequence.OrTake( con1, con2 ); + * + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * con1.cancel(); + * + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // [ 'con1 take' ] + * // Value : 'value1' + * // con2 competitor executed with value : value2 and error : undefined + * + * @param { Consequence|Promise|Null } ... arguments - Competitors to handle. + * @returns { Consequence } - Returns new Consequence when any of competitors received its resource. + * @throws { Error } If any of elements of {-arguments-} has not valid type. + * @throws { Error } If routine calls by instance of Consequence. + * static + * @method OrTake + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function OrTake( srcs ) +{ + _.assert( !_.instanceIs( this ) ) + let result = new _.Consequence().take( null ); + result.procedure( 1 ).nameElse( 'OrTake' ); + result.afterOrTaking( arguments ); + return result; +} + +// + +/** + * Static routine OrKeep() takes first received resource from any of passed competitors and resolve it. + * The competitor, which received a resource, resolves resource before. + * + * @example + * let track = []; + * let con1 = new _.Consequence(); + * let con2 = new _.Consequence(); + * + * let conOwner = _.Consequence.OrKeep( con1, con2 ); + * + * _.time.out( 50, () => + * { + * track.push( 'con1 take' ); + * con1.take( 'value1' ); + * }); + * _.time.out( 200, () => + * { + * track.push( 'con2 take' ); + * con2.take( 'value2' ); + * }); + * + * con1.tap( ( err, value ) => + * { + * track.push( 'con1 tap' ); + * console.log( `con1 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * con2.tap( ( err, value ) => + * { + * track.push( 'con2 tap' ); + * console.log( `con2 competitor executed with value : ${ value } and error : ${ err }` ); + * }); + * + * conOwner.finallyGive( ( err, val ) => + * { + * console.log( _.entity.exportString( track ) ); + * if( err ) + * console.log( `Error : ${ err }` ); + * else + * console.log( `Value : ${ _.entity.exportString( val ) }` ); + * }); + * + * // log : + * // con1 competitor executed with value : value1 and error : undefined + * // [ 'con1 take', 'con1.tap' ] + * // Value : 'value1' + * // con2 competitor executed with value : value2 and error : undefined + * + * @param { Consequence|Promise|Null } ... arguments - Competitors to handle. + * @returns { Consequence } - Returns new Consequence when any of competitors received its resource. + * @throws { Error } If any of elements of {-arguments-} has not valid type. + * @throws { Error } If routine calls by instance of Consequence. + * static + * @method OrKeep + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function OrKeep( srcs ) +{ + _.assert( !_.instanceIs( this ) ) + let result = new _.Consequence().take( null ); + result.procedure( 1 ).nameElse( 'OrKeep' ); + result.afterOrKeeping( arguments ); + return result; +} + +// + +function tolerantCallback() +{ + let self = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + return function tolerantCallback( err, arg ) + { + if( !err ) + err = undefined; + if( arg === null || err ) + arg = undefined; + return self( err, arg ); + } +} + +// -- +// resource +// -- + +function takeLater( timeOut, error, argument ) +{ + let self = this; + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( _.numberIs( timeOut ) ); + + if( argument === undefined ) + { + argument = arguments[ 1 ]; + error = undefined; + } + + if( error === null ) + error = undefined; + + _.assert( error !== undefined || argument !== undefined, 'Argument of take should be something, not undefined' ); + _.assert( error === undefined || argument === undefined, 'Cant take both error and argument, one should be undefined' ); + + /* */ + + _.time.begin( timeOut, function now() + { + self.take( error, argument ); + }); + + return self; +} + +takeLater.having = +{ + consequizing : 1, +} + +// + +function takeSoon( error, argument ) +{ + let self = this; + + if( arguments.length === 1 ) + { + argument = error; + error = undefined; + } + + if( error === null ) + error = undefined; + + _.assert( arguments.length === 2 || arguments.length === 1, 'Expects 1 or 2 arguments, but got ' + arguments.length ); + _.assert( error !== undefined || argument !== undefined, 'Argument of take should be something, not undefined' ); + _.assert( error === undefined || argument === undefined, 'Cant take both error and argument, one should be undefined' ); + + // self.__onTake( error, argument ); + + _.time.begin( 1, () => + { + self.take( error, argument ); + }); + + return self; +} + +// + +function takeAll() +{ + let self = this; + + for( let a = 0 ; a < arguments.length ; a++ ) + self.take( arguments[ a ] ); + + return self; +} + +// + +/** + * Method pushes `resource` into wConsequence resources queue. + * Method also can accept two parameters: error, and + * Returns current wConsequence instance. + * @example + * function gotHandler1( error, value ) + { + console.log( 'competitor 1: ' + value ); + }; + + let con1 = new _.Consequence(); + + con1.finallyGive( gotHandler1 ); + con1.take( 'hello' ); + + // prints " competitor 1: hello ", + * @param {*} [resource] Resolved value + * @returns {wConsequence} consequence current wConsequence instance. + * @throws {Error} if passed extra parameters. + * @method take + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function take( error, argument ) +{ + let self = this; + + if( arguments.length === 1 ) + { + argument = error; + error = undefined; + } + + if( error === null ) + error = undefined; + + _.assert( arguments.length === 2 || arguments.length === 1, 'Expects 1 or 2 arguments, but got ' + arguments.length ); + _.assert( error !== undefined || argument !== undefined, 'Argument of take should be something, not undefined' ); + _.assert( error === undefined || argument === undefined, 'Cant take both error and argument, one should be undefined' ); + + if( error !== undefined ) + error = self.__handleError( error ) + + self.__take( error, argument ); + + if( self.AsyncCompetitorHanding || self.AsyncResourceAdding ) + self.__handleResourceSoon( true ); + else + self.__handleResourceNow(); + + return self; +} + +take.having = +{ + consequizing : 1, +} + +// + +/** + * Using for adds to resource queue error reason, that using for informing corespondent that will handle it, about + * exception + * @example + function showResult(err, val) + { + if( err ) + { + console.log( 'handleGot1 error: ' + err ); + } + else + { + console.log( 'handleGot1 value: ' + val ); + } + }; + + let con = new _.Consequence(); + + function divade( x, y ) + { + let result; + if( y!== 0 ) + { + result = x / y; + con.take(result); + } + else + { + con.error( 'divide by zero' ); + } + } + + con.finallyGive( showResult ); + divade( 3, 0 ); + + // prints : handleGot1 error: divide by zero + * @param {*|Error} error error, or value that represent error reason + * @throws {Error} if passed extra parameters. + * @method error + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function error( error ) +{ + let self = this; + + _.assert( arguments.length === 1 || arguments.length === 0 ); + + if( arguments.length === 0 ) + error = _.err(); + + if( error !== undefined ) + error = self.__handleError( error ) + + self.__take( error, undefined ); + + if( self.AsyncCompetitorHanding || self.AsyncResourceAdding ) + self.__handleResourceSoon( true ); + else + self.__handleResourceNow(); + + return self; +} + +error.having = +{ + consequizing : 1, +} + +// + +function __take( error, argument ) +{ + let self = this; + + let resource = Object.create( null ); + resource.error = error; + resource.argument = argument; + + _.assert( error !== undefined || argument !== undefined, 'Argument of take should be something, not undefined' ); + _.assert( error === undefined || argument === undefined, 'Cant take both error and argument, one should be undefined' ); + _.assert( arguments.length === 2 ); + + // self.__onTake( error, argument ); /* aaa : Dmytro : commented due to task. Maybe, need to remove */ + + if( _.consequenceIs( argument ) ) + { + argument.finallyGive( self ); + return self; + } + else if( _.promiseLike( argument ) ) + { + Self.From( argument ).finallyGive( self ); + return self; + } + + if( Config.debug ) + { + if( error === undefined ) + if( !( !self.capacity || self._resources.length < self.capacity ) ) + { + let args = + [ + `Resource capacity of ${self.qualifiedName} set to ${self.capacity}, but got more resources.` + + `\nConsider resetting : "{ capacity : 0 }"` + ] + throw _._err({ args, stackRemovingBeginExcluding : /\bConsequence.s\b/ }); + } + if( !( error === undefined || argument === undefined ) ) + { + let args = + [ + '{-error-} and {-argument-} channels should not be in use simultaneously\n' + + '{-error-} or {-argument-} should be undefined, but currently ' + + '\n{-error-} is ' + _.entity.strType( error ) + + '\n{-argument-} is ' + _.entity.strType( argument ) + ] + throw _._err({ args, stackRemovingBeginExcluding : /\bConsequence.s\b/ }); + } + } + + self._resources.push( resource ); + + return self; +} + +// // +// +// function __onTake( err, arg ) /* aaa : Dmytro : commented due to task. Maybe, need to remove */ +// { +// let self = this; +// +// } +// +// // + +// /** +// * Creates and pushes resource object into wConsequence resources sequence, and trying to get and return result of +// handling this resource by appropriate competitor. +// * @example +// let con = new _.Consequence(); +// +// function increment( err, value ) +// { +// return ++value; +// }; +// +// +// con.finallyGive( increment ); +// let result = con.ping( undefined, 4 ); +// console.log( result ); +// // prints 5; +// * @param {*} error +// * @param {*} argument +// * @returns {*} result +// * @throws {Error} if missed arguments or passed extra arguments +// * @method ping +// * @module Tools/base/Consequence +// * @namespace Tools +// * @class wConsequence +// */ +// +// function _ping( error, argument ) +// { +// let self = this; +// +// throw _.err( 'deprecated' ); +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// +// let resource = +// { +// error, +// argument, +// } +// +// self._resources.push( resource ); +// let result = self.__handleResourceSoon(); +// +// return result; +// } + +// -- +// handling mechanism +// -- + +/** + * Creates and handles error object based on `err` parameter. + * Returns new _.Consequence instance with error in resources queue. + * @param {*} err error value. + * @returns {wConsequence} + * @private + * @method __handleError + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function __handleError( err, competitor ) +{ + let self = this; + + if( _.symbolIs( err ) ) + return err; + + if( Config.debug && competitor && err && !err.asyncCallsStack ) + { + err = _._err + ({ + args : [ err ], + level : 3, + asyncCallsStack : competitor.procedure ? [ competitor.procedure.stack() ] : null, + }); + } + else + { + if( !_.error.isFormed( err ) ) + err = _._err + ({ + args : [ err ], + level : 3, + }); + } + + // if( _.error.isAttended( err ) ) + // return err; + + _.error._handleUncaughtAsync( err ); + + return err; + // let timer = _.time._finally( self.UncaughtTimeOut, function uncaught() + // { + // + // if( _.error.isAttended( err ) ) + // return; + // + // // if( !_.time.timerInCancelBegun( timer ) && _.error.isSuspended( err ) ) /* yyy */ + // // return; + // + // if( _.error.isSuspended( err ) ) + // return; + // + // _.error._handleUncaught2( err, 'uncaught asynchronous error' ); + // return null; + // }); + // + // return err; +} + +// + +/** + * Method for processing corespondents and _resources queue. Provides handling of resolved resource values and errors by + corespondents from competitors value. Method takes first resource from _resources sequence and try to pass it to + the first corespondent in corespondents sequence. Method returns the result of current corespondent execution. + There are several cases of __handleResourceSoon behavior: + - if corespondent is regular function: + trying to pass resources error and argument values into corespondent and executing. If during execution exception + occurred, it will be catch by __handleError method. If corespondent was not added by tap or persist method, + __handleResourceSoon will remove resource from head of queue. + + If corespondent was added by finally, _onceThen, catchKeep, or by other "thenable" method of wConsequence, finally: + + 1) if result of corespondents is ordinary value, finally __handleResourceSoon method appends result of corespondent to the + head of resources queue, and therefore pass it to the next competitor in corespondents queue. + 2) if result of corespondents is instance of wConsequence, __handleResourceSoon will append current wConsequence instance + to result instance corespondents sequence. + + After method try to handle next resource in queue if exists. + + - if corespondent is instance of wConsequence: + in that case __handleResourceSoon pass resource into corespondent`s resources queue. + + If corespondent was added by tap, or one of finally, _onceThen, catchKeep, or by other "thenable" method of + wConsequence finally __handleResourceSoon try to pass current resource to the next competitor in corespondents sequence. + + - if in current wConsequence are present corespondents added by persist method, finally __handleResourceSoon passes resource to + all of them, without removing them from sequence. + + * @returns {*} + * @throws {Error} if on invocation moment the _resources queue is empty. + * @private + * @method __handleResourceSoon + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function __handleResourceSoon( isResource ) +{ + let self = this; + let async = isResource ? self.AsyncResourceAdding : self.AsyncCompetitorHanding; + + _.assert( _.boolIs( isResource ) ); + + if( async ) + { + + if( !self._competitorsEarly.length && !self._competitorsLate.length ) + return; + if( !self._resources.length ) + return; + + _.time.soon( () => self.__handleResourceNow() ); + + } + else + { + self.__handleResourceNow(); + } + +} + +// + +function __handleResourceNow() +{ + let self = this; + let counter = 0; + let consequences = []; + + do + { + while( __iteration() ); + self = consequences.pop(); + } + while( self ); + + function __iteration() + { + + if( !self._resources.length ) + return false; + if( !self._competitorsEarly.length && !self._competitorsLate.length ) + return false; + + /* */ + + let resource = self._resources[ 0 ]; + let competitor, isEarly; + + if( self._competitorsEarly.length > 0 ) + { + competitor = self._competitorsEarly.shift(); + isEarly = true; + } + else + { + competitor = self._competitorsLate.shift(); + isEarly = false; + } + + let isConsequence = _.consequenceIs( competitor.competitorRoutine ) + let errorOnly = competitor.kindOfResource === Self.KindOfResource.ErrorOnly; + let argumentOnly = competitor.kindOfResource === Self.KindOfResource.ArgumentOnly; + + let executing = true; + executing = executing && ( !errorOnly || ( errorOnly && !!resource.error ) ); + executing = executing && ( !argumentOnly || ( argumentOnly && !resource.error ) ); + + if( !executing ) + { + if( competitor.procedure ) + competitor.procedure.end(); + return true; + } + + /* resourceReusing */ + + _.assert( !!competitor.instant, 'not implemented' ); + + let resourceReusing = false; + resourceReusing = resourceReusing || !executing; + resourceReusing = resourceReusing || competitor.tapping; + if( isConsequence && competitor.keeping && competitor.instant ) + resourceReusing = true; + + if( !resourceReusing ) + self._resources.shift(); + + /* debug */ + + if( Config.debug ) + if( self.Diagnostics ) + { + if( isConsequence ) + _.arrayRemoveElementOnceStrictly( competitor.competitorRoutine._dependsOf, self ); + } + + if( isConsequence ) + { + + competitor.competitorRoutine.__take( resource.error, resource.argument ); + + if( competitor.procedure ) + competitor.procedure.end(); + + // if( !competitor.instant && competitor.keeping ) + // competitor.competitorRoutine._competitorAppend + // ({ + // competitorRoutine : self, + // keeping : true, + // kindOfResource : Self.KindOfResource.Both, + // stack : 3, + // instant : 1, + // late : 1, + // }); + + if( competitor.competitorRoutine.AsyncCompetitorHanding || competitor.competitorRoutine.AsyncResourceAdding ) + { + competitor.competitorRoutine.__handleResourceSoon( true ); + } + else + { + consequences.push( self ); + self = competitor.competitorRoutine; + } + + } + else + { + + /* call routine */ + + let throwenErr = 0; + let result; + + if( competitor.procedure ) + { + if( !competitor.procedure.use() ) + competitor.procedure.activate( true ); + _.assert( competitor.procedure.isActivated() ); + } + + try + { + if( errorOnly ) + result = competitor.competitorRoutine.call( self, resource.error ); + else if( argumentOnly ) + result = competitor.competitorRoutine.call( self, resource.argument ); + else + result = competitor.competitorRoutine.call( self, resource.error, resource.argument ); + } + catch( err ) + { + throwenErr = self.__handleError( err, competitor ); + } + + if( competitor.procedure ) + { + competitor.procedure.unuse(); + if( !competitor.procedure.isUsed() ) + { + competitor.procedure.activate( false ); + competitor.procedure.end(); + } + } + + if( !throwenErr ) + if( competitor.keeping && result === undefined ) + { + let err = self.ErrNoReturn( competitor.competitorRoutine ); + throwenErr = self.__handleError( err, competitor ) + } + + /* keeping */ + + if( throwenErr ) + { + self.__take( throwenErr, undefined ); + } + else if( competitor.keeping ) + { + + if( _.consequenceIs( result ) ) + { + result.finally( self ); + } + else if( _.promiseLike( result ) ) + { + Self.From( result ).finally( self ); + } + else + { + self.__take( undefined, result ); + } + + } + + } + + if( self.AsyncCompetitorHanding || self.AsyncResourceAdding ) + return self.__handleResourceSoon( true ); + + counter += 1; + return true; + } + +} + +// + +/** + * Method created and appends competitor object, based on passed options into wConsequence competitors queue. + * + * @param {Object} o options map + * @param {Competitor|wConsequence} o.competitorRoutine callback + * @param {Object} [o.context] if defined, it uses as 'this' context in competitor function. + * @param {Array<*>|ArrayLike} [o.argument] values, that will be used as binding arguments in competitor. + * @param {boolean} [o.keeping=false] If sets to true, finally result of current competitor will be passed to the next competitor + in competitors queue. + * @param {boolean} [o.persistent=false] If sets to true, finally competitor will be work as queue listener ( it will be + * processed every value resolved by wConsequence). + * @param {boolean} [o.tapping=false] enabled some breakpoints in debug mode; + * @returns {wConsequence} + * @private + * @method _competitorAppend + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function _competitorAppend( o ) +{ + let self = this; + let competitorRoutine = o.competitorRoutine; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.consequenceIs( self ) ); + _.assert + ( + _.routineIs( competitorRoutine ) || _.consequenceIs( competitorRoutine ), + () => 'Expects routine or consequence, but got ' + _.entity.strType( competitorRoutine ) + ); + _.assert( o.kindOfResource >= 1 ); + _.assert( competitorRoutine !== self, 'Consquence cant depend on itself' ); + _.assert( o.stack >= 0, 'Competitor should have stack level greater or equal to zero' ); + _.routine.options_( _competitorAppend, o ); + + /* */ + + if( o.times !== 1 ) + { + let o2 = _.props.extend( null, o ); + o2.times = 1; + for( let t = 0 ; t < o.times ; t++ ) + self._competitorAppend( o2 ); + return; + } + + let stack = o.stack; + delete o.times; + delete o.stack; + + /* */ + + if( Config.debug ) + { + + if( !_.consequenceIs( competitorRoutine ) ) + { + if( o.kindOfResource === Self.KindOfResource.ErrorOnly ) + _.assert( competitorRoutine.length <= 1, 'ErrorOnly competitor should expect single argument' ); + else if( o.kindOfResource === Self.KindOfResource.ArgumentOnly ) + _.assert( competitorRoutine.length <= 1, 'ArgumentOnly competitor should expect single argument' ); + else if( o.kindOfResource === Self.KindOfResource.Both ) + _.assert( competitorRoutine.length === 0 || competitorRoutine.length === 2, 'Finally competitor should expect two arguments' ); + } + + if( _.consequenceIs( competitorRoutine ) ) + if( self.Diagnostics ) + { + self.assertNoDeadLockWith( competitorRoutine ); + competitorRoutine._dependsOf.push( self ); + } + + // if( self.Diagnostics && self.Stacking ) + // { + // competitorDescriptor.stack = _.introspector.stack([ stack, Infinity ]); + // } + + } + + /* procedure */ + + _.assert( _.routineIs( o.competitorRoutine ) ); + + if( o.procedure === null && !_.consequenceIs( o.competitorRoutine ) ) + { + if( self._procedure ) + { + o.procedure = self._procedure; + self._procedure = null + } + else + { + if( self._procedure !== false ) + o.procedure = new _.Procedure({ _stack : stack }); + } + } + else + { + _.assert + ( + self._procedure === null, + 'Procedure should not be allocated for consequence in role of callback' + ); + _.assert + ( + !_.consequenceIs( o.competitorRoutine ) || o.procedure === null, + 'Procedure should not be allocated for consequence in role of callback ( passed to _competitorAppend )' + ); + } + + if( o.procedure ) + { + if( !o.procedure.name() ) + o.procedure.name( o.competitorRoutine.name || '' ); + + _.assert( o.procedure._routine === null || o.procedure._routine === o.competitorRoutine ); + + if( !o.procedure._routine ) + o.procedure._routine = o.competitorRoutine; + if( !o.procedure._object ) + o.procedure._object = o; + o.procedure.begin(); + } + + /* */ + + // if( o.late === null ) + // o.late = _.consequenceIs( o.competitorRoutine ); + // if( o.late ) + // zzz : implement con1.then( con ) + + if( o.late ) + self._competitorsLate.unshift( o ); + else + self._competitorsEarly.push( o ); + + return o; +} + +_competitorAppend.defaults = +{ + competitorRoutine : null, + keeping : null, + tapping : null, + kindOfResource : null, + late : false, + instant : true, + // instant : false, // zzz : implement con1.then( con ) + times : 1, + stack : null, + procedure : null, +} + +// -- +// accounter +// -- + +function dependencyChainFor( competitor ) +{ + let self = this; + + _.assert( _.consequenceIs( competitor ) ); + + return look( self, competitor, [] ); + + /* */ + + function look( con1, con2, visited ) + { + + if( _.longHas( visited, con1 ) ) + return null; + visited.push( con1 ); + + _.assert( _.consequenceIs( con1 ) ); + + if( !con1._dependsOf ) + return null; + if( con1 === con2 ) + return [ con1 ]; + + for( let c = 0 ; c < con1._dependsOf.length ; c++ ) + { + let con1b = con1._dependsOf[ c ]; + if( _.consequenceIs( con1b ) ) + { + let chain = look( con1b, con2, visited ); + if( chain ) + { + chain.unshift( con1 ); + return chain; + } + } + } + + return null; + } + +} + +// + +function doesDependOf( competitor ) +{ + let self = this; + + _.assert( _.consequenceIs( competitor ) ); + + let chain = self.dependencyChainFor( competitor ); + + return !!chain; + + // if( !self._dependsOf ) + // return false; + // + // for( let c = 0 ; c < self._dependsOf.length ; c++ ) + // { + // let cor = self._dependsOf[ c ]; + // if( cor === competitor ) + // return true; + // if( _.consequenceIs( cor ) ) + // if( cor.doesDependOf( competitor ) ) + // return true; + // } + // + // return false; +} + +// + +function assertNoDeadLockWith( competitor ) +{ + let self = this; + + _.assert( _.consequenceIs( competitor ) ); + + let result = self.doesDependOf( competitor ); + + if( !result ) + return !result; + + return true; + // logger.log( self.deadLockReport( competitor ) ); + // + // let msg = 'Dead lock!\n'; + // + // _.assert( !result, msg ); + // + // return result; +} + +// + +function deadLockReport( competitor ) +{ + let self = this; + + _.assert( _.consequenceIs( competitor ) ); + + let chain = self.dependencyChainFor( competitor ); + + if( !chain ) + return ''; + + let log = ''; + + chain.forEach( ( con ) => + { + if( log ) + log += '\n'; + log += con.qualifiedName ; + }); + + return log; +} + +// + +function isEmpty() +{ + let self = this; + if( self.resourcesCount() ) + return false; + if( self.competitorsCount() ) + return false; + return true; +} + +// + +/** + * Clears all resources and corespondents of wConsequence. + * @method cancel + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function cancel() +{ + let self = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + + self.competitorsCancel(); + self.resourcesCancel(); + + return self; +} + +// -- +// competitors +// -- + +function competitorOwn( competitorRoutine ) +{ + let self = this; + + _.assert( _.routineIs( competitorRoutine ) ); + + for( let c = 0 ; c < self._competitorsEarly.length ; c++ ) + { + let competitor = self._competitorsEarly[ c ]; + if( competitor.competitorRoutine === competitorRoutine ) + return competitor; + } + + for( let c = 0 ; c < self._competitorsLate.length ; c++ ) + { + let competitor = self._competitorsLate[ c ]; + if( competitor.competitorRoutine === competitorRoutine ) + return competitor; + } + + return false; +} + +// + +function competitorHas( competitorRoutine ) +{ + let self = this; + + _.assert( _.routineIs( competitorRoutine ) ); + + for( let c = 0 ; c < self._competitorsEarly.length ; c++ ) + { + let competitor = self._competitorsEarly[ c ]; + if( competitor.competitorRoutine === competitorRoutine ) + return competitor; + if( _.consequenceIs( competitor ) ) + if( competitor.competitorHas( competitorRoutine ) ) + return competitor; + } + + for( let c = 0 ; c < self._competitorsLate.length ; c++ ) + { + let competitor = self._competitorsLate[ c ]; + if( competitor.competitorRoutine === competitorRoutine ) + return competitor; + if( _.consequenceIs( competitor ) ) + if( competitor.competitorHas( competitorRoutine ) ) + return competitor; + } + + return false; +} + +// + +function competitorsCount( competitorRoutine ) +{ + let self = this; + + if( arguments.length === 0 ) + { + return self._competitorsEarly.length + self._competitorsLate.length; + } + else if( arguments.length === 1 ) + { + _.assert( _.routineIs( competitorRoutine ), 'Expects competitor routine {-competitorRoutine-}' ); + + let competitorRoutinesEqualize = ( competitor, routine ) => competitor.competitorRoutine === routine; + let numberOfEarlyCompetitors = _.longCountElement( self._competitorsEarly, competitorRoutine, competitorRoutinesEqualize ); + let numberOfLateCompetitors = _.longCountElement( self._competitorsLate, competitorRoutine, competitorRoutinesEqualize ); + + return numberOfEarlyCompetitors + numberOfLateCompetitors; + } + else + { + _.assert( 0, 'Expects no arguments or single competitor routine {-competitorRoutine-}.' ); + } +} + +// + +/** + * The _corespondentMap object + * @typedef {Object} _corespondentMap + * @property {Function|wConsequence} competitor function or wConsequence instance, that accepts resolved resources from + * resources queue. + * @property {boolean} keeping determines if corespondent pass his result back into resources queue. + * @property {boolean} tapping determines if corespondent return accepted resource back into resources queue. + * @property {boolean} errorOnly turn on corespondent only if resource represent error; + * @property {boolean} argumentOnly turn on corespondent only if resource represent no error; + * @property {boolean} debug enables debugging. + * @property {string} id corespondent id. + * @class wConsequence + * @namespace Tools + * @module Tools/base/Consequence + */ + +/** + * Returns array of corespondents + * @example + * function corespondent1(err, val) + { + console.log( 'corespondent1 value: ' + val ); + }; + + function corespondent2(err, val) + { + console.log( 'corespondent2 value: ' + val ); + }; + + function corespondent3(err, val) + { + console.log( 'corespondent1 value: ' + val ); + }; + + let con = _.Consequence(); + + con.tap( corespondent1 ).finally( corespondent2 ).finallyGive( corespondent3 ); + + let corespondents = con.competitorsEarlyGet(); + + console.log( corespondents ); + + * @returns {_corespondentMap} + * @method competitorsEarlyGet + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function competitorsEarlyGet() +{ + let self = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + return self._competitorsEarly; +} + +// + +function competitorsLateGet() +{ + let self = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + return self._competitorsLate; +} + +// + +function competitorsGet() +{ + let self = this; + let r = []; + _.assert( arguments.length === 0, 'Expects no arguments' ); + if( self._competitorsEarly.length ) + _.arrayAppendArray( r, self._competitorsEarly ); + if( self._competitorsLate.length ) + _.arrayAppendArray( r, self._competitorsLate ); + return r; +} + +// + +/** + * If called without arguments, method competitorsCancel() removes all corespondents from wConsequence + * competitors queue. + * If as argument passed routine, method competitorsCancel() removes it from corespondents queue if exists. + * @example + function corespondent1(err, val) + { + console.log( 'corespondent1 value: ' + val ); + }; + + function corespondent2(err, val) + { + console.log( 'corespondent2 value: ' + val ); + }; + + function corespondent3(err, val) + { + console.log( 'corespondent1 value: ' + val ); + }; + + let con = _.Consequence(); + + con.finallyGive( corespondent1 ).finallyGive( corespondent2 ); + con.competitorsCancel(); + + con.finallyGive( corespondent3 ); + con.take( 'bar' ); + + // prints + // corespondent1 value: bar + * @param {Routine} [competitor] + * @method competitorsCancel + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function competitorsCancel( competitorRoutine ) +{ + let self = this; + let r = 0; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( arguments.length === 0 || _.routineIs( competitorRoutine ) ); + + if( arguments.length === 0 ) + { + + for( let c = self._competitorsEarly.length - 1 ; c >= 0 ; c-- ) + { + let competitorDescriptor = self._competitorsEarly[ c ]; + if( competitorDescriptor.procedure ) + competitorDescriptor.procedure.end(); + self._competitorsEarly.splice( c, 1 ); + r += 1; + } + + for( let c = self._competitorsLate.length - 1 ; c >= 0 ; c-- ) + { + let competitorDescriptor = self._competitorsLate[ c ]; + if( competitorDescriptor.procedure ) + competitorDescriptor.procedure.end(); + self._competitorsLate.splice( c, 1 ); + r += 1; + } + + } + else + { + + let found = _.longLeft( self._competitorsEarly, competitorRoutine, ( c ) => c.competitorRoutine, ( c ) => c ); + while( found.element ) + { + _.assert( found.element.competitorRoutine === competitorRoutine ); + if( found.element.procedure ) + found.element.procedure.end(); + self._competitorsEarly.splice( found.index, 1 ) + found = _.longLeft( self._competitorsEarly, competitorRoutine, ( c ) => c.competitorRoutine, ( c ) => c ); + r += 1; + } + + found = _.longLeft( self._competitorsLate, competitorRoutine, ( c ) => c.competitorRoutine, ( c ) => c ); + while( found.element ) + { + _.assert( found.element.competitorRoutine === competitorRoutine ); + if( found.element.procedure ) + found.element.procedure.end(); + self._competitorsLate.splice( found.index, 1 ) + found = _.longLeft( self._competitorsLate, competitorRoutine, ( c ) => c.competitorRoutine, ( c ) => c ); + r += 1; + } + + _.assert( r > 0, `Found no competitor ${competitorRoutine.name}` ); + + } + + return self; +} + +// + +function argumentsCount( arg ) +{ + let self = this; + // self._resources.filter( ( e ) => console.log( e ) ); + + if( arguments.length === 0 ) + return self._resources.filter( ( e ) => e.argument !== undefined ).length; + else if( arguments.length === 1 ) + return self._resources.filter( ( e ) => e.argument === arg ).length; + else + _.assert( 0, 'Expects no arguments or single argument {-arg-}.' ); +} + +// + +function errorsCount( err ) +{ + let self = this; + + if( arguments.length === 0 ) + return self._resources.filter( ( e ) => e.error !== undefined ).length; + else if( arguments.length === 1 ) + return self._resources.filter( ( e ) => e.error === err ).length; + else + _.assert( 0, 'Expects no arguments or single argument {-err-}.' ); +} + +// + +/** + * Returns number of resources in current resources queue. + * @example + * let con = _.Consequence(); + + let conLen = con.resourcesCount(); + console.log( conLen ); + + con.take( 'foo' ); + con.take( 'bar' ); + con.error( 'baz' ); + conLen = con.resourcesCount(); + console.log( conLen ); + + con.resourcesCancel(); + + conLen = con.resourcesCount(); + console.log( conLen ); + // prints: 0, 3, 0; + + * @returns {number} + * @method resourcesCount + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function resourcesCount( arg ) +{ + let self = this; + + if( arguments.length === 0 ) + return self._resources.length; + else if( arguments.length === 1 ) + return self._resources.filter( ( e ) => e.argument === arg || e.error === arg ).length; + else + _.assert( 0, 'Expects no arguments or single argument {-arg-}.' ); +} + +// +// + +/** + * The internal wConsequence view of resource. + * @typedef {Object} _resourceObject + * @property {*} error error value + * @property {*} argument resolved value + * @class wConsequence + * @namespace Tools + * @module Tools/base/Consequence + */ + +/** + * Returns resources queue. + * @example + * let con = _.Consequence(); + + con.take( 'foo' ); + con.take( 'bar '); + con.error( 'baz' ); + + + let resources = con.resourcesGet(); + + console.log( resources ); + + // prints + // [ { error: null, argument: 'foo' }, + // { error: null, argument: 'bar ' }, + // { error: 'baz', argument: undefined } ] + + * @returns {_resourceObject[]} + * @method resourcesGet + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function resourcesGet( index ) +{ + let self = this; + _.assert( arguments.length === 0 || arguments.length === 1 ) + _.assert( index === undefined || _.numberIs( index ) ); + if( index === undefined ) + return self._resources; + else + return self._resources[ index ]; + + // if( index !== undefined ) + // return self._resources[ index ]; + // else + // return self._resources; +} + +// + +function argumentsGet( index ) +{ + let self = this; + _.assert( arguments.length === 0 || arguments.length === 1 ) + _.assert( index === undefined || _.numberIs( index ) ); + if( index === undefined ) + return _.filter_( null, self._resources, ( r ) => r.argument ? r.argument : undefined ); + else + return self._resources[ index ].argument; + + // if( index !== undefined ) + // return self._resources[ index ].argument; + // else + // return _.filter_( null, self._resources, ( r ) => r.argument ? r.argument : undefined ); +} + +// + +function errorsGet( index ) +{ + let self = this; + _.assert( arguments.length === 0 || arguments.length === 1 ) + _.assert( index === undefined || _.numberIs( index ) ); + if( index === undefined ) + return _.filter_( null, self._resources, ( r ) => r.error ? r.error : undefined ); + else + return self._resources[ index ].error; + + // if( index !== undefined ) + // return self._resources[ index ].error; + // else + // return _.filter_( null, self._resources, ( r ) => r.error ? r.error : undefined ); +} + +// + +/** + * If called without arguments, method removes all resources from wConsequence + * competitors queue. + * If as argument passed value, method resourcesCancel() removes it from resources queue if resources queue contains it. + * @example + * let con = _.Consequence(); + + con.take( 'foo' ); + con.take( 'bar '); + con.error( 'baz' ); + + con.resourcesCancel(); + let resources = con.resourcesGet(); + + console.log( resources ); + // prints: [] + * @param {_resourceObject} arg resource object for removing. + * @throws {Error} If passed extra arguments. + * @method competitorsCancel + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function resourcesCancel( arg ) +{ + let self = this; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( arguments.length === 0 ) + { + self._resources.splice( 0, self._resources.length ); + } + else + { + throw _.err( 'not tested' ); + _.arrayRemoveElement( self._resources, arg ); + } + +} + +// -- +// procedure +// -- + +function procedure( arg ) +{ + let self = this; + + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + + if( self._procedure ) + return self._procedure; + + if( self._procedure === false && arg !== true ) + return self._procedure; + + if( _.routineIs( arg ) ) + arg = arg(); + + if( arguments.length === 2 ) + { + _.assert( arg === undefined || arg === null || _.strIs( arg ) || _.numberIs( arg ) ); + _.assert( _.numberIs( arguments[ 1 ] ) ); + self._procedure = _.Procedure({ _stack : _.Procedure.Stack( arg, arguments[ 1 ] ) }); + } + else if( _.procedureIs( arg ) ) + { + self._procedure = arg; + return arg; + } + else if( _.numberIs( arg ) ) + { + self._procedure = _.Procedure({ _stack : arg + 1 }); /* yyy */ + } + else if( _.strIs( arg ) ) + { + self._procedure = _.Procedure({ _name : arg, _stack : 1 }); /* yyy : should be 1 not 2 */ + } + else if( _.mapIs( arg ) ) + { + _.assert( arg._stack !== undefined ); + self._procedure = _.Procedure( arg ); + } + else if( arg === false ) + { + self._procedure = false; + } + else if( arg === true ) + { + self._procedure = null; + } + else if( arg === null ) + { + self._procedure = _.Procedure(); + } + else _.assert( 0 ); + + return self._procedure; +} + +// + +function procedureDetach() +{ + let self = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + let procedure = self._procedure; + + if( self._procedure ) + self._procedure = null; + + return procedure; +} + +// -- +// exporter +// -- + +function _exportString( o, it ) +{ + let self = this; + let result = ''; + + _.routine.assertOptions( _exportString, o ); + + if( o.verbosity >= 2 ) + { + result += self.qualifiedName; + result += '\n argument resources : ' + self.argumentsCount(); + result += '\n error resources : ' + self.errorsCount(); + result += '\n early competitors : ' + self.competitorsEarlyGet().length; + result += '\n late competitors : ' + self.competitorsLateGet().length; + } + else + { + if( o.verbosity >= 1 ) + result += self.qualifiedName; + result += ' ' + self.resourcesCount() + ' / ' + self.competitorsCount(); + } + + return result; +} + +_exportString.defaults = +{ + verbosity : 1, + it : null, +} + +// + +function exportString( o ) +{ + let self = this; + _.assert( arguments.length === 0 || arguments.length === 1 ); + o = _.routine.options( exportString, o || null ); + return self._exportString( o ); +} + +_.routineExtend( exportString, _exportString ); + +// + +function _callbacksInfoLog() +{ + let self = this; + + self._competitorsEarly.forEach( ( competitor ) => + { + console.log( competitor.competitorRoutine ); + }); + + self._competitorsLate.forEach( ( competitor ) => + { + console.log( competitor.competitorRoutine ); + }); + + return self.exportString(); +} + +// + +/** + * Serializes current wConsequence instance. + * @example + * function corespondent1(err, val) + { + console.log( 'corespondent1 value: ' + val ); + }; + + let con = _.Consequence(); + con.finallyGive( corespondent1 ); + + let conStr = con.toStr(); + + console.log( conStr ); + + con.take( 'foo' ); + con.take( 'bar' ); + con.error( 'baz' ); + + conStr = con.toStr(); + + console.log( conStr ); + // prints: + + // wConsequence( 0 ) + // resource : 0 + // competitors : 1 + // competitor names : corespondent1 + + // corespondent1 value: foo + + // wConsequence( 0 ) + // resource : 2 + // competitors : 0 + // competitor names : + + * @returns {string} + * @method toStr + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +function toStr( o ) +{ + let self = this; + return self.exportString( _.mapOnly_( null, o || Object.create( null ), self.exportString.defaults ) ); +} + +// + +function toString( o ) +{ + let self = this; + return self.exportString( _.mapOnly_( null, o || Object.create( null ), self.exportString.defaults ) ); +} + +// + +function _inspectCustom() +{ + let self = this; + return self.exportString(); +} + +// + +function _toPrimitive() +{ + let self = this; + return self.exportString(); +} + +// + +// /** +// * Can use as competitor. If `err` is not null, throws exception based on `err`. Returns `arg`. +// * @callback wConsequence._onDebug +// * @param {*} err Error object, or any other type, that represent or describe an error reason. If during resolving +// value no exception occurred, it will be set to null; +// * @param {*} arg resolved by wConsequence value; +// * @returns {*} +// * @module Tools/base/Consequence +// * @namespace Tools +// * @class wConsequence +// */ +// +// function _onDebug( err, arg ) +// { +// if( err ) +// throw _.err( err ); +// return arg; +// } + +// -- +// accessor +// -- + +function AsyncModeSet( mode ) +{ + let constr = this.Self; + _.assert( constr.AsyncCompetitorHanding !== undefined ); + _.assert( mode.length === 2 ); + _.assert( arguments.length === 1, 'Expects single argument' ); + constr.AsyncCompetitorHanding = !!mode[ 0 ]; + constr.AsyncResourceAdding = !!mode[ 1 ]; + return [ constr.AsyncCompetitorHanding, constr.AsyncResourceAdding ]; +} + +// + +function AsyncModeGet( mode ) +{ + let constr = this.Self; + _.assert( constr.AsyncCompetitorHanding !== undefined ); + return [ constr.AsyncCompetitorHanding, constr.AsyncResourceAdding ]; +} + +// + +function qualifiedNameGet() +{ + let result = this.shortName; + if( this.tag ) + result = result + '::' + this.tag; + else + result = result + '::'; + if( this.id !== undefined ) + result += `#${this.id}`; + return result; +} + +// + +function _arrayGetter_functor( name ) +{ + let symbol = Symbol.for( name ); + return function _get() + { + var self = this; + if( self[ symbol ] === undefined ) + self[ symbol ] = []; + return self[ symbol ]; + } +} + +// + +function _defGetter_functor( name, def ) +{ + let symbol = Symbol.for( name ); + return function _get() + { + var self = this; + if( self[ symbol ] === undefined ) + return def; + return self[ symbol ]; + } +} + +// + +function __call__() +{ + let self = this; + + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + if( arguments.length === 2 ) + self.take( arguments[ 0 ], arguments[ 1 ] ); + else + self.take( arguments[ 0 ] ); + +} + +// -- +// static +// -- + +/* aaa : remove second argument */ +// function From( src, timeLimit ) + +function From( src ) /* qqq : cover */ +{ + let con = src; + + // _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( arguments.length === 1 ); + // _.assert( timeLimit === undefined || _.numberIs( timeLimit ) ); + + if( _.promiseLike( src ) ) + { + con = new Self(); + let onFulfilled = ( arg ) => { arg === undefined ? con.take( null ) : con.take( arg ); } + let onRejected = ( err ) => { con.error( err ); } + src.then( onFulfilled, onRejected ); + } + + if( _.consequenceIs( con ) ) + { + // let con2 = con; + // if( timeLimit !== undefined ) + // con2 = new _.Consequence().take( null ).timeLimitError( timeLimit, con ); + // return con2; + return con; + } + + if( _.errIs( src ) ) + return new Self().error( src ); + return new Self().take( src ); +} + +// + +function FromCalling( src ) +{ + if( !_.consequenceIs( src ) && _.routineIs( src ) ) + src = src(); + src = this.From( src ); + return src; +} + +// + +/** + * If `consequence` if instance of wConsequence, method pass arg and error if defined to it's resource sequence. + * If `consequence` is routine, method pass arg as arguments to it and return result. + * @example + * function showResult(err, val) + { + if( err ) + { + console.log( 'handleGot1 error: ' + err ); + } + else + { + console.log( 'handleGot1 value: ' + val ); + } + }; + + let con = new _.Consequence(); + + con.finallyGive( showResult ); + + _.Consequence.take( con, 'hello world' ); + // prints: handleGot1 value: hello world + * @param {Function|wConsequence} consequence + * @param {*} arg argument value + * @param {*} [error] error value + * @returns {*} + * @static + * @method take + * @module Tools/base/Consequence + * @namespace wConsequence + */ + +function Take( consequence ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + let err, arg; + if( arguments.length === 2 ) + { + arg = arguments[ 1 ]; + } + else if( arguments.length === 3 ) + { + err = arguments[ 1 ]; + arg = arguments[ 2 ]; + } + + let args = [ arg ]; + + return _Take + ({ + consequence, + context : undefined, + error : err, + args, + }); + +} + +// + +/** + * If `o.consequence` is instance of wConsequence, method pass o.args and o.error if defined, to it's resource sequence. + * If `o.consequence` is routine, method pass o.args as arguments to it and return result. + * @param {Object} o parameters object. + * @param {Function|wConsequence} o.consequence wConsequence or routine. + * @param {Array} o.args values for wConsequence resources queue or arguments for routine. + * @param {*|Error} o.error error value. + * @returns {*} + * @private + * @throws {Error} if missed arguments. + * @throws {Error} if passed argument is not object. + * @throws {Error} if o.consequence has unexpected type. + * @method _Take + * @module Tools/base/Consequence + * @namespace Tools + * @class wConsequence + */ + +/* zzz : deprecate? */ +function _Take( o ) +{ + let context; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.object.isBasic( o ) ); + _.assert( _.argumentsArray.like( o.args ) && o.args.length <= 1, 'not tested' ); + _.routine.assertOptions( _Take, arguments ); + + /* */ + + if( _.argumentsArray.like( o.consequence ) ) + { + + for( let i = 0 ; i < o.consequence.length ; i++ ) + { + let optionsGive = _.props.extend( null, o ); + optionsGive.consequence = o.consequence[ i ]; + _Take( optionsGive ); + } + + } + else if( _.consequenceIs( o.consequence ) ) + { + + _.assert( _.argumentsArray.like( o.args ) && o.args.length <= 1 ); + + context = o.consequence; + + o.consequence.take( o.error, o.args[ 0 ] ); + + } + else if( _.routineIs( o.consequence ) ) + { + + _.assert( _.argumentsArray.like( o.args ) && o.args.length <= 1 ); + + return o.consequence.call( context, o.error, o.args[ 0 ] ); + + } + else throw _.err( 'Unknown type of consequence : ' + _.entity.strType( o.consequence ) ); + +} + +_Take.defaults = +{ + consequence : null, + context : null, + error : null, + args : null, +} + +// + +/** + * If `consequence` if instance of wConsequence, method error to it's resource sequence. + * If `consequence` is routine, method pass error as arguments to it and return result. + * @example + * function showResult(err, val) + * { + * if( err ) + * { + * console.log( 'handleGot1 error: ' + err ); + * } + * else + * { + * console.log( 'handleGot1 value: ' + val ); + * } + * }; + * + * let con = new _.Consequence(); + * + * con.finallyGive( showResult ); + * + * wConsequence.error( con, 'something wrong' ); + * // prints: handleGot1 error: something wrong + * @param {Function|wConsequence} consequence + * @param {*} error error value + * @returns {*} + * @static + * @method error + * @module Tools/base/Consequence + * @namespace wConsequence + */ + +function Error( consequence, error ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + return _Take + ({ + consequence, + context : undefined, + error, + args : [], + }); + +} + +// + +function Try( routine ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.routineIs( routine ) ); + + try + { + let r = routine(); + return Self.From( r ); + } + catch( err ) + { + let error = _.err( err ); + return new Self().error( error ); + } + +} + +// + +/** + * Can use as competitor. If `err` is not null, throws exception based on `err`. Returns `arg`. + * @callback PassThru + * @param {*} err Error object, or any other type, that represent or describe an error reason. If during resolving + value no exception occurred, it will be set to null; + * @param {*} arg resolved by wConsequence value; + * @returns {*} + * @class wConsequence + * @namespace Tools + * @module Tools/base/Consequence + */ + +function FinallyPass( err, arg ) +{ + _.assert( err !== undefined || arg !== undefined, 'Argument of take should be something, not undefined' ); + _.assert( err === undefined || arg === undefined, 'Cant take both error and argument, one should be undefined' ); + if( err ) + throw err; + return arg; +} + +// -- +// meta +// -- + +function _metaDefine( how, key, value ) +{ + let opts = + { + enumerable : false, + configurable : false, + } + + if( how === 'get' ) + { + opts.get = value; + Object.defineProperty( Self.prototype, key, opts ); + } + else if( how === 'field' ) + { + opts.value = value; + Object.defineProperty( Self.prototype, key, opts ); + } + else if( how === 'static' ) + { + opts.get = value; + Object.defineProperty( Self, key, opts ); + Object.defineProperty( Self.prototype, key, opts ); + } + else _.assert( 0 ); + +} + +// -- +// relations +// -- + +/** + * @typedef {Object} Fields + * @property {Array} [_competitorsEarly=[]] Queue of competitor that are penging for resource. + * @property {Array} [_resources=[]] Queue of messages that are penging for competitor. + * @property {wProcedure} [_procedure=null] Instance of wProcedure. + * @property {String} tag + * @property {Number} id Id of current instance + * @property {Array} [_dependsOf=[]] + * @property {Number} [capacity=0] Maximal number of resources. Unlimited by default. + * @class wConsequence + * @namespace Tools + * @module Tools/base/Consequence +*/ + + +let Composes = +{ + capacity : 1, + _resources : null, +} + +let ComposesDebug = +{ + tag : '', +} + +if( Config.debug ) +_.props.extend( Composes, ComposesDebug ); + +let Aggregates = +{ + _procedure : null, +} + +let Restricts = +{ + _competitorsEarly : null, + _competitorsLate : null, +} + +let RestrictsDebug = +{ + _dependsOf : null, + // id : 0, +} + +if( Config.debug ) +_.props.extend( Restricts, RestrictsDebug ); + +let Medials = +{ + tag : '', +} + +let Statics = +{ + + // Now : _.now, + // Async : _.now, + After : _.after, + From, /* qqq : cover please */ + FromCalling, + Take, + Error, + ErrNoReturn, + Try, /* qqq : cover please */ + + TimeLimit, + TimeLimitError, + + AndTake, + AndKeep, + AndImmediate, + And : AndKeep, + + OrTake, + OrKeep, + Or : OrKeep, + + FinallyPass, + // ThenPass, /* aaa : Dmytro : commented due to task. Maybe, need to remove */ + // CatchPass, /* aaa : Dmytro : commented due to task. Maybe, need to remove */ + + AsyncModeSet, + AsyncModeGet, + + // ToolsExtension, + KindOfResource, + + // _Extend, + + // + + // UncaughtTimeOut : 100, + Diagnostics : 1, + AsyncCompetitorHanding : 0, /* xxx : deprecate */ + AsyncResourceAdding : 0, /* xxx : deprecate */ + Counter : 0, + + shortName : 'Consequence', + +} + +let Forbids = +{ + every : 'every', + mutex : 'mutex', + mode : 'mode', + resourcesCounter : 'resourcesCounter', + _competitor : '_competitor', + _competitorPersistent : '_competitorPersistent', + dependsOf : 'dependsOf', +} + +let Accessors = +{ + competitorNext : 'competitorNext', + _competitorsEarly : { get : _arrayGetter_functor( '_competitorsEarly' ) }, + _competitorsLate : { get : _arrayGetter_functor( '_competitorsLate' ) }, + _resources : { get : _arrayGetter_functor( '_resources' ) }, + _procedure : { get : _defGetter_functor( '_procedure', null ) }, + capacity : { get : _defGetter_functor( 'capacity', 1 ) }, +} + +let DebugAccessors = +{ + tag : { get : _defGetter_functor( 'tag', null ) }, + _dependsOf : { get : _arrayGetter_functor( '_dependsOf' ) }, +} + +if( Config.debug ) +_.props.extend( Accessors, DebugAccessors ); + +// -- +// declare +// -- + +let Extension = +{ + + init, + is, + + // basic + + finallyGive, + give : finallyGive, + finallyKeep, + finally : finallyKeep, + + thenGive, + // ifNoErrorGot : thenGive, + // got : thenGive, + thenKeep, + then : thenKeep, + ifNoErrorThen : thenKeep, + + catchGive, + catchKeep, + catch : catchKeep, + ifErrorThen : catchGive, + + // to promise // qqq : cover please + + _promiseThen, + _promise, + finallyPromiseGive, + finallyPromiseKeep, + promise : finallyPromiseKeep, + thenPromiseGive, + thenPromiseKeep, + catchPromiseGive, + catchPromiseKeep, + + // deasync // qqq : cover please + + _deasync, + deasync, + + // advanced + + _first, + first, + + split : splitKeep, + splitKeep, + splitGive, + tap, + catchLog, + catchBrief, + syncMaybe, + sync, + + // experimental + + _competitorFinally, + wait, + participateGive, + participateKeep, + + // etc + + ErrNoReturn, + + // put + + _put, + put : thenPutGive, + putGive, + putKeep, + thenPutGive, + thenPutKeep, + + // time + + _delay, /* yyy : rename */ + finallyDelay, + thenDelay, + exceptDelay, + delay : finallyDelay, + + _timeLimit, + timeLimit, + timeLimitError, + timeLimitSplit, + timeLimitErrorSplit, + TimeLimit, /* qqq : cover please */ + TimeLimitError, /* qqq : cover please */ + + // and + + _and, + andTake, + andKeep, + andImmediate, + andKeepAccumulative, + + alsoTake, + alsoKeep, + alsoImmediate, + also : alsoKeep, + + AndTake, + AndKeep, + And : AndKeep, + AndImmediate, + + // or + + _or, + afterOrTaking, + afterOrKeeping, + // orKeepingSplit, /* yyy : depracate? */ + orTaking, + orKeeping, + or : orKeeping, + + OrTake, /* qqq : cover. separate test routine for procedure and its sourcePath checking */ + OrKeep, /* qqq : cover. separate test routine for procedure and its sourcePath checking */ + Or : OrKeep, + + // adapter + + tolerantCallback, + + // resource + + takeLater, + takeSoon, + takeAll, + take, + resolve : take, + error, + reject : error, + __take, + // __onTake, /* aaa : Dmytro : commented due to task. Maybe, need to remove */ + + // handling mechanism + + __handleError, + __handleResourceSoon, + __handleResourceNow, + _competitorAppend, + + // accounter + + doesDependOf, + dependencyChainFor, + assertNoDeadLockWith, + deadLockReport, + + isEmpty, + cancel, + + // competitor + + competitorOwn, /* aaa2 : cover */ /* Dmytro : covered, _competitorsLate restricted and not used */ + competitorHas, + competitorsCount, /* aaa2 : cover */ /* Dmytro : covered, _competitorsLate restricted and not used */ + competitorsEarlyGet, + competitorsLateGet, + competitorsGet, + competitorsCancel, + + // resource + + argumentsCount, /* aaa2 : cover */ /* Dmytro : covered */ + errorsCount, /* aaa2 : cover */ /* Dmytro : covered */ + resourcesCount, /* aaa2 : cover */ /* Dmytro : covered */ + resourcesGet, + argumentsGet, + errorsGet, + resourcesCancel, + + // procedure + + procedure, + procedureDetach, + + // exporter + + _exportString, + exportString, + _callbacksInfoLog, + toStr, + toString, + _inspectCustom, + _toPrimitive, + + // accessor + + AsyncModeSet, + AsyncModeGet, + qualifiedNameGet, + + __call__, + + // relations + + Composes, + Aggregates, + Restricts, + Medials, + Forbids, + Accessors, + +} + +// + +/* statics should be supplemental not extending */ + +let Supplement = +{ + Statics, +} + +// + +_.classDeclare +({ + cls : wConsequence, + parent : null, + extend : Extension, + supplement : Supplement, + usingOriginalPrototype : 1, +}); + +_.Copyable.mixin( wConsequence ); /* zzz : remove the mixin, maybe */ + +_metaDefine( 'field', Symbol.toPrimitive, _toPrimitive ); +_metaDefine( 'field', Symbol.for( 'nodejs.util.inspect.custom' ), _inspectCustom ); + +// + +_.assert( _.routineIs( wConsequence.prototype.FinallyPass ) ); +_.assert( _.routineIs( wConsequence.FinallyPass ) ); +_.assert( _.object.isBasic( wConsequence.prototype.KindOfResource ) ); +_.assert( _.object.isBasic( wConsequence.KindOfResource ) ); +_.assert( _.strDefined( wConsequence.name ) ); +_.assert( _.strDefined( wConsequence.shortName ) ); +_.assert( _.routineIs( wConsequence.prototype.take ) ); + +_.assert( _.routineIs( wConsequenceProxy.prototype.FinallyPass ) ); +_.assert( _.routineIs( wConsequenceProxy.FinallyPass ) ); +_.assert( _.object.isBasic( wConsequenceProxy.prototype.KindOfResource ) ); +_.assert( _.object.isBasic( wConsequenceProxy.KindOfResource ) ); +_.assert( _.strDefined( wConsequenceProxy.name ) ); +_.assert( _.strDefined( wConsequenceProxy.shortName ) ); +_.assert( _.routineIs( wConsequenceProxy.prototype.take ) ); + +_.assert( wConsequenceProxy.shortName === 'Consequence' ); + +_.assert( !!Self.FieldsOfRelationsGroupsGet ); +_.assert( !!Self.prototype.FieldsOfRelationsGroupsGet ); +_.assert( !!Self.FieldsOfRelationsGroups ); +_.assert( !!Self.prototype.FieldsOfRelationsGroups ); +_.assert( _.props.keys( Self.FieldsOfRelationsGroups ).length > 0 ); + +_.assert( _.mapIs( Self.KindOfResource ) ); +_.assert( _.mapIs( Self.prototype.KindOfResource ) ); +_.assert( Self.AsyncCompetitorHanding === 0 ); +_.assert( Self.prototype.AsyncCompetitorHanding === 0 ); + +_global_[ Self.name ] = _[ Self.shortName ] = Self; +if( !_global_.__GLOBAL_PRIVATE_CONSEQUENCE__ ) +_realGlobal_[ Self.name ] = Self; + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wConsequence/proto/wtools/abase/l9/consequence/Consequence.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wConsequence/proto/wtools/abase/l9/consequence' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Consequence_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Consequence_s */ })(); + +/* */ /* begin of file Namespace_s */ ( function Namespace_s() { function Namespace_s_naked() { ( function _Namespace_s_() +{ + +'use strict'; + +/** + * Advanced synchronization mechanism. Asynchronous routines may use Consequence to wrap postponed result, what allows classify callback for such routines as output, not input, what improves analyzability of a program. Consequence may be used to make a queue for mutually exclusive access to a resource. Algorithmically speaking Consequence is 2 queues ( FIFO ) and a customizable arbitrating algorithm. The first queue contains available resources, the second queue includes competitors for this resources. At any specific moment, one or another queue may be empty or full. Arbitrating algorithm makes resource available for a competitor as soon as possible. There are 2 kinds of resource: regular and erroneous. Unlike Promise, Consequence is much more customizable and can solve engineering problem which Promise cant. But have in mind with great power great responsibility comes. Consequence can coexist and interact with a Promise, getting fulfillment/rejection of a Promise or fulfilling it. Use Consequence to get more flexibility and improve readability of asynchronous aspect of your application. + @module Tools/base/Consequence +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + _.include( 'wProto' ); + _.include( 'wCopyable' ); + _.include( 'wProcedure' ); +} + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( !_.Consequence, 'Consequence included several times' ); + +// -- +// time +// -- + +/** + * The routine sleep() suspends program execution on time delay {-delay-}. + * + * @example + * let result = []; + * let periodic = _.time.periodic( 100, () => result.length < 10 ? result.push( 1 ) : undefined ); + * let before = _.time.now(); + * _.time.sleep( 500 ); + * console.log( result.length <= 1 ); + * // log : true + * let after = _.time.now(); + * let delta = after - before; + * console.log( delta <= 550 ); + * // log : true + * + * @param { Number } delay - The delay to suspend program. + * @returns { Undefined } - Returns not a value, suspends program. + * @function sleep + * @throws { Error } If arguments.length is less then 1 or great then 2. + * @throws { Error } If {-delay-} is not a Number. + * @throws { Error } If {-delay-} is less then zero. + * @throws { Error } If {-delay-} has not finite value. + * @namespace wTools.time + * @extends Tools + */ + +function sleep( delay ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.intIs( delay ) && delay >= 0, 'Specify valid value {-delay-}.' ); + let con = new _.Consequence().take( null ); + con.delay( delay ).deasync(); +} + +// + +/** + * Routine creates timer that executes provided routine( onReady ) after some amout of time( delay ). + * Returns wConsequence instance. {@link module:Tools/base/Consequence.wConsequence wConsequence} + * + * If ( onReady ) is not provided, time.out returns consequence that gives empty message after ( delay ). + * If ( onReady ) is a routine, time.out returns consequence that gives message with value returned or error throwed by ( onReady ). + * If ( onReady ) is a consequence or routine that returns it, time.out returns consequence and waits until consequence from ( onReady ) resolves the message, then + * time.out gives that resolved message throught own consequence. + * If ( delay ) <= 0 time.out performs all operations on nextTick in node + * @see {@link https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/#the-node-js-event-loop-timers-and-process-nexttick } + * or after 1 ms delay in browser. + * Returned consequence controls the timer. Timer can be easly stopped by giving an error from than consequence( see examples below ). + * Important - Error that stops timer is returned back as regular message inside consequence returned by time.out. + * Also time.out can run routine with different context and arguments( see example below ). + * + * @param {Number} delay - Delay in ms before ( onReady ) is fired. + * @param {Function|wConsequence} onReady - Routine that will be executed with delay. + * + * @example + * // simplest, just timer + * let t = _.time.out( 1000 ); + * t.give( () => console.log( 'Message with 1000ms delay' ) ) + * console.log( 'Normal message' ) + * + * @example + * // run routine with delay + * let routine = () => console.log( 'Message with 1000ms delay' ); + * let t = _.time.out( 1000, routine ); + * t.give( () => console.log( 'Routine finished work' ) ); + * console.log( 'Normal message' ) + * + * @example + * // routine returns consequence + * let routine = () => new _.Consequence().take( 'msg' ); + * let t = _.time.out( 1000, routine ); + * t.give( ( err, got ) => console.log( 'Message from routine : ', got ) ); + * console.log( 'Normal message' ) + * + * @example + * // time.out waits for long time routine + * let routine = () => _.time.out( 1500, () => 'work done' ) ; + * let t = _.time.out( 1000, routine ); + * t.give( ( err, got ) => console.log( 'Message from routine : ', got ) ); + * console.log( 'Normal message' ) + * + * @example + * // how to stop timer + * let routine = () => console.log( 'This message never appears' ); + * let t = _.time.out( 5000, routine ); + * t.error( 'stop' ); + * t.give( ( err, got ) => console.log( 'Error returned as regular message : ', got ) ); + * console.log( 'Normal message' ) + * + * @example + * // running routine with different context and arguments + * function routine( y ) + * { + * let self = this; + * return self.x * y; + * } + * let context = { x : 5 }; + * let arguments = [ 6 ]; + * let t = _.time.out( 100, context, routine, arguments ); + * t.give( ( err, got ) => console.log( 'Result of routine execution : ', got ) ); + * + * @returns {wConsequence} Returns wConsequence instance that resolves message when work is done. + * @throws {Error} If ( delay ) is not a Number. + * @throws {Error} If ( onEnd ) is not a routine or wConsequence instance. + * @function time.out + * @namespace Tools + */ + +function out_head( routine, args ) +{ + let o, procedure; + + _.assert( arguments.length === 2 ); + _.assert( !!args ); + + if( _.procedureIs( args[ 1 ] ) ) + { + procedure = args[ 1 ]; + args = _.longBut_( args, [ 1, 1 ] ); + // args = _.longBut( args, [ 1, 2 ] ); + } + + if( _.mapIs( args[ 0 ] ) ) + { + o = args[ 0 ]; + } + else + { + if( args.length === 1 || args.length === 2 ) + { + let delay = args[ 0 ]; + let onEnd = args[ 1 ]; + + if( onEnd !== undefined && !_.routineIs( onEnd ) && !_.consequenceIs( onEnd ) ) + { + _.assert( args.length === 2, 'Expects two arguments if second one is not callable' ); + _.assert( !routine.defaults.error, 'Time out throwing error should have callback to attend it' ); /* qqq : cover */ + let returnOnEnd = args[ 1 ]; + onEnd = function onEnd() + { + return returnOnEnd; + } + } + + if( onEnd === undefined ) + o = { delay } + else + o = { delay, onEnd } + } + else + { + _.assert( args.length <= 4 ); + + let delay = args[ 0 ]; + let onEnd = _.routineJoin.call( _, args[ 1 ], args[ 2 ], args[ 3 ] ); /* qqq : cover by separate test routine */ + + o = { delay, onEnd } + } + } + + + // if( !_.mapIs( args[ 0 ] ) || args.length === 2 ) + // if( !_.mapIs( args[ 0 ] ) ) + // { + // if( args.length === 1 || args.length === 2 ) + // { + // let delay = args[ 0 ]; + // let onEnd = args[ 1 ]; + // + // if( onEnd !== undefined && !_.routineIs( onEnd ) && !_.consequenceIs( onEnd ) ) + // { + // _.assert( args.length === 2, 'Expects two arguments if second one is not callable' ); + // _.assert( !routine.defaults.error, 'Time out throwing error should have callback to attend it' ); /* qqq : cover */ + // let returnOnEnd = args[ 1 ]; + // onEnd = function onEnd() + // { + // return returnOnEnd; + // } + // } + // // else if( _.routineIs( onEnd ) && !_.consequenceIs( onEnd ) ) + // // { + // // let _onEnd = onEnd; + // // onEnd = function timeOutEnd( timer ) + // // { + // // let result = _onEnd.apply( this, arguments ); + // // return result === undefined ? timer : result; + // // } + // // } + // + // o = { delay, onEnd } + // } + // else + // { + // + // _.assert( args.length <= 4 ); + // + // // if( args[ 1 ] !== undefined && args[ 2 ] === undefined && args[ 3 ] === undefined ) + // // _.assert( _.routineIs( onEnd ) || _.consequenceIs( onEnd ) ); + // // else if( args[ 2 ] !== undefined || args[ 3 ] !== undefined ) + // // _.assert( _.routineIs( args[ 2 ] ) ); + // // + // // if( args[ 2 ] !== undefined || args[ 3 ] !== undefined ) + // + // let delay = args[ 0 ]; + // let onEnd = _.routineJoin.call( _, args[ 1 ], args[ 2 ], args[ 3 ] ); /* qqq : cover by separate test routine */ + // + // o = { delay, onEnd } + // } + // } + // else + // { + // o = args[ 0 ]; + // } + + _.assert( _.mapIs( o ) ); + + if( procedure ) + o.procedure = procedure; + + _.routine.options_( routine, o ); + _.assert( _.numberIs( o.delay ) ); + _.assert( o.onEnd === null || _.routineIs( o.onEnd ) ); + + return o; +} + +// + +function out_body( o ) +{ + let con = new _.Consequence(); + let timer = null; + + _.routine.assertOptions( out_body, arguments ); + + /* */ + + if( o.procedure === null ) + o.procedure = _.Procedure( 3 ).name( 'time.out' ); /* delta : 3 to not include info about `routine.unite` in the stack */ + _.assert( _.procedureIs( o.procedure ) ); + + if( Config.debug ) + if( con.tag === null ) + con.tag = 'time.out'; + con.procedure( o.procedure.clone() ); + con.finally( timeEnd2 ); + + /* */ + + timer = _.time.begin( o.delay, o.procedure, timeEnd1 ); + + return con; + + /* */ + + function timeEnd2( err, arg ) + { + if( _.time.timerInEndBegun( timer ) ) + { + if( _.consequenceIs( o.onEnd ) ) + { + arg = o.onEnd; + err = undefined; + } + else + { + if( o.onEnd ) + arg = o.onEnd.call( timer, err ? err : arg ); + if( arg === undefined ) + arg = timer; + else + err = undefined; + } + } + else + { + _.time.cancel( timer ); + if( Config.debug ) + if( !_.symbolIs( err ) ) + { + let err2 = _.err + ( + 'Only symbol in error channel of conseqeucne should be used to cancel timer.' + + '\nFor example: "consequence.error( _.dont );"' + + ( err === undefined ? `` : `\nError of type ${_.entity.strType( err )} was recieved instead` ) + + ( err === undefined ? `\nArgument of type ${_.entity.strType( arg )} was recieved instead` : `` ) + ); + _.error._handleUncaught2({ err : err2 }); + throw err2; + } + } + + // if( !_.time.timerInEndBegun( timer ) ) + // { + // _.time.cancel( timer ); + // if( Config.debug ) + // if( !_.symbolIs( err ) ) + // { + // let err2 = _.err + // ( + // 'Only symbol in error channel of conseqeucne should be used to cancel timer.' + // + '\nFor example: "consequence.error( _.dont );"' + // + ( err !== undefined ? `\nError of type ${_.entity.strType( err )} was recieved instead` : `` ) + // + ( err !== undefined ? `` : `\nArgument of type ${_.entity.strType( arg )} was recieved instead` ) + // ); + // _.error._handleUncaught2({ err : err2 }); + // throw err2; + // } + // } + // else + // { + // if( _.consequenceIs( o.onEnd ) ) + // { + // arg = o.onEnd; + // err = undefined; + // } + // else + // { + // if( o.onEnd ) + // arg = o.onEnd.call( timer, err ? err : arg ); + // if( arg === undefined ) + // arg = timer; + // else + // err = undefined; + // } + // } + + if( err ) + throw err; + return arg; + } + + /* */ + + function timeEnd1() + { + if( !con.competitorOwn( timeEnd2 ) ) + return; + if( o.error ) + con.error( errMake() ); + else + con.take( timer ); + } + + /* */ + + function errMake() + { + let err = _.time._errTimeOut + ({ + message : 'Time out!', + reason : 'time out', + consequnce : con, + procedure : o.procedure, + }); + return err; + } + + /* */ + +} + +out_body.defaults = +{ + delay : null, + onEnd : null, + procedure : null, + error : 0, +} + +let out = _.routine.uniteCloning_replaceByUnite( out_head, out_body ); +out.defaults.error = 0; + +// + +/** + * Routine works moslty same like {@link wTools.time.out} but has own small features: + * Is used to set execution time limit for async routines that can run forever or run too long. + * wConsequence instance returned by time.outError always give an error: + * - Own 'time.out' error message if ( onReady ) was not provided or it execution dont give any error. + * - Error throwed or returned in consequence by ( onRead ) routine. + * + * @param {Number} delay - Delay in ms before ( onReady ) is fired. + * @param {Function|wConsequence} onReady - Routine that will be executed with delay. + * + * @example + * // time.out error after delay + * let t = _.time.outError( 1000 ); + * t.give( ( err, got ) => { throw err; } ) + * + * @example + * // using time.outError with long time routine + * let time = 5000; + * let time.out = time / 2; + * function routine() + * { + * return _.time.out( time ); + * } + * // orKeepingSplit waits until one of provided consequences will resolve the message. + * // In our example single time.outError consequence was added, so orKeepingSplit adds own context consequence to the queue. + * // Consequence returned by 'routine' resolves message in 5000 ms, but time.outError will do the same in 2500 ms and 'time.out'. + * routine() + * .orKeepingSplit( _.time.outError( time.out ) ) + * .give( function( err, got ) + * { + * if( err ) + * throw err; + * console.log( got ); + * }) + * + * @returns {wConsequence} Returns wConsequence instance that resolves error message when work is done. + * @throws {Error} If ( delay ) is not a Number. + * @throws {Error} If ( onReady ) is not a routine or wConsequence instance. + * @function time.outError + * @namespace Tools + */ + +let outError = _.routine.uniteCloning_replaceByUnite( out_head, out_body ); +outError.defaults.error = 1; + +// /* zzz : remove the body, use out_body */ +// function outError_body( o ) +// { +// _.assert( _.routineIs( _.Consequence ) ); +// _.routine.assertOptions( outError_body, arguments ); +// +// if( _.numberIs( o.procedure ) ) +// o.procedure += 1; +// else if( o.procedure === null ) +// o.procedure = 2; +// +// if( !o.procedure || _.numberIs( o.procedure ) ) +// o.procedure = _.procedure.from( o.procedure ).nameElse( 'time.outError' ); +// +// let con = _.time.out.body.call( _, o ); +// if( Config.debug && con.tag === '' ) +// con.tag = 'TimeOutError'; +// +// _.assert( con._procedure === null ); +// con.procedure( o.procedure.clone() ); +// con.finally( outError ); +// _.assert( con._procedure === null ); +// +// return con; +// +// function outError( err, arg ) +// { +// if( err ) +// throw err; +// if( arg === _.dont ) +// return arg; +// +// err = _.time._errTimeOut +// ({ +// message : 'Time out!', +// reason : 'time out', +// consequnce : con, +// procedure : o.procedure, +// }); +// +// throw err; +// } +// +// } +// +// outError_body.defaults = Object.create( out_body.defaults ); +// +// let outError = _.routine.uniteCloning_replaceByUnite( out_head, outError_body ); + +// + +function _errTimeOut( o ) +{ + if( _.strIs( o ) ) + o = { message : o } + o = _.routine.options_( _errTimeOut, o ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + + o.message = o.message || 'Time out!'; + o.reason = o.reason || 'time out'; + + let err = _._err + ({ + args : [ o.message ], + throws : o.procedure ? [ o.procedure._sourcePath ] : [], + asyncCallsStack : o.procedure ? [ o.procedure.stack() ] : [], + reason : o.reason, + throwCallsStack : o.procedure ? o.procedure._stack : null, + }); + + if( o.consequnce ) + { + let properties = + { + enumerable : false, + configurable : false, + writable : false, + value : o.consequnce, + }; + Object.defineProperty( err, 'consequnce', properties ); + } + + return err; +} + +_errTimeOut.defaults = +{ + message : null, + reason : null, + consequnce : null, + procedure : null, +} + +// -- +// experimental +// -- + +function take() +{ + if( arguments.length ) + return new _.Consequence().take( ... arguments ); + else + return new _.Consequence().take( null ); + + // if( !arguments.length ) + // return new _.Consequence().take( null ); + // else + // return new _.Consequence().take( ... arguments ); +} + +// + +// function Now() +// { +// _.assert( arguments.length === 0, 'Expects no arguments' ); +// return new _.Consequence().take( null ); +// } + +// + +function After( resource ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( arguments.length === 0 || resource !== undefined ); + + if( resource === undefined ) + return new _.Consequence().take( null ); + else + return _.Consequence.From( resource ); + + // if( resource !== undefined ) + // return _.Consequence.From( resource ); + // else + // return new _.Consequence().take( null ); +} + +// // +// +// function Before( consequence ) +// { +// _.assert( arguments.length === 1 ); +// _.assert( arguments.length === 0 || consequence !== undefined ); +// _.assert( 0, 'not tested' ); +// +// let result; +// if( _.consequenceLike( consequence ) ) +// { +// consequence = _.Consequence.From( consequence ); +// } +// +// let result = _.Consequence(); +// result.lateFinally( consequence ); +// +// return result; +// } + +// + +function stagesRun( stages, o ) +{ + let logger = _global.logger || _global.console; + + o = o || Object.create( null ); + + _.routine.options( stagesRun, o ); + + o.stages = stages; + o.stack = _.introspector.stackRelative( o.stack, 1 ); + + Object.preventExtensions( o ); + + /* validation */ + + _.assert( _.object.isBasic( stages ) || _.longIs( stages ), 'Expects array or object ( stages ), but got', _.entity.strType( stages ) ); + + for( let s in stages ) + { + + let routine = stages[ s ]; + + if( o.onRoutine ) + routine = o.onRoutine( routine ); + + // _.assert( routine || routine === null,'stagesRun :','#'+s,'stage is not defined' ); + _.assert( _.routineIs( routine ) || routine === null, () => 'stage' + '#'+s + ' does not have routine to execute' ); + + } + + /* let */ + + let ready = _.time.out( 1 ); + let keys = Object.keys( stages ); + let s = 0; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + + /* begin */ + + if( o.onBegin ) + { + ready.procedure({ _stack : o.stack }); + ready.finally( o.onBegin ); + _.assert( ready._procedure === null ); + } + + handleStage(); + + return ready; + + /* end */ + + function handleEnd() + { + + ready.procedure({ _stack : o.stack }); + ready.finally( function( err, data ) + { + if( err ) + { + throw _.errLogOnce( err ); + } + else + { + return data; + } + }); + _.assert( ready._procedure === null ); + + if( o.onEnd ) + { + ready.procedure({ _stack : o.stack }); + ready.finally( o.onEnd ); + _.assert( ready._procedure === null ); + } + + } + + /* staging */ + + function handleStage() + { + + let stage = stages[ keys[ s ] ]; + let iteration = Object.create( null ); + + iteration.index = s; + iteration.key = keys[ s ]; + + s += 1; + + if( stage === null ) + return handleStage(); + + if( !stage ) + return handleEnd(); + + /* arguments */ + + iteration.stage = stage; + if( o.onRoutine ) + iteration.routine = o.onRoutine( stage ); + else + iteration.routine = stage; + iteration.routine = _.routineJoin( o.context, iteration.routine, o.args ); + + function routineCall() + { + let ret = iteration.routine(); + return ret; + } + + /* exec */ + + if( o.onEachRoutine ) + { + ready.procedure({ _stack : o.stack }); + ready.ifNoErrorThen( _.routineSeal( o.context, o.onEachRoutine, [ iteration.stage, iteration, o ] ) ); + _.assert( ready._procedure === null ); + } + + if( !o.manual ) + { + ready.procedure({ _stack : o.stack }); + ready.ifNoErrorThen( routineCall ); + _.assert( ready._procedure === null ); + } + + ready.procedure({ _stack : o.stack }); + ready.delay( o.delay ); + _.assert( ready._procedure === null ); + + handleStage(); + + } + +} + +stagesRun.defaults = /* qqq : make head and body. refactor maybe */ +{ + delay : 1, + stack : null, + + args : undefined, + context : undefined, + manual : false, + + onEachRoutine : null, + onBegin : null, + onEnd : null, + onRoutine : null, +} + +// + +function sessionsRun_head( routine, args ) +{ + let o; + + if( _.longIs( args[ 0 ] ) ) + o = { sessions : args[ 0 ] }; + else + o = args[ 0 ]; + + o = _.routine.options_( routine, o ); + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1, 'Expects single argument' ); + _.assert( _.longIs( o.sessions ) ); + + return o; +} + +/* qqq for junior : cover please */ +function sessionsRun_body( o ) +{ + let firstReady = new _.Consequence().take( null ); + let prevReady = firstReady; + let readies = []; + let begins = []; + let ends = []; + let readyRoutine = null; + + if( !o.ready ) + { + o.ready = _.take( null ); + } + else if( !_.consequenceIs( o.ready ) ) + { + readyRoutine = o.ready; + o.ready = _.take( null ); + } + + if( o.sessions.length ) + o.ready.thenGive( () => + { + + o.sessions.forEach( ( session, i ) => + { + + if( o.concurrent ) + { + prevReady.then( session.ready ); + } + else + { + prevReady.finally( session.ready ); + prevReady = session.ready; + } + + try + { + o.onRun( session ); + } + catch( err ) + { + o.error = o.error || err; + session.ready.error( err ); + } + + _.assert( _.consequenceIs( session[ o.conBeginName ] ) ); + _.assert( _.consequenceIs( session[ o.conEndName ] ) ); + _.assert( _.consequenceIs( session[ o.readyName ] ) ); + + begins.push( session[ o.conBeginName ] ); + ends.push( session[ o.conEndName ] ); + readies.push( session[ o.readyName ] ); + + if( !o.concurrent ) + session.ready.catch( ( err ) => + { + o.error = o.error || err; + if( o.onError ) + o.onError( err ); + else + throw err; + }); + + }); + + let onBegin; + if( o.concurrent ) + onBegin = _.Consequence.AndImmediate( ... begins ); + else + onBegin = _.Consequence.OrKeep( ... begins ); + let onEnd = _.Consequence.AndImmediate( ... ends ); + let ready = _.Consequence.AndImmediate( ... readies ); + + o.onBegin = direct( onBegin, o.onBegin ); + o.onEnd = direct( onEnd, o.onEnd ); + + ready.finally( o.ready ); + + }); + + if( readyRoutine ) + o.ready.finally( readyRoutine ); + + return o; + + function direct( icon, ocon ) + { + if( _.consequenceIs( ocon ) ) + icon.finally( ocon ); + else if( ocon ) + icon.tap( ( err, arg ) => + { + ocon( err, err ? undefined : o ); + }); + else + ocon = icon; + return ocon; + } + +} + +sessionsRun_body.defaults = +{ + concurrent : 1, + sessions : null, + error : null, + conBeginName : 'conBegin', + conEndName : 'conEnd', + readyName : 'ready', + onRun : null, + onBegin : null, + onEnd : null, + onError : null, + ready : null, +} + +let sessionsRun = _.routine.uniteCloning_replaceByUnite( sessionsRun_head, sessionsRun_body ); /* qqq for junior : cover */ + +// + +function retry( o ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument.' ); + + if( o.defaults ) + _.mapSupplementNulls( o, o.defaults ); + _.routine.options( retry, o ); + _.assert( _.routine.is( o.routine ), 'Expects routine {-o.routine-} to run.' ); + _.assert( o.attemptLimit > 0 ); + _.assert( o.attemptDelay >= 0 ); + const loggerIs = _.logger.is( o.logger ); + _.assert( loggerIs || o.logger >= 0 ); + + let log = () => {}; + let attemptLogArray = _.array.make( o.attemptLimit ); + if( loggerIs ) + log = log_functor( o.logger ); + else if( o.logger >= 4 ) + log = log_functor( console ); + + + o.onError = o.onError || onError; + let attempt = 1; + let attemptDelay = o.attemptDelay; + const con = new _.Consequence(); + return _run( o ) + .finally( ( err, arg ) => + { + if( err ) + throw _.err( err ); + return arg; + }); + + /* */ + + function _run( o ) + { + const attemptN = attempt - 1; + if( attempt > o.attemptLimit ) + return con.error( _.err( o.err, `\nAttempts exhausted, made ${ attemptN } attempts : \n`, attemptLogArray.join( '\n' ) ) ); + + const msg = attemptLogArray[ attemptN ] = `Attempt #${ attempt } started at : ${ new Date().toTimeString() }`; + log( msg ); + + _.take( null ).then( () => _.Consequence.Try( o.routine ) ) + .finally( ( err, arg ) => + { + if( err ) + { + o.err = err; + let shouldRetry = false; + try + { + if( o.onError( err ) !== false ) + shouldRetry = true; + } + catch( _err ) + { + return con.error( _.err( err, '\nThe error thown in callback {-onError-}' ) ); + } + + if( shouldRetry ) + return _retry( o ); + return con.error( _.err( err ) ); + } + if( o.onSuccess && !o.onSuccess( arg ) ) + return _retry( o ); + return con.take( arg ); + }); + + return con; + } + + /* */ + + function _retry( o ) + { + if( attempt >= 2 ) + attemptDelay = attemptDelay * o.attemptDelayMultiplier; + attempt += 1; + return _.time.out( attemptDelay, () => _run( o ) ); + } + + /* */ + + function onError( err ) + { + _.error.attend( err ); + return true; + } + + /* */ + + function log_functor( _logger ) + { + return function log( src ) + { + _logger.log( src ); + } + } +} + +retry.defaults = /* aaa : cover */ /* Dmytro : covered */ +{ + routine : null, + onError : null, + onSuccess : null, + attemptLimit : 3, + attemptDelay : 100, + attemptDelayMultiplier : 1, + defaults : null, + logger : 2, +}; + +// -- +// meta +// -- + +// function _Extend( dstGlobal, srcGlobal ) +// { +// _.assert( _.routineIs( srcGlobal.wConsequence.After ) ); +// _.assert( _.mapIs( srcGlobal.wConsequence.Tools ) ); +// _.props.extend( dstGlobal.wTools, srcGlobal.wConsequence.Tools ); +// const Self = srcGlobal.wConsequence; +// dstGlobal.wTools[ Self.shortName ] = Self; +// if( typeof module !== 'undefined' ) +// module[ 'exports' ] = Self; +// return; +// } + +// + +/** + * The routine ready() executes callback {-onReady-} when web-page is loaded. + * If routine is executed in browser environment, then callback can be executed after + * loading page with specified delay {-timeOut-}. + * If routine is executed in NodeJS environment, then the callback is executed after + * specified delay {-timeOut-}. + * + * @example + * let result = []; + * let ready = _.process.ready( () => result.push( 'ready' ) ); + * // when a page is loaded routine will push 'ready' in array `result` immediatelly + * _.consequenceIs( ready ); + * // returns : true + * + * @example + * let result = []; + * let ready = _.process.ready( 500, () => result.push( 'ready' ) ); + * // when a page is loaded routine will push 'ready' in array `result` after time out + * _.consequenceIs( ready ); + * // returns : true + * + * First parameter set : + * @param { Number } timeOut - The time delay. + * @param { Function } onReady - Callback to execute. + * Second parameter set : + * @param { Map|Aux } o - Options map. + * @param { Number } o.timeOut - The time delay. + * @param { Procedure } o.procedure - The procedure to associate with new Consequence. + * @param { Function } o.onReady - Callback to execute. + * @returns { Consequence } - Returns Consequence with result of execution. + * @function ready + * @throws { Error } If arguments.length is greater than 2. + * @throws { Error } If single argument call is provided without callback {-onReady-} and options + * map {-o-} has no option {-o.onReady-}. + * @throws { Error } If {-timeOut-} has defined non integer value or not finite value. + * @throws { Error } If {-o.procedure-} is provided and it is not a Procedure. + * @namespace wTools.time + * @extends Tools + */ + +function ready_body( o ) +{ + + if( !o.procedure ) + o.procedure = _.Procedure({ _stack : 3, _name : 'timeReady' }); /* delta : 3 to not include info about `routine.unite` and `routineClone` in the stack */ + + _.assert( _.procedureIs( o.procedure ) ); + + if( typeof window !== 'undefined' && typeof document !== 'undefined' && document.readyState !== 'complete' ) + { + let con = new _.Consequence({ tag : 'timeReady' }); + window.addEventListener( 'load', function() { handleReady( con, ... arguments ) } ); + return con; + } + else + { + return _.time.out( o.timeOut, o.procedure, o.onReady ); + } + + /* */ + + function handleReady( con ) + { + return _.time.out( o.timeOut, o.procedure, o.onReady ).finally( con ); + } + +} + +ready_body.defaults = +{ + timeOut : 0, + procedure : null, + onReady : null, +}; + +// + +let ready = _.routine.uniteCloning_replaceByUnite( _.process.ready.head, ready_body ); + +// + +function readyJoin( context, routine, args ) +{ + let joinedRoutine = _.routineJoin( context, routine, args ); + return _timeReady; + function _timeReady() + { + let args = arguments; + let procedure = _.Procedure({ _stack : 1, _name : 'timeReadyJoin' }); + let joinedRoutine2 = _.routineSeal( this, joinedRoutine, args ); + return _.process.ready({ procedure, onReady : joinedRoutine2 }); + } +} + +// -- +// relations +// -- + +let ToolsExtension = +{ + take, + // now : Now, yyy + // async : Now, yyy + after : After, + // before : Before, + stagesRun, + sessionsRun, + retry, +}; + +let TimeExtension = +{ + sleep, + out, + outError, + _errTimeOut, +}; + +let ProcessExtension = +{ + ready, + readyJoin, +}; + +_.props.extend( _, ToolsExtension ); +_.props.extend( _global.wTools, ToolsExtension ); +_.time = /* _.props.extend */Object.assign( _.time || null, TimeExtension ); +_global.wTools.time = _.props.extend( _global.wTools.time || null, TimeExtension ); +_.process = /* _.props.extend */Object.assign( _.process || null, ProcessExtension ); +_global.wTools.process = _.props.extend( _global.wTools.process || null, ProcessExtension ); + +require( './Consequence.s' ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wConsequence/proto/wtools/abase/l9/consequence/Namespace.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wConsequence/proto/wtools/abase/l9/consequence' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Namespace_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Namespace_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wCopyable/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wCopyable/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wCopyable */ ( function wCopyable() { function wCopyable_naked() { +module.exports = require( '../wtools/abase/l7_mixin/Copyable.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wCopyable', 'wcopyable' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wCopyable/proto/node_modules/wCopyable' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wCopyable/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wCopyable_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wCopyable */ })(); + +/* */ /* begin of file Copyable_s */ ( function Copyable_s() { function Copyable_s_naked() { ( function _Copyable_s_() +{ + +'use strict'; + +/** + * Copyable mixin add copyability and clonability to your class. The module uses defined relation to deduce how to copy / clone the instanceCopyable mixin adds copyability and clonability to your class. The module uses defined relation to deduce how to copy / clone the instance. + @module Tools/base/CopyableMixin +*/ + +/** + * */ + +/** + * @classdesc Copyable mixin add copyability and clonability to your class. + * @class wCopyable + * @namespace Tools + * @module Tools/base/CopyableMixin +*/ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + + _.include( 'wProto' ); + _.include( 'wCloner' ); + _.include( 'wStringer' ); + _.include( 'wLooker' ); + _.include( 'wEqualer' ); + +} + +// + +const _global = _global_; +const _ = _global_.wTools; +const _ObjectHasOwnProperty = Object.hasOwnProperty; + +_.assert( !!_._cloner ); + +// + +/** + * Mixin this into prototype of another object. + * @param {object} dstClass - constructor of class to mixin. + * @method onMixinApply + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function onMixinApply( mixinDescriptor, dstClass ) +{ + + var dstPrototype = dstClass.prototype; + var has = + { + Composes : 'Composes', + constructor : 'constructor', + } + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.routineIs( dstClass ), () => 'mixin expects constructor, but got ' + _.entity.strTypeSecondary( dstClass ) ); + _.map.assertOwnAll( dstPrototype, has ); + _.assert( _ObjectHasOwnProperty.call( dstPrototype, 'constructor' ), 'prototype of object should has own constructor' ); + + /* */ + + _.mixinApply( this, dstPrototype ); + + /* prototype accessors */ + + var readOnly = { combining : 'supplement', set : false }; + var names = + { + + Self : readOnly, + Parent : readOnly, + className : readOnly, + lowName : readOnly, + qualifiedName : readOnly, + uname : readOnly, + + fieldsOfRelationsGroups : readOnly, + fieldsOfCopyableGroups : readOnly, + fieldsOfTightGroups : readOnly, + fieldsOfInputGroups : readOnly, + + FieldsOfCopyableGroups : readOnly, + FieldsOfTightGroups : readOnly, + FieldsOfRelationsGroups : readOnly, + FieldsOfInputGroups : readOnly, + + } + + _.accessor.readOnly + ({ + object : dstPrototype, + names, + preservingValue : 0, + strict : 0, + prime : 0, + enumerable : 0, + }); + + /* constructor accessors */ + + var names = + { + + Self : readOnly, + Parent : readOnly, + className : readOnly, + lowName : readOnly, + + fieldsOfRelationsGroups : readOnly, + fieldsOfCopyableGroups : readOnly, + fieldsOfTightGroups : readOnly, + fieldsOfInputGroups : readOnly, + + FieldsOfCopyableGroups : readOnly, + FieldsOfTightGroups : readOnly, + FieldsOfRelationsGroups : readOnly, + FieldsOfInputGroups : readOnly, + + } + + _.accessor.readOnly + ({ + object : dstClass, + names, + preservingValue : 0, + strict : 0, + prime : 0, + enumerable : 0, + }); + + /* xxx : temp workaround */ + + if( mixinDescriptor.supplement && mixinDescriptor.supplement[ equalAreSymbol ] !== undefined ) + if( dstPrototype[ equalAreSymbol ] === undefined ) + dstPrototype[ equalAreSymbol ] = mixinDescriptor.supplement[ equalAreSymbol ]; + if( mixinDescriptor.extend && mixinDescriptor.extend[ equalAreSymbol ] !== undefined ) + dstPrototype[ equalAreSymbol ] = mixinDescriptor.extend[ equalAreSymbol ]; + + /* */ + + if( !Config.debug ) + return; + + if( dstPrototype[ equalAreSymbol ] ) + _.assert( dstPrototype[ equalAreSymbol ].length <= 1 ); + + _.assert( !( 'equalWith' in dstPrototype ) ); + if( _.routineIs( dstPrototype.equalWith ) ) + _.assert( dstPrototype.equalWith.length <= 2 ); + + _.assert( !!dstClass.prototype.FieldsOfRelationsGroupsGet ); + _.assert( !!dstClass.FieldsOfRelationsGroupsGet ); + _.assert( !!dstClass.fieldsOfRelationsGroups ); + _.assert( !!dstClass.FieldsOfRelationsGroups ); + _.assert( !!dstClass.prototype.fieldsOfRelationsGroups ); + _.assert( !!dstClass.prototype.FieldsOfRelationsGroups ); + + _.assert( dstPrototype._fieldsOfRelationsGroupsGet === _fieldsOfRelationsGroupsGet ); + _.assert( dstPrototype._fieldsOfCopyableGroupsGet === _fieldsOfCopyableGroupsGet ); + _.assert( dstPrototype._fieldsOfTightGroupsGet === _fieldsOfTightGroupsGet ); + _.assert( dstPrototype._fieldsOfInputGroupsGet === _fieldsOfInputGroupsGet ); + + _.assert( dstPrototype.constructor.FieldsOfRelationsGroupsGet === FieldsOfRelationsGroupsGet ); + _.assert( dstPrototype.constructor.FieldsOfCopyableGroupsGet === FieldsOfCopyableGroupsGet ); + _.assert( dstPrototype.constructor.FieldsOfTightGroupsGet === FieldsOfTightGroupsGet ); + _.assert( dstPrototype.constructor.FieldsOfInputGroupsGet === FieldsOfInputGroupsGet ); + + _.assert( _.routineIs( dstPrototype[ equalAreSymbol ] ), `Lack of method ${String( equalAreSymbol )}` ); + _.assert( _.routineIs( dstPrototype[ equalAreSymbol ].head ), `Lack of method ${String( equalAreSymbol )}.head` ); + _.assert( _.routineIs( dstPrototype[ equalAreSymbol ].body ), `Lack of method ${String( equalAreSymbol )}.body` ); + + _.assert( dstPrototype.finit.name !== 'finitEventHandler', 'wEventHandler mixin should goes after wCopyable mixin.' ); + _.assert( !_.mixinHas( dstPrototype, 'wEventHandler' ), 'wEventHandler mixin should goes after wCopyable mixin.' ); + +} + +// + +/** + * Default instance constructor. + * @method init + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function init( o ) +{ + return _.workpiece.initWithArguments({ instance : this, args : arguments }); +} + +// + +/** + * Instance descturctor. + * @method finit + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function finit() +{ + var self = this; + _.workpiece.finit( self ); +} + +// + +/** + * Is this instance finited. + * @method isFinited + * @param {object} ins - another instance of the class + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function isFinited() +{ + var self = this; + return _.workpiece.isFinited( self ); +} + +// + +function From( src ) +{ + return _.workpiece.from( src ); +} + +// + +function Froms( srcs ) +{ + return _.workpiece.froms( src ); +} + +// + +/** + * Copy data from another instance. + * @param {object} src - another isntance. + * @method copy + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function copy( src ) +{ + var self = this; + var routine = ( self._traverseAct || _traverseAct ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( src instanceof self.Self || _.mapIs( src ), 'Expects instance of Class or map as argument' ); + + var o = + { + dst : self, + src, + technique : 'object', + copyingMedials : _.instanceIs( src ) ? 0 : 1, + }; + var it = _._cloner( routine, o ); + + return routine.call( self, it ); +} + +// + +/** + * Copy data from one instance to another. Customizable static function. + * @param {object} o - options. + * @param {object} o.Prototype - prototype of the class. + * @param {object} o.src - src isntance. + * @param {object} o.dst - dst isntance. + * @param {object} o.constitutes - to constitute or not fields, should be off for serializing and on for deserializing. + * @method copyCustom + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function copyCustom( o ) +{ + var self = this; + var routine = ( self._traverseAct || _traverseAct ); + + _.assert( arguments.length === 1 ); + + if( o.dst === undefined ) + o.dst = self; + + var it = _._cloner( copyCustom, o ); + + return routine.call( self, it ); +} + +copyCustom.iterationDefaults = Object.create( _._cloner.iterationDefaults ); +copyCustom.defaults = _.mapExtendDstNotOwn( Object.create( _._cloner.defaults ), copyCustom.iterationDefaults ); + +// + +function copyDeserializing( o ) +{ + var self = this; + + _.map.assertHasAll( o, copyDeserializing.defaults ) + _.map.assertHasNoUndefine( o ); + _.assert( arguments.length === 1 ); + _.assert( _.object.isBasic( o ) ); + + var optionsMerging = Object.create( null ); + optionsMerging.src = o; + optionsMerging.proto = Object.getPrototypeOf( self ); + optionsMerging.dst = self; + optionsMerging.deserializing = 1; + + var result = _.cloneObjectMergingBuffers( optionsMerging ); + + return result; +} + +copyDeserializing.defaults = +{ + descriptorsMap : null, + buffer : null, + data : null, +} + +// + +/** + * Clone only data. + * @param {object} [options] - options. + * @method cloneObject + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function cloneObject( o ) +{ + var self = this; + var o = o || Object.create( null ); + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.routine.options_( cloneObject, o ); + + var it = _._cloner( cloneObject, o ); + + return self._cloneObject( it ); +} + +cloneObject.iterationDefaults = Object.create( _._cloner.iterationDefaults ); +cloneObject.defaults = _.mapExtendDstNotOwn( Object.create( _._cloner.defaults ), cloneObject.iterationDefaults ); +cloneObject.defaults.technique = 'object'; + +// + +/** + * Clone only data. + * @param {object} [options] - options. + * @method _cloneObject + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function _cloneObject( it ) +{ + var self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( it.iterator.technique === 'object' ); + + /* */ + + + if( it.dst ) + { + it.dst._traverseAct( it ); + } + else + { + dst = it.dst = new it.src.constructor( it.src ); + if( it.dst === it.src ) + { + dst = it.dst = new it.src.constructor(); + it.dst._traverseAct( it ); + } + } + + // if( !it.dst ) + // { + // dst = it.dst = new it.src.constructor( it.src ); + // if( it.dst === it.src ) + // { + // dst = it.dst = new it.src.constructor(); + // it.dst._traverseAct( it ); + // } + // } + // else + // { + // it.dst._traverseAct( it ); + // } + + return it.dst; +} + +// + +/** + * Clone only data. + * @param {object} [options] - options. + * @method cloneData + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function cloneData( o ) +{ + var self = this; + var o = o || Object.create( null ); + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( o.src === undefined ) + o.src = self; + + if( o.dst === undefined || o.dst === null ) + o.dst = Object.create( null ); + + var it = _._cloner( cloneData, o ); + + return self._cloneData( it ); +} + +cloneData.iterationDefaults = Object.create( _._cloner.iterationDefaults ); +cloneData.iterationDefaults.dst = null; +cloneData.iterationDefaults.copyingAggregates = 3; +cloneData.iterationDefaults.copyingAssociates = 0; +cloneData.defaults = _.mapExtendDstNotOwn( Object.create( _._cloner.defaults ), cloneData.iterationDefaults ); +cloneData.defaults.technique = 'data'; + +// + +/** + * Clone only data. + * @param {object} [options] - options. + * @method _cloneData + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function _cloneData( it ) +{ + var self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( it.iterator.technique === 'data' ); + + return self._traverseAct( it ); +} + +// + +function _traverseAct_head( routine, args ) +{ + let self = this; + let it = args[ 0 ]; + + _.assert( _.object.isBasic( it ) ); + _.assert( arguments.length === 2, 'Expects single argument' ); + _.assert( args.length === 1, 'Expects single argument' ); + + /* adjust */ + + if( it.src === undefined ) + it.src = self; + + if( it.iterator.technique === 'data' ) + if( !it.dst ) + it.dst = Object.create( null ); + + if( !it.proto && it.dst ) + it.proto = Object.getPrototypeOf( it.dst ); + if( !it.proto && it.src ) + it.proto = Object.getPrototypeOf( it.src ); + + return it; +} + +// + +/** + * Copy data from one instance to another. Customizable static function. + * @param {object} o - options. + * @param {object} o.Prototype - prototype of the class. + * @param {object} o.src - src isntance. + * @param {object} o.dst - dst isntance. + * @param {object} o.constitutes - to constitute or not fields, should be off for serializing and on for deserializing. + * @method _traverseAct + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +var _empty = Object.create( null ); +function _traverseAct_body( it ) +{ + var self = this; + + /* adjust */ + + _.assert( !_.primitiveIs( it.proto ) ); + + /* var */ + + var proto = it.proto; + var src = it.src; + var dst = it.dst; + var dropFields = it.dropFields || _empty; + var Composes = proto.Composes || _empty; + var Aggregates = proto.Aggregates || _empty; + var Associates = proto.Associates || _empty; + var Restricts = proto.Restricts || _empty; + var Medials = proto.Medials || _empty; + + /* verification */ + + _.map.assertHasNoUndefine( it ); + _.map.assertHasNoUndefine( it.iterator ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( src !== dst ); + _.assert( !!src ); + _.assert( _.strIs( it.path ) ); + _.assert( !_.primitiveIs( proto ), 'Expects object {-proto-}, but got', _.entity.strType( proto ) ); + _.assert( !it.customFields || _.object.isBasic( it.customFields ) ); + _.assert( it.level >= 0 ); + _.assert( _.numberIs( it.copyingDegree ) ); + _.assert( _.routineIs( self.__traverseAct ) ); + + if( _.workpiece.instanceIsStandard( src ) ) + _.map.assertOwnOnly( src, [ Composes, Aggregates, Associates, Restricts ], () => 'Options instance for ' + self.qualifiedName + ' should not have fields :' ); + else + _.map.assertOwnOnly( src, [ Composes, Aggregates, Associates, Medials ], () => 'Options map for ' + self.qualifiedName + ' should not have fields :' ); + + /* */ + + if( it.dst === null ) + { + + dst = it.dst = new it.src.constructor( it.src ); + if( it.dst === it.src ) + { + dst = it.dst = new it.src.constructor(); + self.__traverseAct( it ); + } + + } + else + { + + self.__traverseAct( it ); + + } + + /* done */ + + return dst; +} + +_traverseAct_body.iterationDefaults = Object.create( _._cloner.iterationDefaults ); +_traverseAct_body.defaults = _.mapExtendDstNotOwn( Object.create( _._cloner.defaults ), _traverseAct_body.iterationDefaults ); + +let _traverseAct = _.routine.uniteCloning_replaceByUnite( _traverseAct_head, _traverseAct_body ); + +// + +function __traverseAct( it ) +{ + + /* var */ + + var proto = it.proto; + var src = it.src; + var dst = it.dst = it.dst; + var dropFields = it.dropFields || _empty; + var Composes = proto.Composes || _empty; + var Aggregates = proto.Aggregates || _empty; + var Associates = proto.Associates || _empty; + var Restricts = proto.Restricts || _empty; + var Medials = proto.Medials || _empty; + + var ordersHash = new HashMap; + var standardOrder = true; + + /* */ + + var newIt = it.iterationClone(); + + // if( _global_.debugger ) + // debugger; + + copyFacets( Composes, it.copyingComposes ); + copyFacets( Aggregates, it.copyingAggregates ); + copyFacets( Associates, it.copyingAssociates ); + copyFacets( _.mapOnly_( null, Medials, Restricts ), it.copyingMedialRestricts ); + copyFacets( Restricts, it.copyingRestricts ); + copyFacets( it.customFields, it.copyingCustomFields ); + + run(); + + /* done */ + + return dst; + + /* */ + + function copyFacets( screen, copyingDegree ) + { + + if( screen === null ) + return; + + if( !copyingDegree ) + return; + + _.assert( _.mapIs( screen ) || _.aux.isPrototyped( screen ) ); + let screen2 = _.props.extend( null, screen ); + _.assert( _.numberIs( copyingDegree ) ); + _.assert( it.dst === dst ); + _.assert( _.mapIs( screen2 ) || _.aux.isPrototyped( screen2 ) || !copyingDegree ); + + let newIt2 = Object.create( null ); + newIt2.screenFields = screen2; + newIt2.copyingDegree = Math.min( copyingDegree, it.copyingDegree ); + newIt2.instanceAsMap = 1; + + _.assert( it.copyingDegree === 3, 'not tested' ); + _.assert( newIt2.copyingDegree === 1 || newIt2.copyingDegree === 3, 'not tested' ); + + /* copyingDegree applicable to fields, so increment is needed */ + + if( newIt2.copyingDegree === 1 ) + newIt2.copyingDegree += 1; + + for( let s in screen2 ) + { + let e = screen[ s ]; + if( _.definitionIs( e ) ) + if( e.order < 0 || e.order > 0 ) + { + let newIt3 = _.props.extend( null, newIt2 ); + newIt3.screenFields = Object.create( null ); + newIt3.screenFields[ s ] = screen2[ s ]; + delete screen2[ s ]; + orderAdd( e.order, newIt3 ); + } + } + + orderAdd( 0, newIt2 ); + + } + + /* */ + + function orderAdd( order, newIt2 ) + { + _.assert( _.numberIs( order ) ); + + if( !ordersHash.has( order ) ) + ordersHash.set( order, [] ); + + ordersHash.get( order ).push( newIt2 ); + + } + + /* */ + + function run() + { + + let orders = Array.from( ordersHash.keys() ); + orders.sort(); + + orders.forEach( ( order ) => + { + let its = ordersHash.get( order ); + its.forEach( ( newIt2 ) => + { + _.props.extend( newIt, newIt2 ); + _._traverseMap( newIt ); + }); + }); + + } + +} + +// + +function Clone( o ) +{ + var cls = this.Self; + o = o || Object.create( null ); + + _.assert( arguments.length <= 1 ); + + if( o instanceof cls ) + return o.clone(); + else + return cls( o ) +} + +// + +/** + * Clone only data. + * @param {object} [options] - options. + * @method cloneSerializing + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function cloneSerializing( o ) +{ + var self = this; + var o = o || Object.create( null ); + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( o.src === undefined ) + o.src = self; + + if( o.copyingMedials === undefined ) + o.copyingMedials = 0; + + if( o.copyingMedialRestricts === undefined ) + o.copyingMedialRestricts = 1; + + var result = _.cloneDataSeparatingBuffers( o ); + + return result; +} + +cloneSerializing.defaults = +{ + copyingMedialRestricts : 1, +} + +// cloneSerializing.defaults.__proto__ = _.cloneDataSeparatingBuffers.defaults; +Object.setPrototypeOf( cloneSerializing.defaults, _.cloneDataSeparatingBuffers.defaults ) + +// + +/** + * Clone instance. + * @method clone + * @param {object} [self] - optional destination + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function clone() +{ + var self = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + var dst = new self.constructor( self ); + _.assert( dst !== self ); + + return dst; +} + +// + +function cloneExtending( override ) +{ + var self = this; + + _.assert( arguments.length <= 1 ); + + // if( !override ) + if( override ) + { + var src = _.mapOnly_( null, self, self.Self.FieldsOfCopyableGroups ); + _.props.extend( src, override ); + var dst1 = new self.constructor( src ); + _.assert( dst1 !== self && dst1 !== src ); + return dst1; + + // var dst0 = new self.constructor( self ); + // _.assert( dst0 !== self ); + // return dst0; + } + else + { + var dst0 = new self.constructor( self ); + _.assert( dst0 !== self ); + return dst0; + + // var src = _.mapOnly_( null, self, self.Self.FieldsOfCopyableGroups ); + // _.props.extend( src, override ); + // var dst1 = new self.constructor( src ); + // _.assert( dst1 !== self && dst1 !== src ); + // return dst1; + } + +} + +// + +function cloneEmpty() +{ + var self = this; + return self.clone(); +} + +// -- +// etc +// -- + +/** + * Gives descriptive string of the object. + * @method toStr + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function toStr( o ) +{ + return _.workpiece.toStr( this, o ); +} + +// -- +// dichotomy +// -- + +function _equalAre_functor( fieldsGroupsMap ) +{ + _.assert( arguments.length <= 1 ); + + fieldsGroupsMap = _.routine.options_( _equalAre_functor, fieldsGroupsMap || null ); + + _.routineExtend( _equalAre, _.equaler._equal ); + + return _equalAre; + + function _equalAre( it ) + { + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.object.isBasic( it ) ); + _.assert( it.strictTyping !== undefined ); + _.assert( it.containing !== undefined ); + + if( !it.src ) + return end( false ); + + if( !it.src2 ) + return end( false ); + + if( it.strictTyping ) + if( it.src.constructor !== it.src2.constructor ) + return end( false ); + + if( it.src === it.src2 ) + return end( true ); + + /* */ + + var fieldsMap = Object.create( null ); + for( var g in fieldsGroupsMap ) + if( fieldsGroupsMap[ g ] ) + _.props.extend( fieldsMap, this[ g ] ); + + /* */ + + let c = 0; + for( var f in fieldsMap ) + { + if( !it.continue || !it.iterator.continue ) + break; + var newIt = it.iterationMake().choose( it.src[ f ], f, c, true ); + c += 1; + if( !_.props.own( it.src, f ) ) + return end( false ); + newIt.iterate(); + // if( !_.equaler._equal.body( newIt ) ) + // return end( false ); + } + + if( !it.iterator.continue ) + return; + // yyy + // return it.result; + + /* */ + + if( !it.containing ) + { + if( !( it.src2 instanceof this.constructor ) ) + if( _.props.keys( _.mapBut_( null, it.src, fieldsMap ) ).length ) + return end( false ); + } + + if( !( it.src instanceof this.constructor ) ) + if( _.props.keys( _.mapBut_( null, it.src, fieldsMap ) ).length ) + return end( false ); + + /* */ + + return end( true ); + + /* */ + + function end( result ) + { + it.continue = false; + it.result = result; + } + + } + +} + +_equalAre_functor.defaults = Object.create( null ); + +var on = _.map.make( _.DefaultFieldsGroupsCopyable ); +var off = _.mapBut_( null, _.DefaultFieldsGroups, _.DefaultFieldsGroupsCopyable ); +_.mapAllValsSet( on, 1 ); +_.mapAllValsSet( off, 0 ); +_.props.extend( _equalAre_functor.defaults, on, off ); + +// + +/** + * Is this instance same with another one. Use relation maps to compare. + * @method _equalAre + * @param {object} ins - another instance of the class + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +var _equalAre = _equalAre_functor(); + +// + +/** + * Is this instance same with another one. Use relation maps to compare. + * @method identicalWith + * @param {object} src - another instance of the class + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function identicalWith( src, opts ) +{ + var self = this; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( !opts || _.mapIs( opts ), 'not tested' ); + + var args = [ self, src, opts ]; + var it = self[ equalAreSymbol ].head.call( self, self.identicalWith, args ); + var r = this[ equalAreSymbol ]( it ); + + return it.result; +} + +_.routine.extendReplacing( identicalWith, { defaults : _.entityIdentical.defaults } ); + +// + +/** + * Is this instance equivalent with another one. Use relation maps to compare. + * @method equivalentWith + * @param {object} src - another instance of the class + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function equivalentWith( src, opts ) +{ + var self = this; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( !opts || _.mapIs( opts ), 'not tested' ); + + var args = [ self, src, opts ]; + var it = self[ equalAreSymbol ].head.call( self, self.equivalentWith, args ); + var r = this[ equalAreSymbol ]( it ); + + return it.result; +} + +_.routine.extendReplacing( equivalentWith, { defaults : _.entityEquivalent.defaults } ); + +// + +/** + * Does this instance contain with another instance or map. + * @method contains + * @param {object} src - another instance of the class + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function contains( src, opts ) +{ + var self = this; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( !opts || _.mapIs( opts ), 'not tested' ); + + var args = [ self, src, opts ]; + var it = self[ equalAreSymbol ].head.call( self, self.contains, args ); + + // _.assert( it.src === null ); + // _.assert( it.src2 === null ); + // + // it.src = it.src; + // it.src2 = it.src2; + + var r = this[ equalAreSymbol ]( it ); + + return it.result; +} + +_.routine.extendReplacing( contains, { defaults : _.entityContains.defaults } ); + +// + +function instanceIs() +{ + _.assert( arguments.length === 0, 'Expects no arguments' ); + return _.instanceIs( this ); +} + +// + +function prototypeIs() +{ + _.assert( arguments.length === 0, 'Expects no arguments' ); + return _.workpiece.prototypeIs( this ); +} + +// + +function constructorIs() +{ + _.assert( arguments.length === 0, 'Expects no arguments' ); + return _.constructorIs( this ); +} + +// -- +// field +// -- + +/** + * Get map of all fields. + * @method FieldsOfRelationsGroupsGet + * @class wCopyable + * @module Tools/base/CopyableMixin + * @namespace Tools + */ + +function _fieldsOfRelationsGroupsGet() +{ + var self = this; + return _.workpiece.fieldsOfRelationsGroups( this ); +} + +// + +/** + * Get map of copyable fields. + * @method _fieldsOfCopyableGroupsGet + * @class wCopyable + * @module Tools/base/CopyableMixin + * @namespace Tools + */ + +function _fieldsOfCopyableGroupsGet() +{ + var self = this; + return _.workpiece.fieldsOfCopyableGroups( this ); +} + +// + +/** + * Get map of loggable fields. + * @method _fieldsOfTightGroupsGet + * @class wCopyable + * @module Tools/base/CopyableMixin + * @namespace Tools + */ + +function _fieldsOfTightGroupsGet() +{ + var self = this; + return _.workpiece.fieldsOfTightGroups( this ); +} + +// + +function _fieldsOfInputGroupsGet() +{ + var self = this; + return _.workpiece.fieldsOfInputGroups( this ); +} + +// + +/** + * Get map of all relations fields. + * @method FieldsOfRelationsGroupsGet + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function FieldsOfRelationsGroupsGet() +{ + return _.workpiece.fieldsOfRelationsGroups( this.Self ); +} + +// + +/** + * Get map of copyable fields. + * @method FieldsOfCopyableGroupsGet + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function FieldsOfCopyableGroupsGet() +{ + return _.workpiece.fieldsOfCopyableGroups( this.Self ); +} + +// + +/** + * Get map of tight fields. + * @method FieldsOfTightGroupsGet + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function FieldsOfTightGroupsGet() +{ + return _.workpiece.fieldsOfTightGroups( this.Self ); +} + +// + +/** + * Get map of input fields. + * @method FieldsOfInputGroupsGet + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function FieldsOfInputGroupsGet() +{ + return _.workpiece.fieldsOfInputGroups( this.Self ); +} + +// + +function hasField( propName ) +{ + return _.workpiece.prototypeHasField( this, propName ); +} + +// -- +// class +// -- + +/** + * Return own constructor. + * @method _SelfGet + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function _SelfGet() +{ + var result = _.workpiece.constructorOf( this ); + return result; +} + +// + +/** + * Return parent's constructor. + * @method _ParentGet + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function _ParentGet() +{ + var result = _.workpiece.parentOf( this ); + return result; +} + +// -- +// name +// -- + +function _lowNameGet() +{ + return _.workpiece.lowClassName( this ); +} + +// + +/** + * Return name of class constructor. + * @method _classNameGet + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function _classNameGet() +{ + return _.workpiece.className( this ); +} + +// + +/** + * Nick name of the object. + * @method _qualifiedNameGet + * @module Tools/base/CopyableMixin + * @namespace Tools + * @class wCopyable + */ + +function _qualifiedNameGet() +{ + return _.workpiece._qualifiedNameGet( this ); +} + +// + +function unameGet() +{ + return _.workpiece.uname( this ); +} + +// -- +// relations +// -- + +var equalAreSymbol = Symbol.for( 'equalAre' ); + +var Composes = +{ +} + +var Aggregates = +{ +} + +var Associates = +{ +} + +var Restricts = +{ +} + +var Medials = +{ +} + +var Statics = +{ + + From, + Froms, + + Clone, + + instanceIs, + prototypeIs, + constructorIs, + + _fieldsOfRelationsGroupsGet, + _fieldsOfCopyableGroupsGet, + _fieldsOfTightGroupsGet, + _fieldsOfInputGroupsGet, + + FieldsOfRelationsGroupsGet, + FieldsOfCopyableGroupsGet, + FieldsOfTightGroupsGet, + FieldsOfInputGroupsGet, + + hasField, + + _SelfGet, + _ParentGet, + _classNameGet, + _lowNameGet, + +} + +Object.freeze( Composes ); +Object.freeze( Aggregates ); +Object.freeze( Associates ); +Object.freeze( Restricts ); +Object.freeze( Medials ); +Object.freeze( Statics ); + +// -- +// declare +// -- + +var Supplement = +{ + + init, + finit, + isFinited, + + From, + Froms, + + copy, + + copyCustom, + copyDeserializing, + + _traverseAct, + __traverseAct, + + cloneObject, + _cloneObject, + + cloneData, + _cloneData, + + Clone, + cloneSerializing, + clone, + cloneExtending, + cloneEmpty, + + // etc + + toStr, + + // dichotomy + + _equalAre_functor, + [ equalAreSymbol ] : _equalAre, + + identicalWith, + equivalentWith, + contains, + + instanceIs, + prototypeIs, + constructorIs, + + // field + + _fieldsOfRelationsGroupsGet, + _fieldsOfCopyableGroupsGet, + _fieldsOfTightGroupsGet, + _fieldsOfInputGroupsGet, + + // class + + _SelfGet, + _ParentGet, + + // name + + _lowNameGet, + _classNameGet, + _qualifiedNameGet, + unameGet, + + // + + Composes, + Aggregates, + Associates, + Restricts, + Medials, + Statics, + +} + +// + +const Self = _.mixinDelcare +({ + supplement : Supplement, + onMixinApply, + name : 'wCopyable', + shortName : 'Copyable', +}); + +// + +_.assert( !Self.copy ); +_.assert( _.routineIs( Self.prototype.copy ) ); +_.assert( _.strIs( Self.shortName ) ); +_.assert( _.object.isBasic( Self.__mixin__ ) ); +_.assert( !Self.onMixinApply ); +_.assert( _.routineIs( Self.mixin ) ); + +// -- +// export +// -- + +_global_[ Self.name ] = _[ Self.shortName ] = Self; +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wCopyable/proto/wtools/abase/l7_mixin/Copyable.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wCopyable/proto/wtools/abase/l7_mixin' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Copyable_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Copyable_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wEventHandler/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wEventHandler/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wEventHandler */ ( function wEventHandler() { function wEventHandler_naked() { +module.exports = require( '../wtools/abase/l7_mixin/EventHandler.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wEventHandler', 'weventhandler' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wEventHandler/proto/node_modules/wEventHandler' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wEventHandler/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wEventHandler_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wEventHandler */ })(); + +/* */ /* begin of file EventHandler_s */ ( function EventHandler_s() { function EventHandler_s_naked() { ( function _EventHandler_s_() +{ + +'use strict'; + +/** + * Mixin adds events dispatching mechanism to your class. EventHandler provides methods to bind/unbind handler of an event, to handle a specific event only once, to associate an event with a namespace what later make possible to unbind handler of event with help of namespace. EventHandler allows redirecting events to/from another instance. Unlike alternative implementation of the concept, EventHandler is strict by default and force developer to explicitly declare / bind / unbind all events supported by object. Use it to add events dispatching mechanism to your classes and avoid accumulation of technical dept and potential errors. + @module Tools/base/EventHandler +*/ + +/* + ++ implement tracking of event kinds !!! +- remove deprecated features !!! +- refactor !!! +- off of not offed event handler should throw error !!! + +*/ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + + _.include( 'wProto' ); + +} + +// + +/** + * @classdesc Mixin adds events dispatching mechanism to your class + * @class wEventHandler + * @namespace Tools + * @module Tools/base/EventHandler + */ + +const _global = _global_; +const _ = _global_.wTools; +const _ObjectHasOwnProperty = Object.hasOwnProperty; +const Parent = null; +const Self = wEventHandler; +function wEventHandler( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'EventHandler'; + +// -- +// +// -- + +/** + * Mixin this methods into prototype of another object. + * @param {object} dstPrototype - prototype of another object. + * @method copy + * @module Tools/base/EventHandler + * @namespace Tools + * @class wEventHandler + */ + +function onMixinApply( mixinDescriptor, dstClass ) +{ + let dstPrototype = dstClass.prototype; + + _.mixinApply( this, dstPrototype ); + + _.assert( _.object.isBasic( dstPrototype.Restricts._eventHandler ) ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.routineIs( dstClass ) ); + _.assert( _.object.isBasic( dstPrototype.Events ) ); + _.assert( _.strIs( dstPrototype.Events.init ) ); + _.assert( _.strIs( dstPrototype.Events.finit ) ); + + _.accessor.ownForbid( dstPrototype, '_eventHandlers' ); + +} + +// -- +// Functors +// -- + +/** + * Functors to produce init. + * @param { routine } original - original method. + * @method init + * @module Tools/base/EventHandler + * @namespace Tools + * @class wEventHandler + */ + +function init( original ) +{ + + return function initEventHandler() + { + let self = this; + + self._eventHandlerInit(); + + let result = original ? original.apply( self, arguments ) : undefined; + + self.eventGive( 'init' ); + + return result; + } + +} + +// + +/** + * Functors to produce finit. + * @param { routine } original - original method. + * @method finit + * @module Tools/base/EventHandler + * @namespace Tools + * @class wEventHandler + */ + +function finit( original ) +{ + + return function finitEventHandler() + { + let self = this; + let result; + + self.eventGive( 'finit' ); + + if( original ) + result = original ? original.apply( self, arguments ) : undefined; + + self._eventHandlerFinit(); + + return result; + } + +} + +// -- +// register +// -- + +function _eventHandlerInit() +{ + let self = this; + + _.assert( !self._eventHandler, () => 'EventHandler.init already done for ' + self.qualifiedName ); + _.assert( self instanceof self.constructor ); + + if( !self._eventHandler ) + self._eventHandler = Object.create( null ); + + if( !self._eventHandler.descriptors ) + self._eventHandler.descriptors = Object.create( null ); + +} + +// + +function _eventHandlerFinit() +{ + let self = this; + + if( Config.debug || !self.strictEventHandling ) + { + + let handlers = self._eventHandler.descriptors; + if( !handlers ) + return; + + for( let h in handlers ) + { + if( !handlers[ h ] || handlers[ h ].length === 0 ) + continue; + if( h === 'finit' ) + continue; + let err = 'Finited instance has bound handler(s), but should not' + h + ':\n' + _.entity.exportString( handlers[ h ], { levels : 2 } ); + console.error( err.toString() + '\n' + err.stack ); + console.error( handlers[ h ][ 0 ].onHandle ); + console.error( self.eventReport() ); + throw _.err( err ); + } + + } + + self.eventHandlerRemove(); +} + +// + +function eventReport() +{ + let self = this; + let result = 'Event Map of ' + ( self.qualifiedName || 'an instance' ) + ':\n'; + let handlerArray; + + let handlers = self._eventHandler.descriptors || {}; + for( let h in handlers ) + { + handlerArray = handlers[ h ]; + if( !handlerArray || handlerArray.length === 0 ) + continue; + let onHandle = handlerArray.map( ( e ) => _.entity.exportString( e.onHandle ) ); + result += h + ' : ' + onHandle.join( ', ' ) + '\n'; + } + + for( let h in self.Events ) + { + handlerArray = handlers[ h ]; + if( !handlerArray || handlerArray.length === 0 ) + { + result += h + ' : ' + '-' + '\n'; + } + } + + return result; +} + +// + +function eventHandlerPrepend( kind, onHandle ) +{ + let self = this; + let owner; + + _.assert( arguments.length === 2 || arguments.length === 3, 'eventHandlerAppend:', 'Expects "kind" and "onHandle" as arguments' ); + + if( arguments.length === 3 ) + { + owner = arguments[ 1 ]; + onHandle = arguments[ 2 ]; + } + + let descriptor = + { + kind, + onHandle, + owner, + appending : 0, + } + + self._eventHandlerRegister( descriptor ); + + return self; +} + +// + +/** + * @summary Registers handler `onHandle` routine for event `kind`. + * @param { String } kind - name of event + * @param { Function } onHandle - event handler + * @method on + * @module Tools/base/EventHandler + * @namespace Tools + * @class wEventHandler + */ + +function eventHandlerAppend( kind, onHandle ) +{ + let self = this; + let owner; + + _.assert( arguments.length === 2 || arguments.length === 3, 'eventHandlerAppend:', 'Expects "kind" and "onHandle" as arguments' ); + + if( arguments.length === 3 ) + { + owner = arguments[ 1 ]; + onHandle = arguments[ 2 ]; + } + + let descriptor = + { + kind, + onHandle, + owner, + appending : 1, + } + + self._eventHandlerRegister( descriptor ); + + return self; +} + +// + +function eventHandlerRegisterProvisional( kind, onHandle ) +{ + let self = this; + let owner; + + _.assert( arguments.length === 2 || arguments.length === 3, 'eventHandlerRegisterProvisional:', 'Expects "kind" and "onHandle" as arguments' ); + + if( arguments.length === 3 ) + { + owner = arguments[ 1 ]; + onHandle = arguments[ 2 ]; + } + + let descriptor = + { + kind, + onHandle, + owner, + once : 0, + provisional : 1, + appending : 0, + } + + self._eventHandlerRegister( descriptor ); + + return self; +} + +// + +/** + * @summary Register handler `onHandle` routine for event `kind`. Handler will be called only once. + * @param { String } kind - name of event + * @param { Function } onHandle - event handler + * @method once + * @module Tools/base/EventHandler + * @namespace Tools + * @class wEventHandler + */ + +function eventHandlerRegisterOneTime( kind, onHandle ) +{ + let self = this; + let owner; + + _.assert( arguments.length === 2 || arguments.length === 3, 'eventHandlerRegisterOneTime:', 'Expects "kind" and "onHandle" as arguments' ); + + if( arguments.length === 3 ) + { + owner = arguments[ 1 ]; + onHandle = arguments[ 2 ]; + } + + let descriptor = + { + kind, + onHandle, + owner, + once : 1, + appending : 0, + } + + self._eventHandlerRegister( descriptor ); + + return self; +} + +// + +function eventHandlerRegisterEclipse( kind, onHandle ) +{ + let self = this; + let owner; + + _.assert( arguments.length === 2 || arguments.length === 3, 'eventHandlerRegisterEclipse:', 'Expects "kind" and "onHandle" as arguments' ); + + if( arguments.length === 3 ) + { + owner = arguments[ 1 ]; + onHandle = arguments[ 2 ]; + } + + let descriptor = + { + kind, + onHandle, + owner, + eclipse : 1, + appending : 0, + } + + self._eventHandlerRegister( descriptor ); + + return self; +} + +// +// +// function eventForbid( kinds ) +// { +// var self = this; +// var owner; +// +// _.assert( arguments.length === 1, 'Expects single argument' ); +// _.assert( _.strIs( kinds ) || _.arrayIs( kinds ) ); +// +// var kinds = _.array.as( kinds ); +// +// function onHandle() +// { +// throw _.err( kinds.join( ' ' ), 'event is forbidden in', self.qualifiedName ); +// } +// +// for( var k = 0 ; k < kinds.length ; k++ ) +// { +// +// var kind = kinds[ k ]; +// +// var descriptor = +// { +// kind, +// onHandle, +// // forbidden : 1, +// appending : 0, +// } +// +// self._eventHandlerRegister( descriptor ); +// +// } +// +// return self; +// } +// +// + +function _eventHandlerRegister( o ) +{ + let self = this; + + if( o.kind === _.anything ) + { + o.kind = []; + for( let k in self.Events ) + { + o.kind.push( k ); + } + } + + if( _.arrayIs( o.kind ) ) + { + for( let k = 0 ; k < o.kind.length ; k++ ) + { + let d = _.props.extend( null, o ); + d.kind = o.kind[ k ]; + self._eventHandlerRegister( d ); + } + return self; + } + + /* verification */ + + _.assert( _.strIs( o.kind ) ); + _.assert( _.routineIs( o.onHandle ), 'Expects routine {-onHandle-}, but got', _.entity.strType( o.oHandle ) ); + _.map.assertHasOnly( o, _eventHandlerRegister.defaults ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( !( o.provisional && o.once ) ); + _.assert( !!self.constructor.prototype.Events || ( !self.constructor.prototype.strictEventHandling && self.constructor.prototype.strictEventHandling !== undefined ), 'Expects static Events' ); + _.assert( !self.strictEventHandling || !!self.Events[ o.kind ], self.constructor.name, 'is not aware about event', _.strQuote( o.kind ) ) + + // if( o.forbidden ) + // console.debug( 'REMINDER : forbidden event is not implemented!' ); + + let handlers = self._eventHandlerDescriptorsByKind( o.kind ); + + if( self._eventKinds && self._eventKinds.indexOf( kind ) === -1 ) + throw _.err( 'eventHandlerAppend:', 'Object does not support such kind of events :', kind, self ); + + /* */ + + o.onHandleEffective = o.onHandle; + + /* eclipse */ + + if( o.eclipse ) + o.onHandleEffective = function handleEclipse() + { + let result = o.onHandle.apply( this, arguments ); + + self._eventHandlerRemove + ({ + kind : o.kind, + onHandle : o.onHandle, + strict : 0, + }); + + return result; + } + + /* once */ + + if( o.once ) + if( self._eventHandlerDescriptorByKindAndHandler( o.kind, o.onHandle ) ) + return self; + + if( o.once ) + o.onHandleEffective = function handleOnce() + { + let result = o.onHandle.apply( this, arguments ); + + self._eventHandlerRemove + ({ + kind : o.kind, + onHandle : o.onHandle, + strict : 0, + }); + + return result; + } + + /* provisional */ + + if( o.provisional ) + o.onHandleEffective = function handleProvisional() + { + let result = o.onHandle.apply( this, arguments ); + + if( result === false ) + self._eventHandlerRemove + ({ + kind : o.kind, + onHandle : o.onHandle, + strict : 0, + }); + + return result; + } + + /* owner */ + + if( o.owner !== undefined && o.owner !== null ) + self.eventHandlerRemoveByKindAndOwner( o.kind, o.owner ); + + /* */ + + if( o.appending ) + handlers.push( o ); + else + handlers.unshift( o ); + + /* kinds */ + + if( self._eventKinds ) + { + _.arrayAppendOnce( self._eventKinds, kind ); + } + + return self; +} + +_eventHandlerRegister.defaults = +{ + kind : null, + onHandle : null, + owner : null, + proxy : 0, + once : 0, + eclipse : 0, + provisional : 0, + appending : 1, +} + +// -- +// unregister +// -- + +/** + * @summary Unregisters handler `onHandle` routine for event `kind`. + * @param { String } kind - name of event + * @param { Function } onHandle - event handler + * @method off + * @module Tools/base/EventHandler + * @namespace Tools + * @class wEventHandler + */ + +function eventHandlerRemove() +{ + let self = this; + + if( !self._eventHandler.descriptors ) + return self; + + if( arguments.length === 0 ) + { + + self._eventHandlerRemove( Object.create( null ) ); + + } + else if( arguments.length === 1 ) + { + + if( _.strIs( arguments[ 0 ] ) ) + { + + self._eventHandlerRemove + ({ + kind : arguments[ 0 ], + }); + + } + else if( _.routineIs( arguments[ 0 ] ) ) + { + + self._eventHandlerRemove + ({ + onHandle : arguments[ 0 ], + }); + + } + else if( _.longIs( arguments[ 0 ] ) ) + { + + for( let i = 0; i < arguments[ 0 ].length; i++ ) + self.eventHandlerRemove( arguments[ 0 ][ i ] ); + + } + else throw _.err( 'unexpected' ); + + } + else if( arguments.length === 2 ) + { + + if( _.longIs( arguments[ 0 ] ) ) + { + + for( let i = 0; i < arguments[ 0 ].length; i++ ) + self.eventHandlerRemove( arguments[ 0 ][ i ], arguments[ 1 ] ); + + } + else if( _.routineIs( arguments[ 1 ] ) ) + { + + self._eventHandlerRemove + ({ + kind : arguments[ 0 ], + onHandle : arguments[ 1 ], + }); + + } + else + { + self._eventHandlerRemove + ({ + kind : arguments[ 0 ], + owner : arguments[ 1 ], + }); + } + } + else _.assert( 0, 'unexpected' ); + + return self; +} + +// + +function _eventHandlerRemove( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.map.assertHasOnly( o, _eventHandlerRemove.defaults ); + if( Object.keys( o ).length && o.strict === undefined ) + o.strict = 1; + + let handlers = self._eventHandler.descriptors; + if( !handlers ) + return self; + + let length = Object.keys( o ).length; + + if( o.kind !== undefined ) + _.assert( _.strIs( o.kind ), 'Expects "kind" as string' ); + + if( o.onHandle !== undefined ) + _.assert( _.routineIs( o.onHandle ), 'Expects "onHandle" as routine' ); + + if( length === 0 ) + { + + for( let h in handlers ) + handlers[ h ].splice( 0, handlers[ h ].length ); + + } + else if( length === 1 && o.kind ) + { + + let handlers = handlers[ o.kind ]; + if( !handlers ) + return self; + + handlers.splice( 0, handlers.length ); + + } + else + { + + // console.error( 'REMINDER', 'fix me' ); debugger; xxx + // return; + // let handlers; // !!! + let removed = 0; + if( o.kind ) + { + + handlers = handlers[ o.kind ]; + if( handlers ) + removed = _.arrayRemovedElement( handlers, o, equalizer ); + + } + else for( let h in handlers ) + { + + removed += _.arrayRemovedElement( handlers[ h ], o, equalizer ); + + } + + _.assert( removed > 0 || !o.onHandle || !o.strict, 'The handler was not registered to unregister it' ); + + } + + function equalizer( a, b ) + { + if( o.kind !== undefined ) + if( a.kind !== b.kind ) + return false; + + if( o.onHandle !== undefined ) + if( a.onHandle !== b.onHandle ) + return false; + + if( o.owner !== undefined ) + if( a.owner !== b.owner ) + return false; + + return true; + } + + return self; +} + +_eventHandlerRemove.defaults = +{ + kind : null, + onHandle : null, + owner : null, + strict : 1, +} + +// + +function eventHandlerRemoveByKindAndOwner( kind, owner ) +{ + let self = this; + + _.assert( arguments.length === 2 && !!owner, 'eventHandlerRemove:', 'Expects "kind" and "owner" as arguments' ); + + let handlers = self._eventHandler.descriptors; + if( !handlers ) + return self; + + handlers = handlers[ kind ]; + if( !handlers ) + return self; + + let descriptor; // !!! + do + { + + descriptor = self._eventHandlerDescriptorByKindAndOwner( kind, owner ); + + if( descriptor ) + _.arrayRemoveElementOnce( handlers, descriptor ); + + } + while( descriptor ); + + return self; +} + + +// -- +// handle +// -- + +function eventGive( event ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.routineIs( self._eventGive ) ); + + if( _.strIs( event ) ) + event = { kind : event }; + + return self._eventGive( event, Object.create( null ) ); +} + +// + +function eventHandleUntil( event, value ) +{ + let self = this; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.strIs( event ) ) + event = { kind : event }; + + return self._eventGive( event, { until : value } ); +} + +// + +function eventHandleSingle( event ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.strIs( event ) ) + event = { kind : event }; + + return self._eventGive( event, { single : 1 } ); +} + +// + +function _eventGive( event, o ) +{ + let self = this; + let result = o.result = o.result || []; + let untilFound = 0; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( event.type === undefined || event.kind !== undefined, 'event should have "kind" field, no "type" field' ); + _.assert( !!self.constructor.prototype.Events || ( !self.constructor.prototype.strictEventHandling && self.constructor.prototype.strictEventHandling !== undefined ), 'Expects static Events' ); + _.assert( !self.strictEventHandling || !!self.Events[ event.kind ], () => self.constructor.name + ' is not aware about event ' + _.strQuote( event.kind ) ); + _.assert( _.object.isBasic( self._eventHandler ) ); + + if( self.eventVerbosity ) + logger.log( 'fired event', self.qualifiedName + '.' + event.kind ); + + /* head */ + + let handlers = self._eventHandler.descriptors; + if( handlers === undefined ) + return result; + + let handlerArray = handlers[ event.kind ]; + if( handlerArray === undefined ) + return result; + + handlerArray = handlerArray.slice( 0 ); + + event.target = self; + + if( self.eventVerbosity ) + logger.up(); + + if( o.single ) + _.assert( handlerArray.length <= 1, 'Expects single handler, but has ' + handlerArray.length ); + + /* iterate */ + + for( let i = 0, il = handlerArray.length; i < il; i ++ ) + { + + let handler = handlerArray[ i ]; + + if( self.eventVerbosity ) + logger.log( event.kind, 'caught by', handler.onHandle.name ); + + if( handler.proxy ) + { + handler.onHandleEffective.call( self, event, o ); + } + else + { + + result.push( handler.onHandleEffective.call( self, event ) ); + if( o.until !== undefined ) + { + if( result[ result.length-1 ] === o.until ) + { + untilFound = 1; + result = o.until; + break; + } + } + + } + + if( handler.eclipse ) + break; + + } + + /* post */ + + if( self.eventVerbosity ) + logger.down(); + + if( o.single ) + result = result[ 0 ]; + + if( o.until && !untilFound ) + result = undefined; + + return result; +} + +// + +/** + * @summary Returns `Consequence` instance that gives a message when event fires. Message is given only once. + * @param { String } kind - name of event + * @method eventWaitFor + * @module Tools/base/EventHandler + * @namespace Tools + * @class wEventHandler + */ + +function eventWaitFor( kind ) +{ + let self = this; + let con = new _.Consequence(); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( kind ) ); + + let descriptor = + { + kind, + onHandle : function( e, o ) + { + _.time.begin( 0, () => con.take( e ) ); + }, + eclipse : 0, + once : 1, + appending : 1, + } + + self._eventHandlerRegister( descriptor ); + + return con; +} + +// -- +// get +// -- + +function _eventHandlerDescriptorByKindAndOwner( kind, owner ) +{ + let self = this; + + let handlers = self._eventHandler.descriptors; + if( !handlers ) + return; + + handlers = handlers[ kind ]; + if( !handlers ) + return; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + function eq( a, b ){ return a.kind === b.kind && a.owner === b.owner; }; + let element = { kind, owner }; + let index = _.longRightIndex( handlers, element, eq ); + + if( !( index >= 0 ) ) + return; + + let result = handlers[ index ]; + result.index = index; + + return result; +} + +// + +function _eventHandlerDescriptorByKindAndHandler( kind, onHandle ) +{ + let self = this; + + let handlers = self._eventHandler.descriptors; + if( !handlers ) + return; + + handlers = handlers[ kind ]; + if( !handlers ) + return; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + function eq( a, b ){ return a.kind === b.kind && a.onHandle === b.onHandle; }; + let element = { kind, onHandle }; + let index = _.longRightIndex( handlers, element, eq ); + + if( !( index >= 0 ) ) + return; + + let result = handlers[ index ]; + result.index = index; + + return result; +} + +// + +function _eventHandlerDescriptorByHandler( onHandle ) +{ + let self = this; + + _.assert( _.routineIs( onHandle ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + let handlers = self._eventHandler.descriptors; + if( !handlers ) + return; + + for( let h in handlers ) + { + + let index = _.longRightIndex( handlers[ h ], { onHandle }, ( a, b ) => a.onHandle === b.onHandle ); + + if( index >= 0 ) + { + handlers[ h ][ index ].index = index; + return handlers[ h ][ index ]; + } + + } + +} + +// + +function _eventHandlerDescriptorsByKind( kind ) +{ + let self = this; + + _.assert( _.object.isBasic( self._eventHandler ) ); + + // if( !self._eventHandler.descriptors ) + // debugger; + + let handlers = self._eventHandler.descriptors; + handlers = handlers[ kind ] = handlers[ kind ] || []; + + return handlers; +} + +// + +function _eventHandlerDescriptorsAll() +{ + let self = this; + let result = []; + + for( let d in self._eventHandler.descriptors ) + { + let descriptor = self._eventHandler.descriptors[ d ]; + + result.push( descriptor ); + + } + + return result; +} + +// + +function eventHandlerDescriptorsFilter( filter ) +{ + let self = this; + let handlers = + ( + filter.kind ? self._eventHandlerDescriptorsByKind( filter.kind ) : self._eventHandlerDescriptorsAll( filter.kind ) + ); + + if( _.object.isBasic( filter ) ) + _.map.assertHasOnly( filter, eventHandlerDescriptorsFilter.defaults ); + + let result = _.filter_( null, handlers, filter ); + +} + +eventHandlerDescriptorsFilter.defaults = +{ + kind : null, + onHandle : null, + owner : null, +} + +// -- +// proxy +// -- + +function eventProxyTo( dstPrototype, rename ) +{ + let self = this; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.object.isBasic( dstPrototype ) || _.arrayIs( dstPrototype ) ); + _.assert( _.mapIs( rename ) || _.strIs( rename ) ); + + if( _.arrayIs( dstPrototype ) ) + { + for( let d = 0 ; d < dstPrototype.length ; d++ ) + self.eventProxyTo( dstPrototype[ d ], rename ); + return self; + } + + /* */ + + _.assert( _.routineIs( dstPrototype.eventGive ) ); + _.assert( _.routineIs( dstPrototype._eventGive ) ); + + if( _.strIs( rename ) ) + { + let r = Object.create( null ); + r[ rename ] = rename; + rename = r; + } + + /* */ + + for( let r in rename ) ( function() + { + let name = r; + _.assert( rename[ r ] && _.strIs( rename[ r ] ), 'eventProxyTo :', 'Expects name as string' ); + + let descriptor = + { + kind : r, + onHandle : function( event, o ) + { + if( name !== rename[ name ] ) + { + event = _.props.extend( null, event ); + event.kind = rename[ name ]; + } + return dstPrototype._eventGive( event, o ); + }, + owner : dstPrototype, + proxy : 1, + appending : 1, + } + + self._eventHandlerRegister( descriptor ); + + })(); + + return self; +} + +// + +function eventProxyFrom( src, rename ) +{ + let self = this; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.arrayIs( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + self.eventProxyFrom( src[ s ], rename ); + return self; + } + + return src.eventProxyTo( self, rename ); +} + +// -- +// relations +// -- + +let Groups = +{ + Events : 'Events', +} + +let Composes = +{ +} + +let Restricts = +{ + + eventVerbosity : 0, + _eventHandler : _.define.own( {} ), + +} + +let Statics = +{ + + strictEventHandling : 1, + +} + +let Events = +{ + init : 'init', + finit : 'finit', +} + +let Forbids = +{ + _eventHandlers : '_eventHandlers', + _eventHandlerOwners : '_eventHandlerOwners', + _eventHandlerDescriptors : '_eventHandlerDescriptors', +} + +// -- +// declaration +// -- + +let Supplement = +{ + + // register + + _eventHandlerInit, + _eventHandlerFinit, + + eventReport, + + eventHandlerPrepend, + eventHandlerAppend, + addEventListener : eventHandlerAppend, + on : eventHandlerAppend, + + eventHandlerRegisterProvisional, + provisional : eventHandlerRegisterProvisional, + + eventHandlerRegisterOneTime, + once : eventHandlerRegisterOneTime, + + eventHandlerRegisterEclipse, + eclipse : eventHandlerRegisterEclipse, + + _eventHandlerRegister, + + // unregister + + removeListener : eventHandlerRemove, + removeEventListener : eventHandlerRemove, + off : eventHandlerRemove, + eventHandlerRemove, + _eventHandlerRemove, + + eventHandlerRemoveByKindAndOwner, + + // handle + + dispatchEvent : eventGive, + emit : eventGive, + eventGive, + eventHandleUntil, + eventHandleSingle, + + _eventGive, + + eventWaitFor, + + // get + + _eventHandlerDescriptorByKindAndOwner, + _eventHandlerDescriptorByKindAndHandler, + _eventHandlerDescriptorByHandler, + _eventHandlerDescriptorsByKind, + _eventHandlerDescriptorsAll, + eventHandlerDescriptorsFilter, + + // proxy + + eventProxyTo, + eventProxyFrom, + + // relations + + Groups, + Composes, + Restricts, + Statics, + Events, + Forbids, + +} + +// + +let Functors = +{ + + init, + finit, + +} + +// + +_.classDeclare +({ + cls : Self, + supplement : Supplement, + onMixinApply, + functors : Functors, + withMixin : true, + withClass : true, +}); + +_.assert( _.mapIs( _.DefaultFieldsGroups ) ); + +// -- +// export +// -- + +_global_[ Self.name ] = _[ Self.shortName ] = Self; + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wEventHandler/proto/wtools/abase/l7_mixin/EventHandler.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wEventHandler/proto/wtools/abase/l7_mixin' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, EventHandler_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file EventHandler_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wLogger */ ( function wLogger() { function wLogger_naked() { +module.exports = require( '../wtools/abase/l9/logger/entry/Logger.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wLogger', 'wlogger' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/node_modules/wLogger' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wLogger_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wLogger */ })(); + +/* */ /* begin of file Logger_s */ ( function Logger_s() { function Logger_s_naked() { ( function _Logger_s_( ) +{ + +'use strict'; + +/** + * Class to log data consistently which supports colorful formatting, verbosity control, chaining, combining several loggers/consoles into logging network. Logger provides 10 levels of verbosity [ 0,9 ] any value beyond clamped and multiple approaches to control verbosity. Logger may use console/stream/process/file as input or output. Unlike alternatives, colorful formatting is cross-platform and works similarly in the browser and on the server side. Use the module to make your diagnostic code working on any platform you work with and to been able to redirect your output to/from any destination/source. + @module Tools/base/Logger +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../include/Mid.s' ) + module[ 'exports' ] = _global_.wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/entry/Logger.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/entry' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Logger_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Logger_s */ })(); + +/* */ /* begin of file Basic_s */ ( function Basic_s() { function Basic_s_naked() { ( function _Basic_s_( ) +{ + +'use strict'; + +/* Logger */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../../node_modules/Tools' ); + + _.include( 'wCopyable' ); + _.include( 'wStringer' ); + _.include( 'wStringsExtra' ); + _.include( 'wEventHandler' ); + + _.include( 'wColor256' ); /* qqq : make the depdendeny optional */ + + module[ 'exports' ] = _global_.wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/include/Basic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Basic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Basic_s */ })(); + +/* */ /* begin of file Mid_s */ ( function Mid_s() { function Mid_s_naked() { ( function _Mid_s_() +{ + +'use strict'; + +/* Logger */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( './Basic.s' ); + + require( '../l1/LoggerBasic.s' ); + + require( '../l3/Chainer.s' ); + require( '../l3/ChainingMixin.s' ); + require( '../l3/ColoredMixin.s' ); + require( '../l3/LoggerMid.s' ); + + // require( '../l5/LoggerTop.s' ); + require( '../l5/Logger.s' ); + + require( '../l7/LoggerPrime.s' ); + require( '../l7/ToLayeredHtml.s' ); + require( '../l7/ToString.s' ); + + module[ 'exports' ] = _global_.wTools; +} + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/include/Mid.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Mid_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Mid_s */ })(); + +/* */ /* begin of file LoggerBasic_s */ ( function LoggerBasic_s() { function LoggerBasic_s_naked() { (function _LoggerBasic_s_() +{ + +'use strict'; + +/** + * @classdesc Describes basic abilities of the printer: input transformation, verbosity level change. + * @class wLoggerBasic + * @namespace Tools + * @module Tools/base/Logger + */ + +const _global = _global_; +const _ = _global_.wTools; +const Parent = null; +const Self = wLoggerBasic; +function wLoggerBasic( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'LoggerBasic'; + +// -- +// inter +// -- + +function init( o ) +{ + let self = this; + + _.workpiece.initFields( self ); + + if( self[ chainerSymbol ] === undefined ) + self[ chainerSymbol ] = null; + + Object.preventExtensions( self ); + + if( o ) + self.copy( o ); + + return self; +} + +// -- +// transform +// -- + +function transform_head( routine, args ) +{ + let self = this; + let o = args[ 0 ]; + + _.assert( args.length === 1 ); + _.assert( arguments.length === 2 ); + _.map.assertHasAll( o, routine.defaults ); + + o.output = null; + o.discarding = false; + + if( o.originalInput === undefined || o.originalInput === null ) + o.originalInput = o.input; + if( o.joinedInput === undefined || o.joinedInput === null ) + o.joinedInput = self._strConcat( o.input ); + + return o; +} + +function transform_body( o ) +{ + let self = this; + + // _.map.assertHasAll( o, transform_body.defaults ); + + let o2 = self._transformBegin( o ); + _.assert( o2 === o ); + + if( o.discarding ) + return o; + + let o3 = self._transformAct( o ); + _.assert( o3 === o ); + + if( o.discarding ) + return o; + + _.assert( _.mapIs( o ) ); + _.assert( _.longIs( o.input ) ); + + let o4 = self._transformEnd( o ); + _.assert( o4 === o ); + + return o; +} + +transform_body.defaults = +{ + input : null, +} + +let transform = _.routine.uniteCloning_replaceByUnite( transform_head, transform_body ); + +// + +function _transformBegin( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.map.assertHasAll( o, self.transform.defaults ); + + o.output = null; + o.discarding = false; + + if( o.originalInput === undefined || o.originalInput === null ) + o.originalInput = o.input; + if( o.joinedInput === undefined || o.joinedInput === null ) + o.joinedInput = self._strConcat( o.input ); + + if( self.onTransformBegin ) + { + let o2 = self.onTransformBegin( o ); + _.assert( o2 === o, 'Callback::onTransformBegin should return the argument' ); + } + + if( o.discarding ) + return o; + + return o; +} + +// + +function _transformAct( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.mapIs( o ) ); + _.assert( _.longIs( o.input ) ); + + // o.outputSplitted; + // o._outputForPrinter = [ o.joinedInput ]; + // o._outputForTerminal = [ o.joinedInput ]; + + // /* !!! remove later */ + // + // _.accessor.forbid + // ({ + // object : o, + // names : + // { + // output : 'output', + // } + // }); + + return o; +} + +// + +function _transformEnd( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( self.onTransformEnd ) + self.onTransformEnd( o ); + + return o; +} + +// -- +// leveling +// -- + +/* qqq : poor description */ + +/** + * Increases value of logger level property by( dLevel ). + * + * If argument( dLevel ) is not specified, increases by one. + * + * @example + * let l = new _.Logger({ output : console }); + * l.up( 2 ); + * console.log( l.level ) + * //returns 2 + * @method up + * @throws { Exception } If more then one argument specified. + * @throws { Exception } If( dLevel ) is not a finite number. + * @class wLoggerBasic + * @namespace Tools + * @module Tools/base/Logger + */ + +function up( dLevel ) +{ + let self = this; + + if( dLevel === undefined ) + dLevel = 1; + + _.assert( arguments.length <= 1 ); + _.assert( isFinite( dLevel ) ); + + self.levelSet( self.level+dLevel ); + +} + +// + +/** + * Decreases value of logger level property by( dLevel ). + * If argument( dLevel ) is not specified, decreases by one. + * + * @example + * let l = new _.Logger({ output : console }); + * l.up( 2 ); + * l.down( 2 ); + * console.log( l.level ) + * //returns 0 + * @method down + * @throws { Exception } If more then one argument specified. + * @throws { Exception } If( dLevel ) is not a finite number. + * @class wLoggerBasic + * @namespace Tools + * @module Tools/base/Logger + */ + +/* qqq : poor description */ + +function down( dLevel ) +{ + let self = this; + + if( dLevel === undefined ) + dLevel = 1; + + _.assert( arguments.length <= 1 ); + _.assert( isFinite( dLevel ) ); + + self.levelSet( self.level-dLevel ); + +} + +// + +function levelSet( level ) +{ + let self = this; + + _.assert( level >= 0, 'levelSet : cant go below zero level to', level ); + _.assert( isFinite( level ) ); + + let dLevel = level - self[ levelSymbol ]; + + self[ levelSymbol ] = level ; + +} + +// -- +// etc +// -- + +function _writeAct( channelName, args ) +{ + let self = this; + + _.assert( arguments.length === 2 ); + _.assert( _.longHas( self.Channel, channelName ) ); + + let transformation = + { + input : args, + channelName, + } + + self.transform.head.call( self, self.transform, [ transformation ] ); + + if( self.onWriteBegin ) + self.onWriteBegin( transformation ); + + if( transformation.discarding ) + return transformation; + + self.transform( transformation ); + + if( self.onWriteEnd ) + self.onWriteEnd( transformation ); + + _.assert( transformation.output !== undefined ); + + return transformation; +} + +// + +function _strConcat( args ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( !_.strConcat ) + return _.entity.exportStringDiagnosticShallow/*exportStringSimple*/.apply( _, args ); + + let o2 = + { + linePrefix : self._prefix, + linePostfix : self._postfix, + onToStr, + } + + let result = _.strConcat( args, o2 ); + + return result; + + function onToStr( src, op ) + { + if( _.errIs( src ) && _.color ) + { + src = _.err( src ); + let result = src.stack; + result = _.ct.format( result, 'negative' ); + return result; + } + return _.entity.exportString( src, op.optionsForToStr ); + } +} + +// + +function Init() +{ + let cls = this; + + _.assert( cls.Channel.length > 0 ); + + for( let i = 0 ; i < cls.Channel.length ; i++ ) + channelDeclare( cls.Channel[ i ] ); + + function channelDeclare( channel ) + { + let r = + { + [ channel ] : function() + { + this._writeAct( channel, arguments ); + } + } + cls.prototype[ channel ] = r[ channel ]; + } + +} + +// -- +// relations +// -- + +let levelSymbol = Symbol.for( 'level' ); +let chainerSymbol = Symbol.for( 'chainer' ); + +let Channel = +[ + 'log', + 'error', + 'info', + 'warn', + 'debug' +]; + +let Composes = +{ + + name : '', + level : 0, + + onWriteBegin : null, + onWriteEnd : null, + + onTransformBegin : null, + onTransformEnd : null, + +} + +let Aggregates = +{ +} + +let Associates = +{ +} + +let Accessors = +{ + level : 'level', +} + +let Statics = +{ + MetaType : 'Printer', + Channel, + Init, +} + +// -- +// declare +// -- + +let Proto = +{ + + // routine + + init, + + // transform + + transform, + _transformBegin, + _transformAct, + _transformEnd, + + // leveling + + up, + down, + levelSet, + + // etc + + _writeAct, + _strConcat, + + // relations + + Composes, + Aggregates, + Associates, + Accessors, + Statics, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); + +_.Copyable.mixin( Self ); +Self.Init(); + +// -- +// export +// -- + +_[ Self.shortName ] = Self; +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l1/LoggerBasic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, LoggerBasic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file LoggerBasic_s */ })(); + +/* */ /* begin of file Chainer_s */ ( function Chainer_s() { function Chainer_s_naked() { (function _Chainer_s_() +{ + +'use strict'; + +/** + * @classdesc Encapsulates chainability of printers, loggers and consoles. Use it to construct a chain. + @class wChainer + @namespace Tools + @module Tools/base/Logger + */ + +const _global = _global_; +const _ = _global_.wTools; +const Parent = null; +const Self = wChainer; +function wChainer( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'Chainer'; + +// -- +// inter +// -- + +function init( o ) +{ + let self = this; + + _.workpiece.initFields( self ); + + Object.preventExtensions( self ); + + if( o ) + self.copy( o ); + + return self; +} + +// + +function finit() +{ + let self = this; + self.unchainEverything(); + _.Copyable.prototype.finit.call( self ); +} + +// + +function _chain( o ) +{ + let self = this; + let result = 1; + + o = _.routine.options_( self._chain, arguments ); + + if( self._chainDescriptorLike( o.outputPrinter ) ) + o.outputPrinter = o.outputPrinter.outputPrinter; + if( self._chainDescriptorLike( o.inputPrinter ) ) + o.inputPrinter = o.inputPrinter.inputPrinter; + + _.assert( arguments.length === 1 ); + _.assert( _.printerLike( o.outputPrinter ) || _.argumentsArray.like( o.outputPrinter ) || _.streamIs( o.outputPrinter ) ); + _.assert( _.printerLike( o.inputPrinter ) || _.argumentsArray.like( o.inputPrinter ) || _.streamIs( o.inputPrinter ) ); + _.assert( _.longHas( _.PrinterChainingMixin.Combining, o.outputCombining ), () => 'unknown outputCombining mode ' + _.strQuote( o.outputCombining ) ); + _.assert( _.longHas( _.PrinterChainingMixin.Combining, o.inputCombining ), () => 'unknown inputCombining mode ' + _.strQuote( o.inputCombining ) ); + + /* */ + + if( _.printerLike( o.inputPrinter ) && o.inputPrinter[ chainerSymbol ] ) + if( o.inputPrinter[ chainerSymbol ].outputs && o.inputPrinter[ chainerSymbol ].outputs.length ) + { + if( o.inputCombining === 'supplement' ) + { + result = 0; + return result; + } + else if( o.inputCombining === 'rewrite' ) + { + o.inputPrinter[ chainerSymbol ].outputUnchain(); + } + } + + /* */ + + if( _.printerLike( o.outputPrinter ) && o.outputPrinter[ chainerSymbol ] ) + if( o.outputPrinter[ chainerSymbol ].inputs && o.outputPrinter[ chainerSymbol ].inputs.length ) + { + if( o.outputCombining === 'supplement' ) + { + result = 0; + return result; + } + else if( o.outputCombining === 'rewrite' ) + { + o.outputPrinter[ chainerSymbol ].inputUnchain(); + } + } + + /* */ + + if( _.argumentsArray.like( o.outputPrinter ) ) + { + result = 0; + + o.outputPrinter.forEach( ( outputPrinter ) => + { + let o2 = _.props.extend( null, o ); + o2.outputPrinter = outputPrinter; + + if( self._chainDescriptorLike( outputPrinter ) ) + { + o2.originalOutput = outputPrinter.originalOutput; + o2.exclusiveOutput = outputPrinter.exclusiveOutput; + } + + result += self._chain( o2 ); + }); + + return result; + } + + /* */ + + if( _.argumentsArray.like( o.inputPrinter ) ) + { + result = 0; + + o.inputPrinter.forEach( ( inputPrinter ) => + { + let o2 = _.props.extend( null, o ); + o2.inputPrinter = inputPrinter; + + if( self._chainDescriptorLike( inputPrinter ) ) + { + o2.originalOutput = inputPrinter.originalOutput; + o2.exclusiveOutput = inputPrinter.exclusiveOutput; + } + + result += self._chain( o2 ); + }); + + return result; + } + + /* */ + + _.assert( !!o.outputPrinter, 'Expects {-o.outputPrinter-}' ); + _.assert( o.inputPrinter !== o.outputPrinter, 'Output to itself is not correct chaining' ); + + let cd = self._chainDescriptorMake( o ); + + let inputChainer = cd.inputPrinter[ chainerSymbol ] || self.MakeFor( cd.inputPrinter ); + let outputChainer = cd.outputPrinter[ chainerSymbol ] || self.MakeFor( cd.outputPrinter ); + + /* output check */ + + if( Config.debug ) + if( inputChainer.hasOutputClose( o.outputPrinter ) ) + _.assert( 0, () => _.strConcat([ 'inputPrinter', _.entity.exportStringDiagnosticShallow( o.inputPrinter ), o.inputPrinter.name, 'already has outputPrinter', _.entity.exportStringDiagnosticShallow( o.outputPrinter ), 'in outputs' ] ) ); + + /* input check */ + + if( Config.debug ) + if( !o.originalOutput ) + if( inputChainer.hasInputClose( o.outputPrinter ) ) + _.assert( 0, () => _.strConcat([ 'Close loop, inputPrinter', _.entity.exportStringDiagnosticShallow( o.inputPrinter ), 'to outputPrinter', _.entity.exportStringDiagnosticShallow( o.outputPrinter ) ]) ); + + /* + no need to check inputs if chaining is originalOutput + */ + + if( Config.debug ) + if( !o.originalOutput ) + if( inputChainer.hasInputDeep( o.outputPrinter ) ) + _.assert( 0, () => _.strConcat([ 'Deep loop, inputPrinter', _.entity.exportStringDiagnosticShallow( o.inputPrinter ), 'to outputPrinter', _.entity.exportStringDiagnosticShallow( o.outputPrinter ) ]) ); + + if( cd.outputCombining === 'prepend' ) + { + _.arrayPrependOnceStrictly( outputChainer.inputs, cd ); + } + else + { + _.arrayAppendOnceStrictly( outputChainer.inputs, cd ); + } + + if( cd.inputCombining === 'prepend' ) + { + _.arrayPrependOnceStrictly( inputChainer.outputs, cd ); + } + else + { + _.arrayAppendOnceStrictly( inputChainer.outputs, cd ); + } + + /**/ + + if( _.streamIs( cd.outputPrinter ) ) + { + inputChainer._outputToStream( cd ); + } + else if( _.consoleIs( cd.outputPrinter ) ) + { + inputChainer._outputToConsole( cd ); + } + + if( _.streamIs( cd.inputPrinter ) ) + { + outputChainer._inputFromStream( cd ); + } + else if( _.consoleIs( cd.inputPrinter ) ) + { + outputChainer._inputFromConsole( cd ); + } + + /* */ + + if( cd.originalOutput ) + { + outputChainer.hasOriginalOutputs = +1; + } + + if( cd.exclusiveOutput ) + { + _.assert( !inputChainer.exclusiveOutputPrinter, 'console is already excluded by printer', _.entity.exportStringDiagnosticShallow( inputChainer.exclusiveOutputPrinter ) ); + inputChainer.exclusiveOutputPrinter = o.outputPrinter; + } + + return result; +} + +_chain.defaults = +{ + outputPrinter : null, + inputPrinter : null, + outputCombining : 'append', + inputCombining : 'append', + originalOutput : 0, + exclusiveOutput : 0, +} + +// + +function _inputFromConsole( cd ) +{ + let self = this; + let inputChainer = cd.inputPrinter[ chainerSymbol ]; + + _.assert( arguments.length === 1 ); + _.assert( _.consoleIs( cd.inputPrinter ) ); + _.assert( cd.inputPrinter.outputs === undefined ); + _.assert( !cd.inputPrinter.isPrinter ); + _.assert( !!inputChainer ); + + self.Channel.forEach( ( channel, c ) => + { + _.assert( _.routineIs( inputChainer.readFromMap[ channel ] ) ); + cd.inputPrinter[ channel ] = inputChainer.readFromMap[ channel ]; + }); + +} + +// + +function _outputToConsole( cd ) +{ + let self = this; + let outputChainer = cd.outputPrinter[ chainerSymbol ]; + + _.assert( arguments.length === 1 ); + _.assert( _.consoleIs( cd.outputPrinter ) ); + _.assert( cd.outputPrinter.outputs === undefined ); + _.assert( !cd.outputPrinter.isPrinter ); + _.assert( _.object.isBasic( outputChainer ) ); + + cd.write = Object.create( null ); + + self.Channel.forEach( ( channel, c ) => + { + cd.write[ channel ] = outputChainer.readFromMap[ channel ]; + }); + +} + +// + +function _outputToStream( cd ) +{ + let self = this; + let stream = cd.outputPrinter; + + _.assert( stream.writable && _.routineIs( stream._write ) && _.object.isBasic( stream._writableState ), 'Provided stream is not writable!.' ); + _.assert( cd.write === null ); + + cd.write = Object.create( null ); + + self.Channel.forEach( ( channel, c ) => + { + cd.write[ channel ] = function() + { + stream.write.apply( stream, arguments ); + } + }); + +} + +// + +function _inputFromStream( cd ) +{ + let self = this; + let outputChannel = 'log'; + let stream = cd.inputPrinter; + let outputPrinter = cd.outputPrinter; + + _.assert( stream.readable && _.routineIs( stream._read ) && _.object.isBasic( stream._readableState ), 'Provided stream is not readable!.' ); + _.assert( !cd.onDataHandler ); + + cd.onDataHandler = onDataHandler; + stream.on( 'data', cd.onDataHandler ); + + function onDataHandler( data ) + { + if( _.bufferAnyIs( data ) ) + data = _.bufferToStr( data ); + + // if( _.strEnds( data, '\n' ) ) + // data = _.strRemoveEnd( data, '\n' ); + + outputPrinter._writeAct( outputChannel, [ data ] ); + // outputPrinter[ outputChannel ].call( outputPrinter, data ); + } + +} + +// + +/** + * Adds new logger( output ) to output list. + * + * Each message from current logger will be transfered + * to each logger from that list. Supports several combining modes: 0, rewrite, supplement, append, prepend. + * If output already exists in the list and combining mode is not 'rewrite'. + * @returns True if new output is succesfully added, otherwise return false if output already exists and combining mode is not 'rewrite' + * or if list is not empty and combining mode is 'supplement'. + * + * @param { Object } output - Logger that must be added to list. + * @param { Object } o - Options. + * @param { Object } [ o.leveling=null ] - Controls logger leveling mode: 0, false or '' - logger uses it own leveling methods, + * 'delta' - chains together logger and output leveling methods. + * @param { Object } [ o.combining=null ] - Mode which controls how new output appears in list: + * 0, false or '' - combining is disabled; + * 'rewrite' - clears list before adding new output; + * 'append' - adds output to the end of list; + * 'prepend' - adds output at the beginning; + * 'supplement' - adds output if list is empty. + * + * @example + * let l = new _.Logger({ output : console }); + * l.outputTo( logger, { combining : 'rewrite' } ); //returns true + * logger._prefix = '--'; + * l.log( 'abc' );//logger prints '--abc' + * + * @example + * let l1 = new _.Logger({ output : console }); + * let l2 = new _.Logger({ output : console }); + * l1.outputTo( logger, { combining : 'rewrite' } ); + * l2.outputTo( l1, { combining : 'rewrite' } ); + * logger._prefix = '*'; + * logger._postfix = '*'; + * l2.log( 'msg from l2' );//logger prints '*msg from l2*' + * + * @example + * let l1 = new _.Logger({ output : console }); + * let l2 = new _.Logger({ output : console }); + * let l3 = new _.Logger({ output : console }); + * logger.outputTo( l1, { combining : 'rewrite' } ); + * logger.outputTo( l2, { combining : 'append' } ); + * logger.outputTo( l3, { combining : 'append' } ); + * l1._prefix = '*'; + * l2._prefix = '**'; + * l3._prefix = '***'; + * logger.log( 'msg from logger' ); + * //l1 prints '*msg from logger' + * //l2 prints '**msg from logger' + * //l3 prints '***msg from logger' + * + * @example + * let l1 = new _.Logger({ output : console }); + * l.outputTo( logger, { combining : 'rewrite', leveling : 'delta' } ); + * logger.up( 2 ); + * l.up( 1 ); + * logger.log( 'aa\nb' ); + * l.log( 'c\nd' ); + * //logger prints + * // ---aa + * // ---b + * // ----c + * // -----d + * + * @method outputTo + * @throws { Exception } If no arguments provided. + * @throws { Exception } If( output ) is not a Object or null. + * @throws { Exception } If specified combining mode is not allowed. + * @throws { Exception } If specified leveling mode is not allowed. + * @throws { Exception } If combining mode is disabled and output list has multiple elements. + * @class wChainer + * @namespace Tools + * @module Tools/base/Logger + * + */ + +function outputTo( output, o ) +{ + let self = this; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options_( self.outputTo, o || null ); + + let o2 = _.props.extend( null, o ); + o2.inputPrinter = self.printer; + o2.outputPrinter = output; + o2.inputCombining = o.combining; + delete o2.combining; + + return Self._chain( o2 ); +} + +outputTo.defaults = +{ + combining : 'append', + originalOutput : 0, +} + +// + +/** + * Adds current logger( self ) to output list of logger( input ). + * + * Logger( self ) will take each message from source( input ). + * If( input ) is not a Logger, write methods in( input ) will be replaced with methods from current logger( self ). + * @returns True if logger( self ) is succesfully added to source( input ) output list, otherwise returns false. + * + * @param { Object } input - Object that will be input for current logger. + * @param { Object } o - Options. + * @param { String } [ o.combining='rewrite' ] - Specifies combining mode for outputTo method @see {@link wTools.outputTo}. + * By default rewrites output list of( input ) object if it exists. + * + * @example + * logger.inputFrom( console ); + * logger._prefix = '*'; + * console.log( 'msg for logger' ); //logger prints '*msg for logger' + * + * @example + * let l = new _.Logger({ output : console }); + * logger.inputFrom( l ); + * logger._prefix = '*'; + * l.log( 'msg from logger' ); //logger prints '*msg from logger' + * + * @method inputFrom + * @throws { Exception } If no arguments provided. + * @throws { Exception } If( input ) is not a Object. + * @class wChainer + * @namespace Tools + * @module Tools/base/Logger + * + */ + +function inputFrom( input, o ) +{ + let self = this; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options_( self.outputTo, o || null ); + + let o2 = _.props.extend( null, o ); + o2.inputPrinter = input; + o2.outputPrinter = self.printer; + o2.outputCombining = o.combining; + delete o2.combining; + + return Self._chain( o2 ); +} + +var defaults = inputFrom.defaults = Object.create( null ); + +defaults.combining = 'append'; +defaults.exclusiveOutput = 0; + +// + +function inputsUnchainAll() +{ + let self = this; + let result = 0; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + self.inputs.forEach( ( input ) => + { + result += self.inputUnchain( input.inputPrinter ); + }); + + return result; +} + +// + +function outputsUnchainAll() +{ + let self = this; + let result = 0; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + self.inputs.forEach( ( input ) => + { + result += self.outputUnchain( input.inputPrinter ); + }); + + return result; +} + +// + +function _unchain( o ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + _.assert( _.printerLike( o.outputPrinter ) || _.streamIs( o.outputPrinter ) ); + _.assert( _.printerLike( o.inputPrinter ) || _.streamIs( o.inputPrinter ) ); + _.assert( o.inputPrinter !== o.outputPrinter ); + + let inputChainer = o.inputPrinter[ chainerSymbol ]; + let outputChainer = o.outputPrinter[ chainerSymbol ]; + + let cd1 = _.arrayRemovedElementOnceStrictly( inputChainer.outputs, o.outputPrinter, ( cd ) => cd.outputPrinter, ( e ) => e ); + let cd2 = _.arrayRemovedElementOnceStrictly( outputChainer.inputs, o.inputPrinter, ( cd ) => cd.inputPrinter, ( e ) => e ); + + _.assert( cd1 === cd2 ); + + if( _.streamIs( o.inputPrinter ) ) + { + _.assert( _.routineIs( cd1.onDataHandler ) ); + o.inputPrinter.removeListener( 'data', cd1.onDataHandler ); + _.assert( o.inputPrinter.listeners( 'data' ).indexOf( cd1.onDataHandler ) === -1 ); + } + + if( _.consoleIs( o.inputPrinter ) && !inputChainer.outputs.length ) + self._restoreOriginalWriteConsole( inputChainer ); + + self._chainDescriptorFree( cd1 ); + + if( cd1.exclusiveOutput ) + { + _.assert( inputChainer.exclusiveOutputPrinter === o.outputPrinter ) + inputChainer.exclusiveOutputPrinter = null; + } + + if( cd1.originalOutput ) + { + outputChainer.hasOriginalOutputs -= 1; + _.assert( outputChainer.hasOriginalOutputs >= 0 ); + } + + return 1; +} + +_unchain.defaults = +{ + inputPrinter : null, + outputPrinter : null, +} + +// + +function outputUnchain( output ) +{ + let self = this; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.printerLike( output ) || _.streamIs( output ) || output === undefined ); + + if( output === undefined ) + { + let result = 0; + for( let i = self.outputs.length - 1; i >= 0; i-- ) + { + result += self.outputUnchain( self.outputs[ i ].outputPrinter ); + } + + return result; + } + + return self._unchain({ inputPrinter : self.printer, outputPrinter : output }); +} + +// + +/** + * Removes current logger( self ) from output list of logger( input ). + * + * Logger( self ) will not be receiving any messages from source( input ). + * If( input ) is not a Logger, restores it original write methods. + * @returns True if logger( self ) is succesfully removed from source( input ) output list, otherwise returns false. + * + * @param { Object } input - Object that will not be longer an input for current logger( self ). + * + * @example + * logger.inputUnchain( console ); + * logger._prefix = '*'; + * console.log( 'msg for logger' ); //console prints 'msg for logger' + * + * @example + * let l = new _.Logger({ output : console }); + * logger.inputFrom( l, { combining : 'append' } ); + * logger._prefix = '*'; + * l.log( 'msg for logger' ) //logger prints '*msg for logger' + * logger.inputUnchain( l ); + * l.log( 'msg for logger' ) //l prints 'msg for logger' + * + * @method inputUnchain + * @throws { Exception } If no arguments provided. + * @throws { Exception } If( input ) is not a Object. + * @class wChainer + * @namespace Tools + * @module Tools/base/Logger + * + */ + +function inputUnchain( input ) +{ + let self = this; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.printerLike( input ) || _.streamIs( input ) || input === undefined ); + + if( input === undefined ) + { + let result = 0; + for( let i = self.inputs.length - 1; i >= 0; i-- ) + { + result += self.inputUnchain( self.inputs[ i ].inputPrinter ); + } + return result; + } + + return self._unchain({ inputPrinter : input, outputPrinter : self.printer }); +} + +inputUnchain.defaults = +{ + inputPrinter : null, + outputPrinter : null, +} + +// + +function unchainEverything() +{ + let self = this; + let result = 0; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + result += self.outputUnchain(); + result += self.inputUnchain(); + + return result; +} + +// + +function _restoreOriginalWriteConsole( chainer ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + _.assert( _.object.isBasic( chainer ) ); + _.assert( _.consoleIs( chainer.printer ) ); + _.assert( !chainer.outputs.length > 0, 'Can\'t restore original write methods when console has outputs' ); + + self.Channel.forEach( ( channel, c ) => + { + _.assert( _.routineIs( chainer.originalWriteMap[ channel ] ) ); + chainer.printer[ channel ] = chainer.originalWriteMap[ channel ]; + }); + +} + + +// -- +// +// -- + +function _chainDescriptorMake( o ) +{ + let self = this; + _.assert( arguments.length === 1 ); + let r = new ChainDescriptor(); + + let options = _.mapOnly_( null, o, self.ChainDescriptorFields ); + + Object.assign( r, self.ChainDescriptorFields ); + + /* !!! : remove it later */ + _.accessor.forbid + ({ + object : o, + names : + { + input : 'input', + output : 'output', + } + }); + + Object.preventExtensions( r ); + Object.assign( r, options ); + return r; +} + +// + +function _chainDescriptorFree( cd ) +{ + _.assert( arguments.length === 1 ); + cd.freed = 1; + Object.freeze( cd ); +} + +// + +function Get( printable ) +{ + _.assert( arguments.length === 1 ); + return printable[ chainerSymbol ]; +} + +// + +function MakeFor( printer ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + _.assert( _.printerLike( printer ) || _.streamIs( printer ) ); + _.assert( !printer[ chainerSymbol ] ); + + let chainer = new Self(); + chainer.printer = printer; + printer[ chainerSymbol ] = chainer; /* qqq xxx : instead of writing the field use HashMap */ + + if( _.streamIs( printer ) ) + return chainer; + + self.Channel.forEach( ( channel, c ) => + { + _.assert( _.routineIs( printer[ channel ] ), () => 'Console should have method ' + _.strQuote( channel ) ); + + if( _.consoleIs( printer ) ) + { + chainer.originalWriteMap[ channel ] = printer[ channel ]; + } + else chainer.originalWriteMap[ channel ] = function writeToChannelWithoutExclusion() + { + debugger; + return this._writeToChannelWithoutExclusion( channel, arguments ); + } + + if( _.consoleIs( printer ) ) + chainer.readFromMap[ channel ] = _.routineJoin( undefined, self._printerReadFromConsole, [ channel, printer ] ); + else + chainer.readFromMap[ channel ] = _.routineJoin( undefined, self._printerReadFromPrinter, [ channel ] ); + + }); + + return chainer; +} + +// + +function _printerReadFromConsole( channel, defaultConsole ) +{ + let result; + let console = this || defaultConsole; + + _.assert( !!console, `Expects context` ); + + let chainer = console[ chainerSymbol ]; + let cds = chainer.outputs; + let args = _.longSlice( arguments, 2 ); + + _.assert( _.arrayIs( cds ) ); + _.assert( _.routineIs( chainer.originalWriteMap[ channel ] ) ); + + if( chainer.exclusiveOutputPrinter ) + { + result = chainer.exclusiveOutputPrinter[ channel ].apply( chainer.exclusiveOutputPrinter, args ); + return result; + } + else + { + cds.forEach( ( cd ) => + { + _.assert( cd.inputPrinter === console ); + if( !chainer.exclusiveOutputPrinter || cd.originalOutput ) + cd.outputPrinter[ channel ].apply( cd.outputPrinter, args ); + }); + return chainer.originalWriteMap[ channel ].apply( console, args ); + } + +} + +// + +function _printerReadFromPrinter( channel ) +{ + let result; + let self = this; + let chainer = this[ chainerSymbol ]; + let cds = chainer.outputs; + let args = _.longSlice( arguments, 1 ); + + _.assert( 0, 'not tested' ); + /* xxx */ + + _.assert( _.arrayIs( cds ) ); + _.assert( _.routineIs( chainer.originalWriteMap[ channel ] ) ); + + if( chainer.exclusiveOutputPrinter ) + { + result = chainer.exclusiveOutputPrinter[ channel ].apply( chainer.exclusiveOutputPrinter, arguments ); + } + + if( chainer.exclusiveOutputPrinter ) + return result; + else + return chainer.originalWriteMap[ channel ].apply( self, arguments ); + +} + +// -- +// +// -- + +function _nameGet() +{ + let self = this; + return self.printer.name; +} + +// + +function _nameSet( src ) +{ + let self = this; + + if( src === null ) + return; + + if( !self.printer ) + return; + + self.printer.name = src +} + +// -- +// dichotomy +// -- + +function _hasInput( input, o ) +{ + let self = this; + + o = _.routine.options_( _hasInput, o || null ); + _.assert( _.mapIs( o ) ); + _.assert( _.printerLike( input ) || _.processIs( input ) || _.streamIs( input ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + // _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + // _.assert( _.mapIs( o ) ); + // _.assert( _.printerLike( input ) || _.processIs( input ) || _.streamIs( input ) ); + // _.routine.options_( _hasInput, o ); + + for( let d = 0 ; d < self.inputs.length ; d++ ) + { + if( self.inputs[ d ].inputPrinter === input ) + { + if( o.withoutOutputToOriginal && self.inputs[ d ].originalOutput ) + continue; + return true; + } + } + + if( o.deep ) + for( let d = 0 ; d < self.inputs.length ; d++ ) + { + let inputs = self.inputs[ d ].inputPrinter.inputs; + if( o.withoutOutputToOriginal && self.inputs[ d ].originalOutput ) + continue; + if( inputs && inputs.length ) + { + if( _hasInput.call( self.inputs[ d ].inputPrinter, input, o ) ) + return true; + } + } + + return false; +} + +_hasInput.defaults = +{ + deep : 0, + withoutOutputToOriginal : 1, +} + +// + +function hasInputClose( input ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + return self._hasInput( input, { deep : 0 } ); +} + +// + +function hasInputDeep( input ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + return self._hasInput( input, { deep : 1 } ); +} + +// + +function _hasOutput( output, o ) +{ + let self = this; + + o = _.routine.options_( _hasOutput, o || null ); + _.assert( _.mapIs( o ) ); + _.assert( _.printerLike( output ) || _.processIs( output ) || _.streamIs( output ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + for( let d = 0 ; d < self.outputs.length ; d++ ) + { + if( self.outputs[ d ].outputPrinter === output ) + { + if( o.withoutOutputToOriginal && self.outputs[ d ].originalOutput ) + continue; + return true; + } + } + + if( o.deep ) + for( let d = 0 ; d < self.outputs.length ; d++ ) + { + let outputs = self.outputs[ d ].outputPrinter.outputs; + if( o.withoutOutputToOriginal && self.outputs[ d ].originalOutput ) + continue; + if( outputs && outputs.length ) + { + if( _hasOutput.call( self.outputs[ d ].outputPrinter, output, o ) ) + return true; + } + } + + return false; +} + +_hasOutput.defaults = +{ + deep : 0, + withoutOutputToOriginal : 1, +} + +// + +function hasOutputClose( output ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + return self._hasOutput( output, { deep : 0 } ); +} + +// + +function hasOutputDeep( output ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + return self._hasOutput( output, { deep : 1 } ); +} + +function _chainDescriptorLike( src ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( src instanceof self.ChainDescriptor ) + { + return true; + } + else if( _.objectLike( src ) ) + { + return _.mapHasAll( src, self.ChainDescriptorFields ); + } + + return false; +} + +// -- +// fields +// -- + +let chainerSymbol = Symbol.for( 'chainer' ); + +/* xxx : use blueprint */ +function ChainDescriptor(){}; +ChainDescriptor.prototype = Object.create( null ); + +let ChainDescriptorFields = +{ + exclusiveOutput : 0, + originalOutput : 0, + inputPrinter : null, + outputPrinter : null, + inputCombining : null, + outputCombining : null, + freed : 0, + write : null, + onDataHandler : null +} + +let Combining = [ 'rewrite', 'supplement', 'append', 'prepend' ]; + +let Channel = _.LoggerBasic.Channel; +_.assert( Channel.length > 0 ); + +// -- +// relations +// -- + +let Composes = +{ + name : null, + hasOriginalOutputs : 0, +} + +let Aggregates = +{ +} + +let Associates = +{ + printer : null, + inputs : _.define.own( [] ), + outputs : _.define.own( [] ), + originalWriteMap : _.define.own( {} ), + readFromMap : _.define.own( {} ), + exclusiveOutputPrinter : null, +} + +let Restricts = +{ +} + +let Statics = +{ + + _chain, + + Get, + MakeFor, + _chainDescriptorMake, + _printerReadFromConsole, + _printerReadFromPrinter, + + ChainDescriptor, + ChainDescriptorFields, + + _chainDescriptorLike, + + Combining, + Channel, + +} + +let Forbids = +{ + chainDescriptors : 'chainDescriptors', +} + +let Accessors = +{ + name : 'name', +} + +// -- +// declare +// -- + +let Extension = +{ + + // inter + + init, + finit, + + _outputToConsole, + _inputFromConsole, + _outputToStream, + _inputFromStream, + + outputTo, + inputFrom, + + _unchain, + outputUnchain, + inputUnchain, + unchainEverything, + + _restoreOriginalWriteConsole, + + // + + _chainDescriptorMake, + _chainDescriptorFree, + MakeFor, + _printerReadFromConsole, + _printerReadFromPrinter, + + // + + _nameGet, + _nameSet, + + // dichotomy + + _hasInput, + hasInputClose, + hasInputDeep, + + _hasOutput, + hasOutputClose, + hasOutputDeep, + + _chainDescriptorLike, + + // relations + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + Forbids, + Accessors, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Extension, +}); + +_.Copyable.mixin( Self ); + +// -- +// export +// -- + +_[ Self.shortName ] = Self; +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l3/Chainer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Chainer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Chainer_s */ })(); + +/* */ /* begin of file ChainingMixin_s */ ( function ChainingMixin_s() { function ChainingMixin_s_naked() { (function _aChainingMixin_s_() +{ + +'use strict'; + +/* principles : + + Printer could input / output from / to non-printer objects. + Doing that printer preserves all fields of the object, but "chainerSymbol" field which got reference on chain decriptor. + Printer does not write / rewrite any fields of destination / source object, but "chainerSymbol" field. + +*/ + +/** + * @classdesc Extends printer with mechanism of message transfering between multiple inputs/outputs. + * @class wPrinterChainingMixin + * @namespace Tools + * @module Tools/base/Logger + */ + +const _global = _global_; +const _ = _global_.wTools; +const Parent = null; +const Self = wPrinterChainingMixin; +function wPrinterChainingMixin( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'PrinterChainingMixin'; + +// + +function onMixinEnd( mixinDescriptor, dstClass ) +{ + let dstPrototype = dstClass.prototype; + + _.assert( dstPrototype._writeToChannelWithoutExclusion === _writeToChannelWithoutExclusion ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.routineIs( dstClass ) ); + _.assert( _.routineIs( dstClass ) ); + + dstPrototype._initChainingMixin( mixinDescriptor ); + + _.assert( _.routineIs( Self.prototype._writeAct ) ); + _.assert( dstPrototype._writeAct === Self.prototype._writeAct ); + +} + +// + +function _initChainingMixin( mixinDescriptor ) +{ + let proto = this; + + _.assert( Object.hasOwnProperty.call( proto, 'constructor' ) ); + + proto.Channel.forEach( ( channel, c ) => + { + proto._initChainingMixinChannel( mixinDescriptor, channel ); + }); + +} + +// + +function _initChainingMixinChannel( mixinDescriptor, channel ) +{ + let proto = this; + + _.assert( Object.hasOwnProperty.call( proto, 'constructor' ) ) + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( channel ) ); + + /* */ + + proto[ channel ] = write; + proto[ channel + 'Up' ] = writeUp; + proto[ channel + 'Down' ] = writeDown; + proto[ channel + 'In' ] = writeIn; + + /* */ + + function write() + { + this._writeAct( channel, arguments ); + return this; + } + + /* */ + + function writeUp() + { + this._writeToChannelUp( channel, arguments ); + return this; + } + + /* */ + + function writeDown() + { + this._writeToChannelDown( channel, arguments ); + return this; + } + + /* */ + + function writeIn() + { + this._writeToChannelIn( channel, arguments ); + return this; + } + +} + +// + +function init( original ) +{ + + return function init() + { + let self = this; + + self[ chainerSymbol ] = self._chainerMakeFor( self ); + + let result = original.apply( self, arguments ); + + return result; + } + +} + +// + +function finit( original ) +{ + + return function finit() + { + let self = this; + + self.chainer.finit(); + + let result = original.apply( self, arguments ); + + return result; + } + +} + +// -- +// write +// -- + +function _writeAct( channelName, args ) +{ + let self = this; + let inputChainer = self[ chainerSymbol ]; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( channelName ) ); + _.assert( _.longIs( args ) ); + + if( inputChainer.exclusiveOutputPrinter ) + { + inputChainer.exclusiveOutputPrinter[ channelName ].apply( inputChainer.exclusiveOutputPrinter, args ); + return; + } + + return self._writeToChannelWithoutExclusion( channelName, args ); +} + +// + +function _writeToChannelWithoutExclusion( channelName, args ) +{ + let self = this; + + let transformation = self._transformationForm( channelName, args ); + + if( transformation === null ) + return; + + if( transformation.discarding ) + return transformation; + + self.outputs.forEach( ( chainLink ) => + { + let outputChainer = chainLink.outputPrinter[ chainerSymbol ]; + + transformation.chainLink = chainLink; + let transformation2 = self.transform( transformation ); + _.assert( transformation === transformation2 ); + + if( transformation.discarding ) + return; + + let outputData = transformation.output; + _.assert( _.longIs( outputData ) ); + + if( chainLink.originalOutput ) + { + return outputChainer.originalWriteMap[ channelName ].apply( chainLink.outputPrinter, outputData ); + } + + if( chainLink.write && chainLink.write[ channelName ] ) + { + chainLink.write[ channelName ].apply( chainLink.outputPrinter, outputData ); + } + else + { + _.assert( _.routineIs( chainLink.outputPrinter[ channelName ] ) ); + chainLink.outputPrinter[ channelName ].apply( chainLink.outputPrinter, outputData ); + /* xxx : use _writeAct here */ + } + + }); + + if( self.onWriteEnd ) + self.onWriteEnd( transformation ); + + return transformation; +} + +// + +function _transformationForm( channelName, args ) +{ + let self = this; + let inputChainer = self[ chainerSymbol ]; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( channelName ) ); + _.assert( _.longIs( args ) ); + + args = _.filter_( null, args, ( a ) => a ); + if( !args.length ) + return null; + + let transformation = + { + input : args, + channelName, + } + + /* xxx ; Yevhen : onWriteBegin callback is not called, uncommented to fix */ + self.transform.head.call( self, self.transform, [ transformation ] ); + if( self.onWriteBegin ) + self.onWriteBegin( transformation ); + + return transformation; +} + +// + +function write() +{ + let self = this; + + self._writeAct( channelName, arguments ); + + return self; +} + +// + +function _writeToChannelUp( channelName, args ) +{ + let self = this; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( channelName ) ); + _.assert( _.longIs( args ) ); + + self.up(); + + self.begin( 'head' ); + self._writeAct( channelName, args ); + self.end( 'head' ); + +} + +// + +function _writeToChannelDown( channelName, args ) +{ + let self = this; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( channelName ) ); + _.assert( _.longIs( args ) ); + + self.begin( 'tail' ); + self._writeAct( channelName, args ); + self.end( 'tail' ); + + self.down(); + +} + +// + +function _writeToChannelIn( channelName, args ) +{ + let self = this; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( channelName ) ); + _.assert( _.longIs( args ) ); + _.assert( args.length === 2 ); + _.assert( _.strIs( args[ 0 ] ) ); + + let tag = Object.create( null ); + tag[ args[ 0 ] ] = args[ 1 ]; + + self.begin( tag ); + self._writeAct( channelName, [ args[ 1 ] ] ); + self.end( tag ); + +} + +// -- +// +// -- + +/** + * Adds new logger( output ) to output list. + * + * Each message from current logger will be transfered + * to each logger from that list. Supports several combining modes: 0, rewrite, supplement, append, prepend. + * If output already exists in the list and combining mode is not 'rewrite'. + * @returns True if new output is succesfully added, otherwise return false if output already exists and combining mode is not 'rewrite' + * or if list is not empty and combining mode is 'supplement'. + * + * @param { Object } output - Logger that must be added to list. + * @param { Object } o - Options. + * @param { Object } [ o.leveling=null ] - Controls logger leveling mode: 0, false or '' - logger uses it own leveling methods, + * 'delta' - chains together logger and output leveling methods. + * @param { Object } [ o.combining=null ] - Mode which controls how new output appears in list: + * 0, false or '' - combining is disabled; + * 'rewrite' - clears list before adding new output; + * 'append' - adds output to the end of list; + * 'prepend' - adds output at the beginning; + * 'supplement' - adds output if list is empty. + * + * @example + * let l = new _.Logger({ output : console }); + * l.outputTo( logger, { combining : 'rewrite' } ); //returns true + * logger._prefix = '--'; + * l.log( 'abc' );//logger prints '--abc' + * + * @example + * let l1 = new _.Logger({ output : console }); + * let l2 = new _.Logger({ output : console }); + * l1.outputTo( logger, { combining : 'rewrite' } ); + * l2.outputTo( l1, { combining : 'rewrite' } ); + * logger._prefix = '*'; + * logger._postfix = '*'; + * l2.log( 'msg from l2' );//logger prints '*msg from l2*' + * + * @example + * let l1 = new _.Logger({ output : console }); + * let l2 = new _.Logger({ output : console }); + * let l3 = new _.Logger({ output : console }); + * logger.outputTo( l1, { combining : 'rewrite' } ); + * logger.outputTo( l2, { combining : 'append' } ); + * logger.outputTo( l3, { combining : 'append' } ); + * l1._prefix = '*'; + * l2._prefix = '**'; + * l3._prefix = '***'; + * logger.log( 'msg from logger' ); + * //l1 prints '*msg from logger' + * //l2 prints '**msg from logger' + * //l3 prints '***msg from logger' + * + * @example + * let l1 = new _.Logger({ output : console }); + * l.outputTo( logger, { combining : 'rewrite', leveling : 'delta' } ); + * logger.up( 2 ); + * l.up( 1 ); + * logger.log( 'aa\nb' ); + * l.log( 'c\nd' ); + * //logger prints + * // ---aa + * // ---b + * // ----c + * // -----d + * + * @method outputTo + * @throws { Exception } If no arguments provided. + * @throws { Exception } If( output ) is not a Object or null. + * @throws { Exception } If specified combining mode is not allowed. + * @throws { Exception } If specified leveling mode is not allowed. + * @throws { Exception } If combining mode is disabled and output list has multiple elements. + * @class wPrinterChainingMixin + * @namespace Tools + * @module Tools/base/Logger + * + */ + +function outputTo( output, o ) +{ + let self = this; + + o = _.routine.options( self.outputTo, o || null ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + let o2 = _.props.extend( null, o ); + o2.inputPrinter = self; + o2.outputPrinter = output; + o2.inputCombining = o.combining; + delete o2.combining; + + return _.Chainer._chain( o2 ); +} + +var defaults = outputTo.defaults = Object.create( null ); + +defaults.combining = 'append'; +defaults.exclusiveOutput = 0; +defaults.originalOutput = 0; + +// + +/** + * Removes output( output ) from output list if it exists. + * + * Removed target will not be receiving any messages from current logger. + * @returns True if output is succesfully removed from the list, otherwise returns false. + * + * @param { Object } output - Logger that must be deleted from output list. + * + * @example + * let l1 = new _.Logger({ output : console }); + * let l2 = new _.Logger({ output : console }); + * let l3 = new _.Logger({ output : console }); + * logger.outputTo( l1, { combining : 'rewrite' } ); + * logger.outputTo( l2, { combining : 'append' } ); + * logger.outputTo( l3, { combining : 'append' } ); + * l1._prefix = '*'; + * l2._prefix = '**'; + * l3._prefix = '***'; + * + * logger.outputUnchain( l1 ); //returns true + * logger.outputUnchain( l1 ); //returns false because l1 not exists in the list anymore + * logger.log( 'msg from logger' ); + * //l2 prints '**msg from logger' + * //l3 prints '***msg from logger' + * + * @method outputUnchain + * @throws { Exception } If no arguments provided. + * @throws { Exception } If( output ) is not a Object. + * @throws { Exception } If outputs list is empty. + * @class wPrinterChainingMixin + * @namespace Tools + * @module Tools/base/Logger + * + */ + +/* qqq : should return number */ + +function outputUnchain( output ) +{ + let self = this; + let inputChainer = self[ chainerSymbol ]; + + if( !inputChainer ) + return; + + _.assert( !!inputChainer ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + inputChainer.outputUnchain( output ); +} + +// + +/** + * Adds current logger( self ) to output list of logger( input ). + * + * Logger( self ) will take each message from source( input ). + * If( input ) is not a Logger, write methods in( input ) will be replaced with methods from current logger( self ). + * @returns True if logger( self ) is succesfully added to source( input ) output list, otherwise returns false. + * + * @param { Object } input - Object that will be input for current logger. + * @param { Object } o - Options. + * @param { String } [ o.combining='rewrite' ] - Specifies combining mode for outputTo method @see {@link wTools.outputTo}. + * By default rewrites output list of( input ) object if it exists. + * + * @example + * logger.inputFrom( console ); + * logger._prefix = '*'; + * console.log( 'msg for logger' ); //logger prints '*msg for logger' + * + * @example + * let l = new _.Logger({ output : console }); + * logger.inputFrom( l ); + * logger._prefix = '*'; + * l.log( 'msg from logger' ); //logger prints '*msg from logger' + * + * @method inputFrom + * @throws { Exception } If no arguments provided. + * @throws { Exception } If( input ) is not a Object. + * @class wPrinterChainingMixin + * @namespace Tools + * @module Tools/base/Logger + * + */ + +function inputFrom( input, o ) +{ + let self = this; + + o = _.routine.options( self.inputFrom, o || null ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + let o2 = _.props.extend( null, o ); + o2.inputPrinter = input; + o2.outputPrinter = self; + o2.outputCombining = o.combining; + delete o2.combining; + + return _.Chainer._chain( o2 ); +} + +var defaults = inputFrom.defaults = Object.create( null ); + +defaults.combining = 'append'; +defaults.exclusiveOutput = 0; +defaults.originalOutput = 0; + +// + +/** + * Removes current logger( self ) from output list of logger( input ). + * + * Logger( self ) will not be receiving any messages from source( input ). + * If( input ) is not a Logger, restores it original write methods. + * @returns True if logger( self ) is succesfully removed from source( input ) output list, otherwise returns false. + * + * @param { Object } input - Object that will not be longer an input for current logger( self ). + * + * @example + * logger.inputUnchain( console ); + * logger._prefix = '*'; + * console.log( 'msg for logger' ); //console prints 'msg for logger' + * + * @example + * let l = new _.Logger({ output : console }); + * logger.inputFrom( l, { combining : 'append' } ); + * logger._prefix = '*'; + * l.log( 'msg for logger' ) //logger prints '*msg for logger' + * logger.inputUnchain( l ); + * l.log( 'msg for logger' ) //l prints 'msg for logger' + * + * @method inputUnchain + * @throws { Exception } If no arguments provided. + * @throws { Exception } If( input ) is not a Object. + * @class wPrinterChainingMixin + * @namespace Tools + * @module Tools/base/Logger + * + */ + +function inputUnchain( input ) +{ + let self = this; + let outputChainer = self[ chainerSymbol ]; + _.assert( arguments.length === 0 || arguments.length === 1 ); + return outputChainer.inputUnchain( input ); +} + +// + +function unchain() +{ + let self = this; + + self.inputUnchain(); + self.outputUnchain(); + +} + +// + +function ConsoleIsBarred( output ) +{ + let self = this; + + _.assert( _.consoleIs( output ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + let chainer = output[ chainerSymbol ] + if( !chainer ) + return false; + + return !!chainer.exclusiveOutputPrinter; +} + +// + +/* +qqq : extend test coverage, write doc. ask how +qqq : implement, test, doc method ConsoleBar +qqq : write test routine to bar, unbar, bar +qqq : write test routine to unbar, bar, unbar +*/ + +function ConsoleBar( o ) +{ + let self = this; + + o = _.routine.options( ConsoleBar, arguments ); + + /* */ + + if( o.on ) + { + + if( !o.barPrinter ) + o.barPrinter = new self.Self({ output : null, name : 'barPrinter' }); + // if( !o.outputPrinter && self.instanceIs() ) + // o.outputPrinter = self; + if( !o.outputPrinter ) + { + o.outputPrinter = new self.Self({ output : false, name : 'outputPrinter' }); + _.assert( o.outputPrinter.outputs.length === 0 ); + } + + if( o.verbose ) + { + o.outputPrinter.begin({ verbosity : 4 }); + o.outputPrinter.log( 'Barring console' ); + o.outputPrinter.end({ verbosity : 4 }); + } + + _.assert( !o.barPrinter.inputs.length ); + _.assert( !o.barPrinter.outputs.length ); + + o.outputPrinterHadOutputs = o.outputPrinter.outputs.slice(); + o.outputPrinter.outputUnchain(); + if( o.outputingToConsole ) + o.outputPrinter.outputTo( console, { originalOutput : 1, combining : 'rewrite' } ); + + o.barPrinter.permanentStyle = 'exclusiveOutput.neutral'; + o.barPrinter.inputFrom( console, { exclusiveOutput : 1 } ); + o.barPrinter.outputTo( o.outputPrinter ); + + console[ barSymbol ] = o; + + } + else + { + + let bar = console[ barSymbol ]; + + if( bar ) + { + if( !o.outputPrinter ) + o.outputPrinter = bar.outputPrinter; + if( !o.barPrinter ) + o.barPrinter = bar.barPrinter; + if( !o.outputPrinterHadOutputs ) + o.outputPrinterHadOutputs = bar.outputPrinterHadOutputs; + } + + _.assert( !!bar ); + _.assert( bar.barPrinter === o.barPrinter ); + _.assert( bar.outputPrinter === o.outputPrinter ); + _.assert( bar.outputPrinterHadOutputs === o.outputPrinterHadOutputs ); + + o.barPrinter.unchain(); + // if( o.outputPrinter.outputs.length ) + // debugger + if( o.outputPrinter.hasOutput( console, { withoutOutputToOriginal : 0, deep : 0 } ) ) + o.outputPrinter.outputUnchain( console ); + + _.assert( !!o.outputPrinterHadOutputs ); + + for( let t = 0 ; t < o.outputPrinterHadOutputs.length ; t++ ) + { + let outputOptions = o.outputPrinterHadOutputs[ t ]; + o.outputPrinter.outputTo( outputOptions.outputPrinter, _.mapOnly_( null, outputOptions, o.outputPrinter.outputTo.defaults ) ); + } + + o.outputPrinterHadOutputs = null; + delete console[ barSymbol ]; + + } + + /* + + exclusiveOutput ordinary originalOutput + console -> barPrinter -> outputPrinter -> console + ^ + | + others + + originalOutput link is not transitive, but terminating + so no cycle + + console -> barPrinter -> outputPrinter -> defLogger -> console + + */ + + return o; +} + +ConsoleBar.defaults = +{ + outputPrinter : null, + barPrinter : null, + outputPrinterHadOutputs : null, + outputingToConsole : 0, + on : 1, + verbose : 0, +} + +// + +function Chain( o ) +{ + _.assert( arguments.length === 1 ); + _.routine.options( Chain, o ) + _.assert( _.printerLike( o.inputPrinter ) || _.argumentsArray.like( o.inputPrinter ) ); + _.assert( _.printerLike( o.outputPrinter ) || _.argumentsArray.like( o.outputPrinter ) ); + + return _.Chainer._chain( o ); +} + +var defaults = Chain.defaults = Object.create( _.Chainer.prototype._chain.defaults ); + +// -- +// dichotomy +// -- + +function hasInput( input, o ) +{ + let self = this; + let chainer = self.chainer; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + + return chainer._hasInput( input, o ); +} + +// + +function hasInputClose( input ) +{ + let self = this; + let chainer = self.chainer; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + return chainer._hasInput( input, { deep : 0 } ); +} + +// + +function hasInputDeep( input ) +{ + let self = this; + let chainer = self.chainer; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + return chainer._hasInput( input, { deep : 1 } ); +} + +// + +function hasOutput( output, o ) +{ + let self = this; + let chainer = self.chainer; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + + return chainer._hasOutput( output, o ); +} + +// + +function hasOutputClose( output ) +{ + let self = this; + let chainer = self.chainer; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + return chainer._hasOutput( output, { deep : 0 } ); +} + +// + +function hasOutputDeep( output ) +{ + let self = this; + let chainer = self.chainer; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + return chainer._hasOutput( output, { deep : 1 } ); +} + +// -- +// etc +// -- + +function _outputSet( output ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( output ) + self.outputTo( output, { combining : 'rewrite' } ); + else + self.outputUnchain(); + +} + +// + +function _outputGet( output ) +{ + let self = this; + _.assert( _.arrayIs( self.outputs ) ); + return self.outputs.length ? self.outputs[ self.outputs.length-1 ].outputPrinter : null; +} + +// + +function _outputsSet( outputs ) +{ + let self = this; + _.assert( arguments.length === 1, 'Expects single argument' ); + self.outputTo( outputs, { combining : 'rewrite' } ); +} + +// + +function _outputsGet( outputs ) +{ + let self = this; + let chainer = self[ chainerSymbol ]; + _.assert( arguments.length === 0, 'Expects no arguments' ); + return chainer.outputs; +} + +// + +function _inputsGet() +{ + let self = this; + let chainer = self[ chainerSymbol ]; + return chainer.inputs; +} + +// + +function _inputsSet( inputs ) +{ + let self = this; + _.assert( arguments.length === 1, 'Expects single argument' ); + self.inputFrom( inputs, { combining : 'rewrite' } ); +} + +// + +function _chainerGet() +{ + let self = this; + return _.Chainer.Get( self ); +} + +// + +function _chainerMakeFor( printer ) +{ + let self = this; + _.assert( arguments.length === 1 ); + return _.Chainer.MakeFor( printer ); +} + +// -- +// fields +// -- + +let barSymbol = Symbol.for( 'bar' ); +let chainerSymbol = Symbol.for( 'chainer' ); +let levelSymbol = Symbol.for( 'level' ); + +let ChainDescriptor = _.Chainer.ChainDescriptor; +let Combining = _.Chainer.Combining; +let Channel = _.Chainer.Channel; + +let ChangeLevelMethods = +[ + 'up', + 'down', +]; + +// -- +// relations +// -- + +let Composes = +{ + + outputs : _.define.own( [] ), + inputs : _.define.own( [] ), + +} + +let Aggregates = +{ +} + +let Associates = +{ + + output : null, + +} + +let Restricts = +{ + isPrinter : 1, +} + +let Statics = +{ + + ConsoleBar, + ConsoleIsBarred, + Chain, + + // fields + + ChainDescriptor, + Combining, + Channel, + + ChangeLevelMethods, + unbarringConsoleOnError : 1, + +} + +let Forbids = +{ + format : 'format', + upAct : 'upAct', + downAct : 'downAct', +} + +let Accessors = +{ + output : 'output', + outputs : 'outputs', + inputs : 'inputs', + chainer : 'chainer', +} + +// -- +// declare +// -- + +let Functors = +{ + + init, + finit, + +} + +let Supplement = +{ + +} + +// + +let Extension = +{ + + // write + + _writeAct, + _writeToChannelWithoutExclusion, + _transformationForm, /* Yevhen : subroutine for `_writeToChannelWithoutExclusion` */ + _writeToChannelUp, + _writeToChannelDown, + _writeToChannelIn, + + // init + + _initChainingMixin, + _initChainingMixinChannel, + + // chaining + + outputTo, + + outputUnchain, + + inputFrom, + + inputUnchain, + + unchain, + + ConsoleBar, + ConsoleIsBarred, + + // dichotomy + + hasInput, + hasInputClose, + hasInputDeep, + + hasOutput, + hasOutputClose, + hasOutputDeep, + + // etc + + _outputSet, + _outputGet, + + _outputsSet, + _outputsGet, + + _inputsSet, + _inputsGet, + + _chainerGet, + _chainerMakeFor, + + // relations + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + Forbids, + Accessors, + +} + +// + +_.classDeclare +({ + cls : Self, + extend : Extension, + supplement : Supplement, + onMixinEnd, + functors : Functors, + withMixin : true, + withClass : true, +}); + +// -- +// export +// -- + +_[ Self.shortName ] = Self; + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l3/ChainingMixin.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ChainingMixin_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ChainingMixin_s */ })(); + +/* */ /* begin of file ColoredMixin_s */ ( function ColoredMixin_s() { function ColoredMixin_s_naked() { (function _aColoredMixin_s_() +{ + +'use strict'; + +/** + * @classdesc Extends printer with mechanism of message coloring. Works on server-side and in the browser. Supports colors stacking, output styling, ill colors and color collapse diagnosting. + * @class wPrinterColoredMixin + * @namespace Tools + * @module Tools/base/Logger + */ + +const _global = _global_; +const _ = _global_.wTools; +const Parent = null; +const Self = wPrinterColoredMixin; +function wPrinterColoredMixin( o ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 ); + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'PrinterColoredMixin'; + +_.assert( _.routineIs( _.strSplitInlined ) ); +// _.assert( _.routineIs( _.strSplitInlinedStereo_ ) ); + +// -- +// stack +// -- + +function _stackPush( layer, color ) +{ + let self = this; + + if( !self._colorsStack ) + self._colorsStack = { 'foreground' : [], 'background' : [] }; + + self._colorsStack[ layer ].push( color ); +} + +// + +function _stackPop( layer ) +{ + let self = this; + + return self._colorsStack[ layer ].pop(); +} + +// + +function _stackIsNotEmpty( layer ) +{ + let self = this; + + if( self._colorsStack && self._colorsStack[ layer ].length ) + return true; + + return false; +} + +// -- +// transform +// -- + +function _transformActHtml( o ) +{ + let self = this; + let result = ''; + let spanCount = 0; + let splitted = o._outputSplitted; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.mapIs( o ) ); + _.assert( _.arrayIs( o._outputSplitted ) ); + _.assert( !o._outputForTerminal ); + + let options = _.mapOnly_( null, o, _transformActHtml.defaults ); + _.routine.options_( _transformActHtml, options ); + + for( let i = 0; i < splitted.length; i++ ) + { + if( _.arrayIs( splitted[ i ] ) ) + { + let style = splitted[ i ][ 0 ]; + let color = splitted[ i ][ 1 ].trim(); + + if( color && color !== 'default' ) + { + color = _.color.rgbaFromTry( color ); + if( color ) + color = _.color.rgbaFrom({ src : color, colorMap : _.color.ColorMap }) + } + + if( style === 'foreground') + { + self.foregroundColor = color; + } + else if( style === 'background') + { + self.backgroundColor = color; + } + + let fg = self.foregroundColor; + let bg = self.backgroundColor; + + if( !fg || fg === 'default' ) + fg = null; + + if( !bg || bg === 'default' ) + bg = null; + + if( color === 'default' && spanCount ) + { + result += ``; + spanCount--; + } + else + { + let style = ''; + + if( options.compact ) + { + if( fg ) + style += `color:${ _.color.colorToRgbaHtml( fg ) };`; + + if( bg ) + style += `background:${ _.color.colorToRgbaHtml( bg ) };`; + } + else + { + fg = fg || 'transparent'; + bg = bg || 'transparent'; + style = `color:${ _.color.colorToRgbaHtml( fg ) };background:${ _.color.colorToRgbaHtml( bg ) };`; + } + + if( style.length ) + result += `<${options.tag} style='${style}'>`; + else + result += `<${options.tag}>`; + + spanCount++; + } + } + else + { + let text = _.strReplaceAll( splitted[ i ], '\n', '
' ); + + if( !options.compact && !spanCount ) + { + result += `<${options.tag}>${text}`; + } + else + result += text; + } + } + + _.assert( spanCount === 0 ); + + o._outputForTerminal = [ result ]; + return o; +} + +_transformActHtml.defaults = +{ + tag : 'span', + compact : true, +} + +// + +function _transformAct_nodejs( o ) +{ + let self = this; + let result = ''; + let splitted = o._outputSplitted; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.mapIs( o ) ); + _.assert( _.arrayIs( o._outputSplitted ) ); + _.assert( !o._outputForTerminal ); + + splitted.forEach( function( split ) + { + let output = !!_.color; + + if( _.arrayIs( split ) ) + { + self._directiveApply( split ); + if( output && self.outputRaw ) + output = 0; + if( output && self.outputGray && _.longHas( self.DirectiveColoring, split[ 0 ] ) ) + output = 0; + + if( !self.inputRaw && !self.outputRaw ) + if( split[ 0 ] === 'cls' ) + result += self._directiveClsApply( split[ 1 ].trim() ); + else if( split[ 0 ] === 'move' ) + result += self._directiveMoveApply( split[ 1 ].trim() ); + else if( split[ 0 ] === 'cll' ) + result += `\x1b[K`; + } + else + { + output = output && !self.outputRaw && !self.outputGray; + } + + let styling = !self.outputRaw; + + if( _.strIs( split ) ) + { + if( styling ) + { + if( self._resetStyle ) + { + result += `\x1b[0;0m` + self._resetStyle = false; + } + + if( self.underline ) + result += `\x1b[4m`; + } + + if( output ) + { + self._diagnoseColorCheck(); + + if( self.foregroundColor ) + result += `\x1b[${ self._rgbToCode_nodejs( self.foregroundColor ) }m`; + + if( self.backgroundColor ) + result += `\x1b[${ self._rgbToCode_nodejs( self.backgroundColor, true ) }m`; + } + + result += split; + + if( styling ) + { + if( self.underline ) + result += `\x1b[24m`; + } + + if( output ) + { + if( self.backgroundColor ) + result += `\x1b[49;0m`; + if( self.foregroundColor ) + result += `\x1b[39;0m`; + } + } + + }); + + o._outputForTerminal = [ result ]; + return o; +} + +// + +function _transformAct_browser( o ) +{ + let self = this; + let result = [ '' ]; + let splitted = o._outputSplitted; + let styled = false; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.mapIs( o ) ); + _.assert( _.arrayIs( o._outputSplitted ) ); + _.assert( !o._outputForTerminal ); + + splitted.forEach( function( split ) + { + let output = !!_.color; + + if( _.arrayIs( split ) ) + { + self._directiveApply( split ); + if( output && self.outputRaw ) + output = 0; + if( output && self.outputGray && _.longHas( self.DirectiveColoring, split[ 0 ] ) ) + output = 0; + + if( !self.inputRaw && !self.outputRaw ) + if( split[ 0 ] === 'cls' ) + { + if( _.routineIs( clear ) ) + clear(); + } + } + else + { + output = output && !self.outputRaw && !self.outputGray; + } + + let styling = !self.outputRaw; + + if( _.strIs( split ) ) + { + let foregroundColor = 'none'; + let backgroundColor = 'none'; + let textDecoration = 'none'; + + let style = []; + + if( styling ) + { + if( self._resetStyle ) + { + self._resetStyle = false; + styled = true; + } + + if( self.underline ) + { + textDecoration = 'underline'; + styled = true; + } + } + + /* qqq : make it working without _.color */ + + if( output ) + { + if( self.foregroundColor ) + { + foregroundColor = _.color.colorToRgbaHtml( self.foregroundColor); + styled = true; + } + + if( self.backgroundColor ) + { + backgroundColor = _.color.colorToRgbaHtml( self.backgroundColor); + styled = true; + } + } + + if( styled ) + { + result[ 0 ] += '%c'; + + style.push( `color:${ foregroundColor }` ); + style.push( `background:${ backgroundColor }` ) + style.push( `text-decoration:${ textDecoration }` ) + + result.push( style.join( ';' ) ); + } + + result[ 0 ] += split; + } + + }); + + o._outputForTerminal = result; + return o; +} + +// + +function _transformActWithoutColors( o ) +{ + let self = this; + let result = ''; + let splitted = o._outputSplitted; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.mapIs( o ) ); + _.assert( _.arrayIs( o._outputSplitted ) ); + _.assert( !o._outputForTerminal ); + + for( let i = 0 ; i < splitted.length ; i++ ) + { + if( _.strIs( splitted[ i ] ) ) + result += splitted[ i ]; + } + + o._outputForTerminal = [ result ]; + return o; +} + +// + +function _transformColorApply( o ) +{ + let self = this; + + _.assert( _.strIs( o.joinedInput ) ); + + /* xxx */ + + if( self.permanentStyle ) + { + o.joinedInput = _.ct.formatFinal( o.joinedInput, self.permanentStyle ); + } + + if( self.coloringConnotation ) + { + if( self.attributes.connotation === 'positive' ) + o.joinedInput = _.ct.formatFinal( o.joinedInput, 'positive' ); + else if( self.attributes.connotation === 'negative' ) + o.joinedInput = _.ct.formatFinal( o.joinedInput, 'negative' ); + } + + if( self.coloringHeadAndTail ) + if( self.attributes.head || self.attributes.tail ) + if( _.strStrip( o.joinedInput ) ) + { + let reserve = self.verbosityReserve(); + if( self.attributes.head && reserve > 1 ) + o.joinedInput = _.ct.formatFinal( o.joinedInput, 'head' ); + else if( self.attributes.tail && reserve > 1 ) + o.joinedInput = _.ct.formatFinal( o.joinedInput, 'tail' ); + } + +} + +// + +function _transformSplit( o ) +{ + let self = this; + let result = [ '' ]; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( o.joinedInput ) ); + _.assert( !o._outputSplitted ); + _.assert( !o._outputForTerminal ); + + if( self.raw || self.rawAll ) + { + o._outputSplitted = [ o.joinedInput ]; /* xxx */ + return; + } + + let splits = o._outputSplitted = self._split( o.joinedInput ); + + let inputRaw = self.inputRaw; + let inputGray = self.inputGray; + let outputRaw = self.outputRaw; + let outputGray = self.outputGray; + + splits.forEach( ( split, i ) => + { + + if( !_.arrayIs( split ) ) + return; + + let directive = split[ 0 ]; + let value = split[ 1 ]; + let input = true; + + if( directive === 'inputRaw' ) + inputRaw += _.boolFrom( value.trim() ) ? +1 : -1; + else if( inputRaw ) + input = false; + else if( inputGray && _.longHas( self.DirectiveColoring, directive ) ) + input = false; + + if( !input ) + { + split = '❮' + split[ 0 ] + ':' + split[ 1 ] + '❯'; + splits[ i ] = split; + return; + } + + if( directive === 'inputGray' ) + inputGray += _.boolFrom( value.trim() ) ? +1 : -1; + if( directive === 'outputRaw' ) + outputRaw += _.boolFrom( value.trim() ) ? +1 : -1; + if( directive === 'outputGray' ) + outputGray += _.boolFrom( value.trim() ) ? +1 : -1; + + }); + +} + +// + +/* qqq : implement please */ +function TransformCssStylingToDirectives( input ) +{ + //https://developers.google.com/web/tools/chrome-devtools/console/console-write#styling_console_output_with_css + + if( !_.strHas( input[ 0 ], '%c' ) ) + return input; + + let result = [ '' ]; + + let splitted = _.strSplitFast + ({ + src : input[ 0 ], + delimeter : '%c', + preservingEmpty : 0, + preservingDelimeters : 0 + }); + + splitted.forEach( ( chunk, i ) => + { + let styles = input[ i + 1 ]; + + if( styles ) + { + let splits = _.strSplitFast + ({ + src : styles, + delimeter : [ ';', ':' ], + preservingEmpty : 0, + preservingDelimeters : 0 + }); + + if( splits.length > 1 ) + for( let i = 0; i < splits.length; i += 2 ) + { + let key = _.strStrip( splits[ i ] ); + let value = _.strStrip( splits[ i + 1 ] ); + + if( value === 'none' ) + continue; + + if( key === 'color' ) + { + value = _.color.rgbaHtmlFrom( value ); + value = _.color.colorNameNearest( value ); + chunk = _.color.strFg( chunk, value ); + } + else if( key === 'background' ) + { + value = _.color.rgbaHtmlFrom( value ); + value = _.color.colorNameNearest( value ) + chunk = _.color.strBg( chunk, value ); + } + else if( key === 'text-decoration' ) + { + chunk = `❮${value} : true❯${chunk}❮${value} : false❯` + } + } + } + + result[ 0 ] += chunk; + }) + + if( !result[ 0 ] ) + return input; + + result.push( ... input.slice( splitted.length + 1 ) ); + + return result; +} + +// -- +// +// -- + +function _join( splitted ) +{ + let self = this; + _.assert( _.arrayIs( splitted ) ); + + let result = ''; + splitted.forEach( ( split, i ) => + { + if( _.strIs( split ) ) + result += split + else if( _.arrayIs( split ) ) + result += '❮' + split.join( ':' ) + '❯'; + else _.assert( 0 ); + }); + + return result; +} + +// + +function _split( src ) +{ + let self = this; + _.assert( _.strIs( src ) ); + let splitted = _.ct.parse + ({ + src, + onInlined : self._splitHandle.bind( self ), + // preservingEmpty : 0, + // stripping : 0, + }); + return splitted; +} + +// + +function _splitHandle( split ) +{ + let self = this; + let parts = split.split( ':' ); + if( parts.length === 2 ) + { + parts[ 0 ] = parts[ 0 ].trim(); + if( !_.longHas( self.Directive, parts[ 0 ] ) ) + return; + return parts; + } +} + +// + +function _directiveApply( directive ) +{ + let self = this; + let handled = 0; + let name = directive[ 0 ]; + let value = directive[ 1 ]; + + if( name === 'inputRaw' ) + { + self.inputRaw = _.boolFrom( value.trim() ); + return true; + } + + if( self.inputRaw ) + return; + + if( !self.inputGray ) + { + if( name === 'foreground' || name === 'fg' ) + { + self.foregroundColor = value; + return true; + } + else if( name === 'background' || name === 'bg' ) + { + self.backgroundColor = value; + return true; + } + } + + if( name === 'outputGray' ) + { + self.outputGray = _.boolFrom( value.trim() ); + return true; + } + else if( name === 'inputGray' ) + { + self.inputGray = _.boolFrom( value.trim() ); + return true; + } + else if( name === 'outputRaw' ) + { + self.outputRaw = _.boolFrom( value.trim() ); + return true; + } + else if( name === 'underline' ) + { + self.underline = _.boolFrom( value.trim() ); + return true; + } + else if( name === 'style' ) + { + self.styleSet( value.trim() ); + return true; + } + +} + +// + +/* +move:eol +move:bol +move:bos +move:eos +move:pl +move:nl +move:pc +move:nc + +b = begin +e = end +l = line +s = screen +c = char +p = prev +n = next + +*/ + +function _directiveMoveApply( value ) +{ + _.assert( Config.interpreter === 'njs' ); + + let shellMoveDirectiveCodes = + { + eol, + eos, + 'bol' : '0G', + 'bos' : '1;1H', + 'pl' : '1F', + 'nl' : '1E', + 'pc' : '1D', + 'nc' : '1C' + } + + let code = shellMoveDirectiveCodes[ value ]; + + _.assert( code !== undefined, 'Unknown value for directive move:', value ); + + if( _.routineIs( code ) ) + code = code(); + + /* + for eos, eol returns empty string if program can't get sizes of the terminal + */ + if( code.length ) + code = `\x1b[${code}`; + + return code; + + /* */ + + function eol() + { + let result = ''; + + if( process.stdout.columns ) + result = `${process.stdout.columns}G`; + + return result; + }; + + function eos() + { + let result = ''; + let stdo = process.stdout; + + if( !!stdo.rows && !!stdo.columns ) + result = `${stdo.rows};${stdo.columns}H`; + + return result + }; + +} + +// + +function _directiveClsApply( value ) +{ + _.assert( Config.interpreter === 'njs' ); + + let clsValuesMap = + { + '' : 2, + 'left' : 1, + 'right' : 0, + } + + let cls = clsValuesMap[ value ]; + _.assert( cls !== undefined, 'Unknown value for directive "cls":', value ); + + let code = `\x1b[${cls}J`; + if( cls === 2 ) + code += `\x1b[H`; + + /* + moves cursor to top left corner as terminal 'cls' does + */ + + return code; +} + +// + +function _transformAct( original ) +{ + + return function _transformAct( o ) + { + let self = this; + + _.assert( _.mapIs( o ) ); + + o = original.call( self, o ); + + _.assert( _.strIs( o.joinedInput ) ); + _.assert( _.longIs( o.input ) ); + _.assert( o.output === null ); + _.assert( !!o.chainLink ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( !self.outputGray && _.color ) + self._transformColorApply( o ); + + /* */ + + if( !o.chainLink.outputPrinter.isPrinter ) + { + + if( !o._outputSplitted ) + self._transformSplit( o ); /* xxx */ + + if( !o._outputForTerminal ) + { + if( self.writingToHtml ) + self._transformActHtml( o ); + else if( Config.interpreter === 'njs' ) + self._transformAct_nodejs( o ); + else if( Config.interpreter === 'browser' ) + self._transformAct_browser( o ); + } + + _.assert( _.arrayIs( o._outputForTerminal ) ); + o.output = o._outputForTerminal; + } + else + { + o._outputForPrinter = [ o.joinedInput ]; + o.output = o._outputForPrinter; + _.assert( _.arrayIs( o._outputForPrinter ) ); + } + + return o; + } + +} + +// + +function _rgbToCode_nodejs( rgb, isBackground ) +{ + let name = _.color._colorNameNearest( rgb, _.color.ColorMapShell ); + let code = shellColorCodes[ name ]; + + _.assert( _.numberIs( code ), 'nothing found for color: ', name ); + + if( isBackground ) + code += 10; /* add 10 to convert fg code to bg code */ + + return _.entity.exportString( code ); +} + +// + +function _diagnoseColorCheck() +{ + let self = this; + + if( Config.interpreter === 'browser' ) + return; + + if( !self.foregroundColor || !self.backgroundColor ) + return; + + /* qqq : ??? */ + + let stackFg = self._diagnosingColorsStack[ 'foreground' ]; + let stackBg = self._diagnosingColorsStack[ 'background' ]; + + let fg = stackFg[ stackFg.length - 1 ]; + let bg = stackBg[ stackBg.length - 1 ]; + + /* */ + + let result = {}; + + if( self.diagnosingColor ) + result.ill = self._diagnoseColorIll( fg, bg ); + + if( self.diagnosingColorCollapse ) + result.collapse = self._diagnoseColorCollapse( fg, bg ); + + return result; + +} + +// + +function _diagnoseColorIll( fg, bg ) +{ + let self = this; + let ill = false; + + /* qqq : optimize */ + + for( let i = 0; i < PoisonedColorCombination.length; i++ ) + { + let combination = PoisonedColorCombination[ i ]; + if( combination.fg === fg.originalName && combination.bg === bg.originalName ) + { + self.diagnosingColor = 0; + ill = true; + logger.styleSet( 'info.negative' ); + logger.warn( 'Warning!. Ill colors combination: ' ); + logger.warn( 'fg : ', fg.currentName, self.foregroundColor ); + logger.warn( 'bg : ', bg.currentName, self.backgroundColor ); + logger.warn( 'platform : ', combination.platform ); + logger.styleSet( 'default' ); + } + } + + return ill; +} + +// + +function _diagnoseColorCollapse( fg, bg ) +{ + let self = this; + let collapse = false; + + if( _.long.identical( self.foregroundColor, self.backgroundColor ) ) + { + if( fg.originalName !== bg.originalName ) + { + let diff = _.color._colorDistance( fg.originalValue, bg.originalValue ); + if( diff <= 0.25 ) + collapse = true; + } + } + + if( collapse ) + { + self.diagnosingColorCollapse = 0; + logger.styleSet( 'info.negative' ); + logger.warn( 'Warning: Color collapse in native terminal.' ); + logger.warn( 'fg passed : ', fg.originalName, fg.originalValue ); + logger.warn( 'fg set : ', fg.currentName, self.foregroundColor ); + logger.warn( 'bg passed: ', bg.originalName, bg.originalValue ); + logger.warn( 'bg set : ', bg.currentName, self.backgroundColor ); + logger.styleSet( 'default' ); + } + + return collapse; +} + +// -- +// accessor +// -- + +function _foregroundColorGet() +{ + let self = this; + return self[ symbolForForeground ]; +} + +// + +function _backgroundColorGet() +{ + let self = this; + return self[ symbolForBackground ]; +} + +// + +function _foregroundColorSet( color ) +{ + let self = this; + let layer = 'foreground'; + + self._colorSet( layer, color ); +} + +// + +function _backgroundColorSet( color ) +{ + let self = this; + let layer = 'background'; + + self._colorSet( layer, color ); +} + +// + +function _colorSet( layer, color ) +{ + let self = this; + let symbol, diagnosticInfo; + + if( layer === 'foreground' ) + symbol = symbolForForeground; + else if( layer === 'background' ) + symbol = symbolForBackground; + else _.assert( 0, 'unexpected' ); + + if( _.strIs( color ) ) + color = color.trim(); + + if( !_.color ) + { + self[ symbol ] = null; + return; + } + + _.assert( _.symbolIs( symbol ) ); + + if( !_.color ) + { + color = null; + } + + /* */ + + if( color && color !== 'default' ) + { + let originalName = color; + + if( Config.interpreter === 'browser' ) /* xxx qqq : use field instead of Config.interpreter */ + { + color = _.color.rgbaFromTry( color ); + } + else + { + color = _.color.rgbaFromTry({ colorMap : _.color.ColorMapShell, src : color, def : null }); + if( !color ) + color = _.color.rgbaFromTry( originalName ); + } + + if( !color ) + { + debugger; + throw _.err( `Can\'t set ${layer} color. Unknown color name: "${originalName}".` ); + } + + let originalValue = color; + let currentName; + + if( color ) + { + if( Config.interpreter === 'browser' ) + { + color = _.color.rgbaFrom({ src : color, colorMap : _.color.ColorMap }); + currentName = _getColorName( _.color.ColorMap, color ); + } + else + { + color = _.color.rgbaFrom({ src : color, colorMap : _.color.ColorMapShell }); + currentName = _getColorName( _.color.ColorMapShell, color ); + } + + diagnosticInfo = + { + originalValue, + originalName, + currentName, + exact : !!_.color._colorDistance( color, originalValue ) + }; + + } + + } + + /* */ + + if( !color || color === 'default' ) + { + if( self._stackIsNotEmpty( layer ) ) + self[ symbol ] = self._stackPop( layer ); + else + self[ symbol ] = null; + + if( self._diagnosingColorsStack ) + self._diagnosingColorsStack[ layer ].pop(); + } + else + { + if( self[ symbol ] ) + self._stackPush( layer, self[ symbol ] ); + + self[ symbol ] = color; + self._isStyled = 1; + + if( !self._diagnosingColorsStack ) + self._diagnosingColorsStack = { 'foreground' : [], 'background' : [] }; + + self._diagnosingColorsStack[ layer ].push( diagnosticInfo ); + } + + /* */ + + function _getColorName( map, color ) + { + let keys = _.props.onlyOwnKeys( map ); + for( let i = 0; i < keys.length; i++ ) + if( _.long.identical( map[ keys[ i ] ], color ) ) + return keys[ i ]; + + } + +} + +// + +function styleSet( src ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ) || src === null ); + + let special = [ 'default', 'reset' ]; + + if( _.longHas( special, src ) ) + { + if( src === 'reset' || self._stylesStack.length < 2 ) + { + return self._styleReset(); + } + else + { + self._stylesStack.pop(); + let style = self._stylesStack[ self._stylesStack.length - 1 ]; + return self._styleApply( style ); + } + } + + let style = _.color.strColorStyle( src ); + + _.assert( _.objectLike( style ), 'Unknown style:', src ); + + let _style = _.props.extend( null, style ); + + self._styleApply( _style ); + self._styleComplement( _style ); + + self._stylesStack.push( _style ); + +} + +// + +function _styleApply( style ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.objectLike( style ) ); + + if( style.fg ) + self.foregroundColor = style.fg; + + if( style.bg ) + self.backgroundColor = style.bg; + + if( style.underline ) + self.underline = style.underline; +} + +// + +function _styleComplement( style ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.objectLike( style ) ); + + if( !style.fg ) + style.fg = self.foregroundColor; + + if( !style.bg ) + style.bg = self.backgroundColor; + + if( !style.underline ) + style.underline = self.underline; + +} + +// + +function _styleReset() +{ + let self = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + self._resetStyle = true; + + self[ symbolForForeground ] = null; + self[ symbolForBackground ] = null; + self[ underlineSymbol ] = 0; +} + +// + +function _inputGraySet( src ) +{ + let self = this; + + _.assert( _.boolLike( src ) ); + + if( _.boolIs( src ) ) + src = self.inputGray + ( src ? 1 : -1 ); + + if( src < 0 ) + src = 0; + + self[ inputGraySymbol ] = src; + +} + +// + +function _outputGraySet( src ) +{ + let self = this; + _.assert( _.boolLike( src ) ); + + if( _.boolIs( src ) ) + src = self.outputGray + ( src ? 1 : -1 ); + + if( src < 0 ) + debugger; + + if( src < 0 ) + src = 0; + + self[ outputGraySymbol ] = src; + +} + +// + +function _inputRawSet( src ) +{ + let self = this; + _.assert( _.boolLike( src ) ); + + if( _.boolIs( src ) ) + src = self.inputRaw + ( src ? 1 : -1 ); + + if( src < 0 ) + debugger; + + if( src < 0 ) + src = 0; + + self[ inputRawSymbol ] = src; + +} + +// + +function _outputRawSet( src ) +{ + let self = this; + _.assert( _.boolLike( src ) ); + + if( _.boolIs( src ) ) + src = self.outputRaw + ( src ? 1 : -1 ); + + if( src < 0 ) + debugger; + + if( src < 0 ) + src = 0; + + self[ outputRawSymbol ] = src; + +} + +// + +function _underlineSet( src ) +{ + let self = this; + _.assert( _.boolLike( src ) ); + + if( _.boolIs( src ) ) + src = self.underline + ( src ? 1 : -1 ); + + if( src < 0 ) + debugger; + + if( src < 0 ) + src = 0; + + self[ underlineSymbol ] = src; + +} + +function _clsSet( src ) +{ + let self = this; + + _.assert( src !== undefined ); + + let clsValuesMap = + { + '' : 2, + 'left' : 1, + 'right' : 0, + 'null' : null + } + + let value = clsValuesMap[ src ]; + _.assert( value !== undefined, 'Unknown value for directive "cls":', src ); + self[ clsSymbol ] = value; + +} + +// -- +// string formatters +// -- + +function colorFormat( src, format ) +{ + let self = this; + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + if( self.outputGray || !_.color || !_.ct.formatFinal ) + return src; + return _.ct.formatFinal( src, format ); +} + +// + +function colorBg( src, format ) +{ + let self = this; + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + if( self.outputGray || !_.color || !_.ct.bg ) + return src; + return _.ct.bg( src, format ); +} + +// + +function colorFg( src, format ) +{ + let self = this; + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + if( self.outputGray || !_.color || !_.ct.fg ) + return src; + return _.ct.fg( src, format ); +} + +// + +function escape( src ) +{ + let self = this; + _.assert( arguments.length === 1 ); + if( /*self.outputGray ||*/ !_.color || !_.ct.fg ) + return src; + return _.ct.escape( src ); +} + +// + +function str() +{ + debugger; + return _.entity.exportStringDiagnosticShallow/*exportStringSimple*/.apply( _, arguments ); +} + +// -- +// topic +// -- + +function topic() +{ + let self = this; + + let result = _.strConcat( arguments ); + + if( !self.outputGray ) + result = _.ct.formatFinal( result, 'topic.up' ); + + this.log(); + this.log( result ); + + return result; +} + +// + +function topicUp() +{ + let self = this; + + let result = _.strConcat( arguments ); + + if( !self.outputGray ) + result = _.ct.formatFinal( result, 'topic.up' ); + + this.log(); + this.logUp( result ); + + return result; +} + +// + +function topicDown() +{ + let self = this; + + let result = _.strConcat( arguments ); + + if( !self.outputGray ) + result = _.ct.formatFinal( result, 'topic.down' ); + + this.log(); + this.logDown( result ); + this.log(); + + return result; +} + +// -- +// fields +// -- + +let levelSymbol = Symbol.for( 'level' ); +let symbolForForeground = Symbol.for( 'foregroundColor' ); +let symbolForBackground = Symbol.for( 'backgroundColor' ); + +let inputGraySymbol = Symbol.for( 'inputGray' ); +let outputGraySymbol = Symbol.for( 'outputGray' ); +let inputRawSymbol = Symbol.for( 'inputRaw' ); +let outputRawSymbol = Symbol.for( 'outputRaw' ); +let underlineSymbol = Symbol.for( 'underline' ); + +let shellColorCodes = +{ + 'black' : 30, + 'dark red' : 31, + 'dark green' : 32, + 'dark yellow' : 33, + 'dark blue' : 34, + 'dark magenta' : 35, + 'dark cyan' : 36, + 'dark white' : 37, + + 'bright black' : 90, + 'red' : 91, + 'green' : 92, + 'yellow' : 93, + 'blue' : 94, + 'magenta' : 95, + 'cyan' : 96, + 'white' : 97 +} + +/* let shellColorCodesUnix = +{ + 'white' : 37, + 'bright white' : 97, +} */ + +let PoisonedColorCombination = +[ + + { fg : 'white', bg : 'yellow', platform : 'win32' }, + { fg : 'green', bg : 'cyan', platform : 'win32' }, + { fg : 'red', bg : 'magenta', platform : 'win32' }, + { fg : 'yellow', bg : 'white', platform : 'win32' }, + { fg : 'cyan', bg : 'green', platform : 'win32' }, + { fg : 'cyan', bg : 'yellow', platform : 'win32' }, + { fg : 'magenta', bg : 'red', platform : 'win32' }, + { fg : 'bright black', bg : 'magenta', platform : 'win32' }, + { fg : 'dark yellow', bg : 'magenta', platform : 'win32' }, + { fg : 'dark blue', bg : 'blue', platform : 'win32' }, + { fg : 'dark cyan', bg : 'magenta', platform : 'win32' }, + { fg : 'dark green', bg : 'magenta', platform : 'win32' }, + { fg : 'dark white', bg : 'green', platform : 'win32' }, + { fg : 'dark white', bg : 'cyan', platform : 'win32' }, + { fg : 'green', bg : 'dark white', platform : 'win32' }, + { fg : 'blue', bg : 'dark blue', platform : 'win32' }, + { fg : 'cyan', bg : 'dark white', platform : 'win32' }, + { fg : 'bright black', bg : 'dark yellow', platform : 'win32' }, + { fg : 'bright black', bg : 'dark cyan', platform : 'win32' }, + { fg : 'dark yellow', bg : 'bright black', platform : 'win32' }, + { fg : 'dark yellow', bg : 'dark cyan', platform : 'win32' }, + { fg : 'dark red', bg : 'dark magenta', platform : 'win32' }, + { fg : 'dark magenta', bg : 'dark red', platform : 'win32' }, + { fg : 'dark cyan', bg : 'bright black', platform : 'win32' }, + { fg : 'dark cyan', bg : 'dark yellow', platform : 'win32' }, + { fg : 'dark cyan', bg : 'dark green', platform : 'win32' }, + { fg : 'dark green', bg : 'dark cyan', platform : 'win32' }, + + /* */ + + // { fg : 'white', bg : 'bright yellow', platform : 'darwin' }, /* qqq : check the color */ + { fg : 'green', bg : 'cyan', platform : 'darwin' }, + { fg : 'yellow', bg : 'cyan', platform : 'darwin' }, + { fg : 'blue', bg : 'bright blue', platform : 'darwin' }, + { fg : 'blue', bg : 'black', platform : 'darwin' }, + { fg : 'cyan', bg : 'yellow', platform : 'darwin' }, + { fg : 'cyan', bg : 'green', platform : 'darwin' }, + // { fg : 'bright yellow', bg : 'white', platform : 'darwin' }, + { fg : 'bright red', bg : 'bright magenta', platform : 'darwin' }, + { fg : 'bright magenta', bg : 'bright red', platform : 'darwin' }, + + { fg : 'bright blue', bg : 'blue', platform : 'darwin' }, + // { fg : 'bright white', bg : 'bright cyan', platform : 'darwin' }, + { fg : 'bright green', bg : 'bright cyan', platform : 'darwin' }, + { fg : 'bright cyan', bg : 'bright green', platform : 'darwin' }, + + /* */ + + /* qqq : bright black? */ + + { fg : 'white', bg : 'yellow', platform : 'linux' }, + { fg : 'green', bg : 'cyan', platform : 'linux' }, + { fg : 'yellow', bg : 'white', platform : 'linux' }, + { fg : 'blue', bg : 'magenta', platform : 'linux' }, + { fg : 'cyan', bg : 'green', platform : 'linux' }, + { fg : 'magenta', bg : 'blue', platform : 'linux' }, + { fg : 'dark yellow', bg : 'blue', platform : 'linux' }, + { fg : 'dark yellow', bg : 'magenta', platform : 'linux' }, + { fg : 'dark cyan', bg : 'blue', platform : 'linux' }, + { fg : 'dark green', bg : 'blue', platform : 'linux' }, + { fg : 'dark green', bg : 'magenta', platform : 'linux' }, + { fg : 'dark white', bg : 'green', platform : 'linux' }, + { fg : 'dark white', bg : 'yellow', platform : 'linux' }, + { fg : 'dark white', bg : 'cyan', platform : 'linux' }, + { fg : 'white', bg : 'dark white', platform : 'linux' }, + { fg : 'green', bg : 'dark white', platform : 'linux' }, + { fg : 'yellow', bg : 'dark white', platform : 'linux' }, + { fg : 'blue', bg : 'dark yellow', platform : 'linux' }, + { fg : 'blue', bg : 'dark cyan', platform : 'linux' }, + { fg : 'cyan', bg : 'dark white', platform : 'linux' }, + { fg : 'magenta', bg : 'dark yellow', platform : 'linux' }, + { fg : 'magenta', bg : 'dark cyan', platform : 'linux' }, + { fg : 'magenta', bg : 'dark green', platform : 'linux' }, + { fg : 'bright black', bg : 'dark magenta', platform : 'linux' }, + { fg : 'bright black', bg : 'dark blue', platform : 'linux' }, + { fg : 'dark magenta', bg : 'bright black', platform : 'linux' }, + { fg : 'dark magenta', bg : 'dark blue', platform : 'linux' }, + { fg : 'dark blue', bg : 'bright black', platform : 'linux' }, + { fg : 'dark blue', bg : 'dark magenta', platform : 'linux' }, + { fg : 'dark cyan', bg : 'dark green', platform : 'linux' }, + { fg : 'dark green', bg : 'dark cyan', platform : 'linux' }, + + +] + +let Directive = [ 'bg', 'background', 'fg', 'foreground', 'outputGray', 'inputGray', 'inputRaw', 'outputRaw', 'underline', 'cls', 'style', 'move', 'cll' ]; +let DirectiveColoring = [ 'bg', 'background', 'fg', 'foreground' ]; + +// -- +// relations +// -- + +let Composes = +{ + + foregroundColor : null, + backgroundColor : null, + permanentStyle : null, + + coloringHeadAndTail : 1, + coloringConnotation : 1, + writingToHtml : 0, + + raw : 0, + inputGray : 0, + outputGray : 0, + inputRaw : 0, + outputRaw : 0, + underline : 0, + +} + +let Aggregates = +{ + +} + +let Associates = +{ + +} + +let Restricts = +{ + + _colorsStack : null, + _diagnosingColorsStack : null, /* qqq : what for??? */ + _stylesStack : _.define.own( [] ), + _resetStyle : 0, + _isStyled : 0, + _cursorSaved : 0, + +} + +let Statics = +{ + rawAll : 0, + diagnosingColor : 1, /* xxx */ + diagnosingColorCollapse : 1, + PoisonedColorCombination, + Directive, + DirectiveColoring, + TransformCssStylingToDirectives +} + +let Forbids = +{ + coloring : 'coloring', + outputColoring : 'outputColoring', + inputColoring : 'inputColoring', +} + +let Accessors = +{ + + foregroundColor : 'foregroundColor', + backgroundColor : 'backgroundColor', + + inputGray : 'inputGray', + outputGray : 'outputGray', + inputRaw : 'inputRaw', + outputRaw : 'outputRaw', + underline : 'underline', + +} + +// -- +// declare +// -- + +let Functors = +{ + + _transformAct, + +} + +let Extension = +{ + + // stack + + _stackPush, + _stackPop, + _stackIsNotEmpty, + + // transform + + _transformActHtml, + _transformAct_nodejs, + _transformAct_browser, + _transformActWithoutColors, + _transformColorApply, + _transformSplit, + + // + + _join, + _split, + _splitHandle, + _directiveApply, + _directiveMoveApply, + _directiveClsApply, + + _rgbToCode_nodejs, + _diagnoseColorCheck, + _diagnoseColorIll, + _diagnoseColorCollapse, + + // accessor + + _foregroundColorGet, + _backgroundColorGet, + _foregroundColorSet, + _backgroundColorSet, + _colorSet, + _underlineSet, + + styleSet, + _styleApply, + _styleComplement, + _styleReset, + + _inputGraySet, + _outputGraySet, + _inputRawSet, + _outputRawSet, + + // string formatters + + colorFormat, + colorBg, + colorFg, + escape, + str, + + // topic + + topic, + topicUp, + topicDown, + + // relations + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + Forbids, + Accessors, + +} + +// + +_.classDeclare +({ + cls : Self, + extend : Extension, + functors : Functors, + withMixin : true, + withClass : true, +}); + +// -- +// export +// -- + +_[ Self.shortName ] = Self; +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l3/ColoredMixin.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ColoredMixin_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ColoredMixin_s */ })(); + +/* */ /* begin of file LoggerMid_s */ ( function LoggerMid_s() { function LoggerMid_s_naked() { (function _LoggerMid_s_() +{ + +'use strict'; + +/** + * @classdesc Extends [wLoggerBasic]{@link wLoggerBasic} with input transforming, attributing and verbosity control mechanics. + * @class wLoggerMid + * @namespace Tools + * @module Tools/base/Logger + */ + +const _global = _global_; +const _ = _global_.wTools; +const Parent = _.LoggerBasic; +const Self = wLoggerMid; +function wLoggerMid( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'LoggerMid'; + +// -- +// implementation +// -- + +function init( o ) +{ + let self = this; + o = o || Object.create( null ); + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + // if( Config.debug ) + // if( o.scriptStack === undefined ) + // o.scriptStack = _.introspector.stack([ 1, Infinity ]); + + Parent.prototype.init.call( self, o ); + + self.levelSet( self.level ); + +} + +// -- +// etc +// -- + +function levelSet( level ) +{ + let self = this; + + Parent.prototype.levelSet.call( self, level ); + + level = self[ levelSymbol ]; + + self._prefix = _.strDup( self._dprefix || '', level ); + self._postfix = _.strDup( self._dpostfix || '', level ); + +} + +// + +function _transformBegin( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let o2 = Parent.prototype._transformBegin.call( self, o ); + _.assert( o === o2 ); + + // if( self.onTransformBegin ) + // { + // let o2 = self.onTransformBegin( o ); + // _.assert( o2 === o, 'Callback::onTransformBegin should return the argument' ); + // } + // + // if( o.discarding ) + // return o; + + // debugger; + if( !self.verboseEnough() ) + { + // debugger; + o.discarding = true; + return o; + } + + // let o2 = Parent.prototype._transformBegin.call( self, o ); + // _.assert( o === o2 ); + + // if( o.discarding ) + // return o; + + self._laterActualize(); /* xxx : remove? */ + + return o; +} + +// + +function _transformEnd( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + // if( self.onTransformEnd ) + // self.onTransformEnd( o ); + + let o2 = Parent.prototype._transformEnd.call( self, o ); + _.assert( o2 === o ); + + // if( !o ) + // return; + + return o; +} + +// -- +// attributing +// -- + +function _begin( key, val ) +{ + let self = this; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( key ), 'Expects string {-key-}, got', _.entity.strType( key ) ); + + if( val === undefined ) + { + _.assert( 0, 'value expected' ); + self._end( key, val ); + return self; + } + + if( self.attributes[ key ] !== undefined ) + { + self._attributesStacks[ key ] = self._attributesStacks[ key ] || []; + self._attributesStacks[ key ].push( self.attributes[ key ] ); + } + + self.attributes[ key ] = val; + + return self; +} + +// + +function begin() +{ + let self = this; + + for( let a = 0 ; a < arguments.length ; a++ ) + { + let argument = arguments[ a ]; + + if( _.object.isBasic( argument ) ) + { + for( let key in argument ) + self._begin( key, argument[ key ] ) + return; + } + + self._begin( argument, 1 ); + } + + return self; +} + +// + +function _end( key, val ) +{ + let self = this; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( key ) ); + + if( Config.debug ) + if( val !== undefined ) + if( val !== self.attributes[ key ] ) + throw self._attributeError( key, self.attributes[ key ], val ); + // _.assert + // ( + // val === self.attributes[ key ], + // () => self._attributeError( key, self.attributes[ key ], val ) + // ); + + if( self._attributesStacks[ key ] ) + { + self.attributes[ key ] = self._attributesStacks[ key ].pop(); + if( !self._attributesStacks[ key ].length ) + delete self._attributesStacks[ key ]; + } + else + { + delete self.attributes[ key ]; + } + + return self; +} + +// + +function end() +{ + let self = this; + + for( let a = 0 ; a < arguments.length ; a++ ) + { + let argument = arguments[ a ]; + + if( _.object.isBasic( argument ) ) + { + for( let key in argument ) + self._end( key, argument[ key ] ) + return; + } + + self._end( argument ) + } + + return self; +} + +// + +function _rbegin( key, val ) +{ + let self = this; + let attribute = self.attributes[ key ]; + + if( attribute === undefined ) + { + self._begin( key, 0 ); + attribute = 0; + } + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( key ), 'Expects string {-key-}, got', () => _.entity.strType( key ) ); + _.assert( _.numberIs( val ), 'Expects number {-val-}, got', () => _.entity.strType( val ) ); + _.assert( _.numberIs( attribute ), () => _.args( 'Expects number, but attribute', _.strQuote( key ), 'had value', _.strQuote( attribute ) ) ); + + return self._begin( key, val + attribute ) +} + +// + +function rbegin() +{ + let self = this; + + for( let a = 0 ; a < arguments.length ; a++ ) + { + let argument = arguments[ a ]; + + if( _.object.isBasic( argument ) ) + { + for( let key in argument ) + self._rbegin( key, argument[ key ] ) + return; + } + + self._rbegin( argument, 1 ); + } + + return self; +} + +// + +function _rend( key, val ) +{ + let self = this; + let attributeStack = self._attributesStacks[ key ]; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( key ) ); + _.assert( _.numberIs( val ) ); + + _.assert + ( + _.arrayIs( attributeStack ) && _.numberIs( attributeStack[ attributeStack.length-1 ] ), + () => self._attributeError( key, undefined, val ) + ); + + let attribute = attributeStack[ attributeStack.length-1 ]; + val = attribute + val; + + self._end( key, val ); + + return self; +} + +// + +function rend() +{ + let self = this; + + for( let a = 0 ; a < arguments.length ; a++ ) + { + let argument = arguments[ a ]; + + if( _.object.isBasic( argument ) ) + { + for( let key in argument ) + self._rend( key, argument[ key ] ) + return; + } + + self._rend( argument ) + } + + return self; +} + +// + +function _attributeError( key, begin, end ) +{ + let self = this; + + debugger; + + return _.err + ( + '{-begin-} does not have complemented {-end-}' + + '\nkey : ' + _.entity.exportString( key ) + + '\nbegin : ' + _.entity.exportString( begin ) + + '\nend : ' + _.entity.exportString( end ) + + '\nlength : ' + ( self._attributesStacks[ key ] ? self._attributesStacks[ key ].length : 0 ) + ); + +} + +// -- +// verbosity +// -- + +function verbosityPush( src ) +{ + let self = this; + + // debugger; + + if( !_.numberIs( src ) ) + src = src ? 1 : 0; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + self._verbosityStack.push( self.verbosity ); + + self.verbosity = src; + +} + +// + +function verbosityPop() +{ + let self = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + // debugger; + + self.verbosity = self._verbosityStack.pop(); + +} + +// + +function verbosityReserve( args ) +{ + let self = this; + + if( !self.usingVerbosity ) + return Infinity; + + return self._verbosityReserve(); +} + +// + +function _verbosityReserve() +{ + let self = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + // if( self.attributes.verbosity === undefined ) + // return Infinity; + + if( self.verbosity === null ) + return Infinity; + + return self.verbosity + ( self.attributes.verbosity || 0 ) + 1; +} + +// + +function verboseEnough() +{ + let self = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( !self.usingVerbosity ) + return true; + + return self._verboseEnough(); +} + +// + +function _verboseEnough() +{ + let self = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + return self._verbosityReserve() > 0; +} + +// + +function _verbosityReport() +{ + let self = this; + + console.log( 'logger.verbosity', self.verbosity ); + console.log( 'logger.attributes.verbosity', self.attributes.verbosity ); + console.log( self.verboseEnough() ? 'Verbose enough!' : 'Not enough verbose!' ); + +} + +// + +function _verbositySet( src ) +{ + let self = this; + + if( _.boolIs( src ) ) + src = src ? 1 : 0; + + _.assert( arguments.length === 1 ); + _.assert( _.numberIs( src ) ); + + src = _.numberClamp( src, 0, 9 ); + + let change = self[ verbositySymbol ] !== src; + + self[ verbositySymbol ] = src; + + if( change ) + self.eventGive( 'verbosityChange' ); + + return src; +} + +// -- +// later +// -- + +function later( name ) +{ + let self = this; + let later = Object.create( null ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( name ) ); + + later.name = name; + later.after = []; + later.logger = self; + later.autoFinit = 1; + later.detonated = 0; + later.log = function log() + { + if( this.logger.verboseEnough ) + this.after.push([ 'log', arguments ]); + } + + self._mines[ name ] = later; + + return later; +} + +// + +function _laterActualize() +{ + let self = this; + let result = Object.create( null ); + + for( let m in self._mines ) + { + let later = self._mines[ m ]; + if( !later.detonated ) + self.laterActualize( later ); + } + + return result; +} + +// + +function laterActualize( later ) +{ + let self = this; + + if( _.strIs( later ) ) + later = self._mines[ later ]; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.mapIs( later ) ); + + later.detonated = 1; + + for( let a = 0 ; a < later.after.length ; a++ ) + { + let after = later.after[ a ]; + self[ after[ 0 ] ].apply( self, after[ 1 ] ); + } + + if( later.autoFinit ) + self.laterFinit( later ); + + return self; +} + +// + +function laterFinit( later ) +{ + let self = this; + + if( _.strIs( later ) ) + later = self._mines[ later ]; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.mapIs( later ) ); + _.assert( self._mines[ later.name ] === later ); + + Object.freeze( later ); + delete self._mines[ later.name ]; + + return self; +} + +// -- +// relations +// -- + +let levelSymbol = Symbol.for( 'level' ); +let verbositySymbol = Symbol.for( 'verbosity' ); + +let Composes = +{ + + verbosity : 1, + usingVerbosity : 1, + + // onTransformBegin : null, + // onTransformEnd : null, + + attributes : _.define.own( {} ), + +} + +// if( Config.debug ) +// Composes.scriptStack = null; + +let Aggregates = +{ +} + +let Associates = +{ +} + +let Restricts = +{ + + _prefix : '', + _postfix : '', + + _dprefix : ' ', + _dpostfix : '', + + _verbosityStack : _.define.own( [] ), + + _attributesStacks : _.define.own( {} ), + _mines : _.define.own( {} ), + +} + +let Events = +{ + verbosityChange : 'verbosityChange', +} + +let Accessors = +{ + verbosity : 'verbosity', +} + +let Forbids = +{ + format : 'format', + tags : 'tags', +} + +// -- +// declare +// -- + +let Proto = +{ + + // routine + + init, + + // etc + + levelSet, + _transformBegin, + _transformEnd, + + // attributing + + _begin, + begin, + _end, + end, + + _rbegin, + rbegin, + _rend, + rend, + + _attributeError, + + // verbosity + + verbosityPush, + verbosityPop, + verbosityReserve, + _verbosityReserve, + verboseEnough, + _verboseEnough, + _verbosityReport, + _verbositySet, + + // later + + later, /* xxx : remove? */ + _laterActualize, + laterActualize, + laterFinit, + + // relations + + Composes, + Aggregates, + Associates, + Restricts, + Events, + Accessors, + Forbids, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); + +_.assert( Self.prototype.init === init ); +_.EventHandler.mixin( Self ); + +// -- +// export +// -- + +_[ Self.shortName ] = Self; +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l3/LoggerMid.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, LoggerMid_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file LoggerMid_s */ })(); + +/* */ /* begin of file Logger_s */ ( function Logger_s() { function Logger_s_naked() { (function _Logger_s_() +{ + +'use strict'; + + +/* + +Kinds of Chain : [ ordinary, excluding, original ] + +Kinds of Print-like object : [ console, printer ] + +Kinds of situations : + +conosle -> ordinary -> self +printer -> ordinary -> self +conosle -> excluding -> self +printer -> excluding -> self +self -> ordinary -> conosle +self -> ordinary -> printer +self -> original -> conosle +self -> original -> printer + +*/ + +/** + * @classdesc Creates a logger for printing colorful and well formatted diagnostic code on server-side or in the browser. Based on [wLoggerTop]{@link wLoggerTop}. + * @class wLogger + * @namespace Tools + * @module Tools/base/Logger + */ + +const _global = _global_; +const _ = _global_.wTools; +const Parent = _.LoggerMid; +const Self = wLoggerTop; +function wLoggerTop( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'Logger'; + +// -- +// +// -- + +function init( o ) +{ + let self = this; + _.assert( arguments.length === 0 || arguments.length === 1 ); + Parent.prototype.init.call( self, o ); +} + +// -- +// relations +// -- + +let Composes = +{ + name : '', +} + +let Aggregates = +{ +} + +let Associates = +{ + output : null, +} + +let Restricts = +{ +} + +let Statics = +{ +} + +// -- +// declare +// -- + +let Proto = +{ + + init, + + // relations + + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); + +// + +_.PrinterChainingMixin.mixin( Self ); +_.PrinterColoredMixin.mixin( Self ); + +_.assert( _.routineIs( _.PrinterChainingMixin.prototype._writeAct ) ); +_.assert( Self.prototype._writeAct === _.PrinterChainingMixin.prototype._writeAct ); + +if( !_global_.logger || !( _global_.logger instanceof Self ) ) +_global_.logger = _global_[ 'logger' ] = new Self({ output : console, name : 'global' }); + +// -- +// export +// -- + +_[ Self.shortName ] = Self; +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l5/Logger.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Logger_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Logger_s */ })(); + +/* */ /* begin of file LoggerPrime_s */ ( function LoggerPrime_s() { function LoggerPrime_s_naked() { (function _LoggerPrime_s_() +{ + +'use strict'; + +/** + * @classdesc Creates a logger for printing colorful and well formatted diagnostic code on server-side or in the browser. Based on [wLoggerTop]{@link wLoggerTop}. + * @class wLoggerPrime + * @namespace Tools + * @module Tools/base/Logger + */ + +const _global = _global_; +const _ = _global_.wTools; +const Parent = _.Logger; +const Self = wLoggerPrime; +function wLoggerPrime( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'LoggerPrime'; + +// + +function init( o ) +{ + let self = this; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + Parent.prototype.init.call( self, o ); + + if( !self.outputs.length ) + self.outputTo( _global_.logger ); + +} + +// -- +// relations +// -- + +let Composes = +{ +} + +let Aggregates = +{ +} + +let Associates = +{ +} + +let Restricts = +{ +} + +let Statics = +{ +} + +// -- +// declare +// -- + +let Proto = +{ + + init, + + // relations + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); + +// + +_[ Self.shortName ] = Self; + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l7/LoggerPrime.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, LoggerPrime_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file LoggerPrime_s */ })(); + +/* */ /* begin of file ToLayeredHtml_s */ ( function ToLayeredHtml_s() { function ToLayeredHtml_s_naked() { (function _ToLayeredHtml_s_() +{ + +'use strict'; + +// if( typeof module !== 'undefined' ) +// { +// +// const _ = require( '../../../../../node_modules/Tools' ); +// +// _.include( 'wLogger' ); +// +// } + +if( !_global_.jQuery ) +return; + +// + +/** + * @classdesc Creates a printer that writes messages into a DOM container. Based on [wLoggerTop]{@link wLoggerTop}. + * @class wPrinterToLayeredHtml + * @namespace Tools + * @module Tools/base/Logger + */ + +let $ = jQuery; +const _global = _global_; +const _ = _global_.wTools; +const Parent = _.Logger; +const Self = wPrinterToLayeredHtml; +function wPrinterToLayeredHtml( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'PrinterToLayeredHtml'; + +// + +function init( o ) +{ + let self = this; + + Parent.prototype.init.call( self, o ); + + self.containerDom = $( self.containerDom ); + _.assert( self.containerDom.length > 0, 'wPrinterToLayeredHtml : not found containerDom' ); + + self.containerDom.addClass( self.contentCssClass ); + + if( self.vertical ) + self.containerDom.addClass( 'vertical' ); + else + self.containerDom.addClass( 'horizontal' ); + + self.currentDom = self.containerDom; + +} + +// + +function write() +{ + let self = this; + + /* */ + + if( arguments.length === 1 ) + if( self.canPrintFrom( arguments[ 0 ] ) ) + { + self.printFrom( arguments[ 0 ] ); + return; + } + + /* */ + + let o = _.LoggerBasic.prototype.write.apply( self, arguments ); + + if( !o ) + return; + + _.assert( o ); + _.assert( _.arrayIs( o.output ) ); + + /* */ + + let data = _.strConcat.apply( {}, arguments ); + data = data.split( '\n' ); + + for( let d = 0 ; d < data.length ; d ++ ) + { + if( d > 0 ) + self._makeNextLineDom(); + let terminal = self._makeTerminalDom(); + terminal.text( data[ d ] ); + } + + /* */ + + return o; +} + +// + +function levelSet( level ) +{ + let self = this; + + _.assert( level >= 0, 'level cant go below zero level to', level ); + _.assert( isFinite( level ) ); + + let dLevel = level - self[ levelSymbol ]; + + Parent.prototype.levelSet.call( self, level ); + + if( dLevel > 0 ) + { + for( let l = 0 ; l < dLevel ; l++ ) + self.currentDom = self._makeBranchDom(); + } + else if( dLevel < 0 ) + { + for( let l = 0 ; l < -dLevel ; l++ ) + self.currentDom = self.currentDom.parent(); + } + +} + +// + +function _makeBranchDom( ) +{ + let self = this; + let result = $( '<' + self.elementCssTag + '>' ); + + if( _.props.keys( self.attributes ).length ) + _.dom.s.attr( result, self.attributes ); + + self.currentDom.append( result ); + result.addClass( self.branchCssClass ); + + if( self.usingRandomColor ) + { + let color = _.color.randomRgbWithSl( 0.5, 0.5 ); + color[ 3 ] = self.opacity; + // color = [ 0.75,1,1,0.5 ]; + result.css( 'background-color', _.color.colorToRgbaHtml( color ) ); + } + + return result; +} + +// + +function _makeTerminalDom() +{ + let self = this; + let result = $( '<' + self.elementCssTag + '>' ); + + if( _.props.keys( self.attributes ).length ) + _.dom.s.attr( result, self.attributes ); + + self.currentDom.append( result ); + result.addClass( self.terminalCssClass ); + + return result; +} + +// + +function _makeNextLineDom() +{ + let self = this; + + if( !self.usingNextLineDom ) + return; + + let result = $( '<' + self.elementCssTag + '>' ); + result.text( ' ' ); + + result.addClass( self.nextLineCssClass ); + self.currentDom.append( result ); + + return result; +} + +// -- +// relations +// -- + +let levelSymbol = Symbol.for( 'level' ); + +let Composes = +{ + + contentCssClass : 'layered-log-content', + branchCssClass : 'layered-log-branch', + terminalCssClass : 'layered-log-terminal', + nextLineCssClass : 'layered-log-next-line', + + elementCssTag : 'span', + + opacity : 0.2, + usingRandomColor : 0, + usingNextLineDom : 0, + + vertical : 0, + +} + +let Aggregates = +{ +} + +let Associates = +{ + containerDom : null, + currentDom : null, +} + +// -- +// prototype +// -- + +let Proto = +{ + + init, + + write, + + levelSet, + + _makeBranchDom, + _makeTerminalDom, + _makeNextLineDom, + + + // relations + + /* constructor * : * Self, */ + Composes, + Aggregates, + Associates, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); + +_global_[ Self.name ] = _[ Self.shortName ] = Self; + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l7/ToLayeredHtml.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ToLayeredHtml_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ToLayeredHtml_s */ })(); + +/* */ /* begin of file ToString_s */ ( function ToString_s() { function ToString_s_naked() { (function _ToString_s_() +{ + +'use strict'; + +/** + * @classdesc Creates a printer that collects messages into a single string. Based on [wLoggerTop]{@link wLoggerTop}. + * @class wLoggerToString + * @module Tools/base/Logger + */ + +const _global = _global_; +const _ = _global_.wTools; +const Parent = _.LoggerMid; +const Self = wLoggerToString; +function wLoggerToString( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'LoggerToString'; + +// + +function init( o ) +{ + let self = this; + return Parent.prototype.init.call( self, o ); +} + +// + +function _writeAct( channel, args ) +{ + let self = this; + + let o = _.LoggerBasic.prototype._writeAct.apply( self, arguments ); + + _.assert( _.strIs( o.joinedInput ) ); + + if( self.outputData ) + self.outputData += self.eol + o.joinedInput; + else + self.outputData += o.joinedInput; + + return o; +} + +// -- +// relations +// -- + +let Composes = +{ + eol : '\n', +} + +let Aggregates = +{ + outputData : '', +} + +let Associates = +{ +} + +let Restricts = +{ +} + +// -- +// prototype +// -- + +let Proto = +{ + + init, + + _writeAct, + + // relations + + Composes, + Aggregates, + Associates, + Restricts, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); + +_[ Self.shortName ] = Self; + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l7/ToString.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wLogger/proto/wtools/abase/l9/logger/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ToString_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ToString_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wProto */ ( function wProto() { function wProto_naked() { +module.exports = require( '../wtools/abase/l3_proto/Include.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wProto', 'wproto' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/node_modules/wProto' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wProto_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wProto */ })(); + +/* */ /* begin of file Include_s */ ( function Include_s() { function Include_s_naked() { ( function _Include_s_( ) { + +'use strict'; + +/** + * Relations module. Collection of cross-platform routines to define classes and relations between them. Proto leverages multiple inheritances, mixins, accessors, fields groups defining, introspection and more. Use it as a skeleton of the application. + @module Tools/base/Proto + @extends Tools +*/ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + + _.include( 'wBlueprint' ); + + require( './l1/Define.s' ); + require( './l1/Proto.s' ); + require( './l1/Workpiece.s' ); + + require( './l3/Accessor.s' ); + + require( './l5/Class.s' ); + require( './l5/Collection.s' ); + require( './l5/Like.s' ); + +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/Include.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Include_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Include_s */ })(); + +/* */ /* begin of file Define_s */ ( function Define_s() { function Define_s_naked() { ( function _Define_s_() { + +'use strict'; + +const Self = _global_.wTools; +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +/** +* Creates property-like entity with getter that returns reference to source object. +* @param {Object-like|Long} src - source value +* @returns {module:Tools/base/Proto.wTools.define.Definition} +* @function common +* @namespace Tools.define +*/ + +function common( src ) +{ + let o2 = { val : src } + o2.defGroup = 'definition.named'; + let definition = new _.Definition( o2 ); + + _.assert( src !== undefined, () => 'Expects object-like or long, but got ' + _.entity.strType( src ) ); + _.assert( arguments.length === 1 ); + _.assert( definition.val !== undefined ); + + // definition.toVal = function get() { debugger; return this.val } + definition.toVal = function get( val ) { return val } + + _.props.conceal( definition, 'toVal' ); + + Object.freeze( definition ); + return definition; +} + +// + +/** +* Creates property-like entity with getter that returns shallow copy of source object. +* @param {Object-like|Long} src - source value +* @returns {module:Tools/base/Proto.wTools.define.Definition} +* @function own +* @namespace Tools.define +*/ + +function own( src ) +{ + let o2 = { val : src } + o2.defGroup = 'definition.named'; + let definition = new _.Definition( o2 ); + + _.assert( src !== undefined, () => 'Expects object-like or long, but got ' + _.entity.strType( src ) ); + _.assert( arguments.length === 1 ); + _.assert( definition.val !== undefined ); + + definition.toVal = function get( val ) { return _.cloneJust( val ) }; + // definition.toVal = function get( val ) { return _.entity.cloneDeep( val ) }; /* xxx0 : use replicator */ + + _.props.conceal( definition, 'toVal' ); + + Object.freeze( definition ); + return definition; +} + +// + +/** +* Creates property-like entity with getter that returns new instance of source constructor. +* @param {Function} src - source constructor +* @returns {module:Tools/base/Proto.wTools.define.Definition} +* @function instanceOf +* @namespace Tools.define +*/ + +function instanceOf( src ) +{ + let o2 = { val : src } + o2.defGroup = 'definition.named'; + let definition = new _.Definition( o2 ); + + _.assert( _.routineIs( src ), 'Expects constructor' ); + _.assert( arguments.length === 1 ); + _.assert( definition.val !== undefined ); + + // definition.toVal = function get() { return new this.val() }; + definition.toVal = function get( val ) { return new val() }; + + _.props.conceal( definition, 'toVal' ); + + Object.freeze( definition ); + return definition; +} + +// + +/** +* Creates property-like entity with getter that returns result of source routine call. +* @param {Function} src - source routine +* @returns {module:Tools/base/Proto.wTools.define.Definition} +* @function makeWith +* @namespace Tools.define +*/ + +function makeWith( src ) +{ + let o2 = { val : src } + o2.defGroup = 'definition.named'; + let definition = new _.Definition( o2 ); + + _.assert( _.routineIs( src ), 'Expects constructor' ); + _.assert( arguments.length === 1 ); + _.assert( definition.val !== undefined ); + + // definition.toVal = function get() { return this.val() } + definition.toVal = function get( val ) { return val() }; + + _.props.conceal( definition, 'toVal' ); + + Object.freeze( definition ); + return definition; +} + +// + +/** +* @param {Object} src +* @returns {module:Tools/base/Proto.wTools.define.Definition} +* @function contained +* @namespace Tools.define +*/ + +function contained( src ) +{ + + _.assert( _.mapIs( src ) ); + _.assert( arguments.length === 1 ); + _.assert( src.val !== undefined ); + + let container = _.mapBut_( null, src, contained.defaults ); + let o = _.mapOnly_( null, src, contained.defaults ); + o.container = container; + o.val = src.val; + o.defGroup = 'definition.named'; + let definition = new _.Definition( o ); + + if( o.shallowCloning ) + definition.toVal = function get( val ) + { + let result = _.props.extend( null, container ); + result.value = _.entity.make( val ); + return result; + } + else + definition.toVal = function get( val ) + { + let result = _.props.extend( null, container ); + result.value = val; + return result; + } + + _.props.conceal( definition, 'toVal' ); + Object.freeze( definition ); + _.assert( definition.val !== undefined ); + return definition; +} + +contained.defaults = +{ + val : null, + shallowCloning : 0, +} + +// + +function accessor( o ) +{ + + if( _.routineIs( o ) ) + o = { routine : arguments[ 0 ] } + + _.routine.options_( accessor, o ); + + o.defGroup = 'definition.named'; + o.subKind = 'accessor'; + // o.constructionAmend = constructionAmend; + o.toVal = toVal; + + _.assert( _.routineIs( o.routine ) ); + _.assert( arguments.length === 1 ); + + let definition = new _.Definition( o ); + _.props.conceal( definition, 'constructionAmend' ); + _.assert( definition.val !== undefined ); + return definition; + + /* */ + + function toVal( val ) + { + _.assert( _.routineIs( val ) ); + return val; + } + + /* */ + + // function constructionAmend( dst, key, amend ) + // { + // _.assert( 0, 'deprecated' ); + // let instanceIsStandard = _.workpiece.instanceIsStandard( dst ); + // _.assert( arguments.length === 3 ); + // + // let args = [] + // for( let i = 0 ; i < o.val.length ; i++ ) + // args[ i ] = _.entity.cloneShallow( o.val[ i ] ); + // let o2; + // if( o.routine.head ) + // { + // o2 = o.routine.head( o.routine, args ); + // } + // else + // { + // debugger; + // _.assert( args.length === 1 ); + // o2 = args[ 0 ]; + // } + // + // _.assert( _.mapIs( o2 ) ); + // + // if( o.routine.defaults.propName !== undefined ) + // if( o2.propName === undefined || o2.propName === null ) + // { + // _.assert( 0, 'not tested' ); /* zzz : test */ + // o2.propName = key; + // } + // + // let r; + // if( o.routine.body ) + // r = o.routine.body( o2 ); + // else + // r = o.routine( o2 ); + // + // if( _.boolLike( o.get ) && !o.get && o.set === null ) + // { + // if( _.routineIs( r ) ) + // { + // o.set = r; + // if( o.put === null || _.boolLikeTrue( o.put ) ) + // o.put = r; + // } + // else if( _.mapIs( r ) ) + // { + // o.set = r.set; + // if( o.put === null || _.boolLikeTrue( o.put ) ) + // if( r.put ) + // o.put = r.put; + // } + // else _.assert( 0 ); + // } + // else if( _.boolLike( o.set ) && !o.set && o.get === null ) + // { + // if( _.routineIs( r ) ) + // o.get = r; + // else if( _.mapIs( r ) ) + // o.get = r.get + // else _.assert( 0 ); + // } + // else + // { + // if( _.mapIs( r ) ) + // { + // if( o.get === null || _.boolLikeTrue( o.get ) ) + // o.get = r.get; + // if( o.set === null || _.boolLikeTrue( o.set ) ) + // o.set = r.set; + // if( o.put === null || _.boolLikeTrue( o.put ) ) + // o.put = r.put; + // } + // } + // + // _.assert( _.boolLikeFalse( o.get ) || _.routineIs( o.get ) ); + // _.assert( _.boolLikeFalse( o.set ) || _.routineIs( o.set ) ); + // + // _.accessor.declare + // ({ + // object : dst, + // names : key, + // grab : o.grab, + // get : o.get, + // put : o.put, + // set : o.set, + // prime : instanceIsStandard, + // strict : instanceIsStandard, + // }); + // + // } + + /* */ + +} + +accessor.defaults = +{ + val : null, + routine : null, + grab : null, + get : null, + put : null, + set : null, +} + + + +function getter( o ) +{ + + if( _.routineIs( o ) ) + o = { routine : arguments[ 0 ] } + + _.routine.options_( getter, o ); + + o.get = null; + o.put = false; + o.set = false; + + return _.define.accessor( o ); +} + +getter.defaults = +{ + val : null, + routine : null, +} + + + +function setter( o ) +{ + + if( _.routineIs( o ) ) + o = { routine : arguments[ 0 ] } + + _.routine.options_( setter, o ); + + o.get = false; + o.put = null; + o.set = null; + + return _.define.accessor( o ); +} + +setter.defaults = +{ + val : null, + routine : null, +} + +// + +function putter( o ) +{ + + if( _.routineIs( o ) ) + o = { routine : arguments[ 0 ] } + + _.routine.options_( putter, o ); + + o.get = false; + o.set = false; + o.put = null; + + return _.define.accessor( o ); +} + +putter.defaults = +{ + val : null, + routine : null, +} + +// -- +// define +// -- + +/** +* Collection of definitions for constructions. +* @namespace wTools.define +* @extends Tools +* @module Tools/base/Proto +*/ + +let DefineExtension = +{ + + // field, + common, + own, + instanceOf, + makeWith, + contained, + + accessor, + getter, + setter, + putter, + +} + +_.define = _.define || Object.create( null ); +/* _.props.extend */Object.assign( _.define, DefineExtension ); + +// + +/** +* Routines to manipulate definitions. +* @namespace wTools.definition +* @extends Tools +* @module Tools/base/Proto +*/ + +let DefinitionExtension = +{ +} + +_.definition = _.definition || Object.create( null ); +/* _.props.extend */Object.assign( _.definition, DefinitionExtension ); +_.assert( _.routineIs( _.definitionIs ) ); +_.assert( _.definition.is === _.definitionIs ); + +// + +let ToolsExtension = +{ +} + +_.props.extend( _, ToolsExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/l1/Define.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Define_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Define_s */ })(); + +/* */ /* begin of file Proto_s */ ( function Proto_s() { function Proto_s_naked() { ( function _Proto_s_() { + +'use strict'; + +/** + * Collection of cross-platform routines to define classes and relations between them. + */ + +/** +* Definitions : + +* self :: current object. +* Self :: current class. +* Parent :: parent class. +* Statics :: static fields. +* extend :: extend destination with all properties from source. +* supplement :: supplement destination with those properties from source which do not belong to source. + +* routine :: arithmetical, logical and other manipulations on input data, context and globals to get output data. +* function :: routine which does not have side effects and don't use globals or context. +* procedure :: routine which use globals, possibly modify global's states. +* method :: routine which has context, possibly modify context's states. + +* Synonym : + + A composes B + :: A consists of B.s + :: A comprises B. + :: A made up of B. + :: A exists because of B, and B exists because of A. + :: A складається із B. + A aggregates B + :: A has B. + :: A exists because of B, but B exists without A. + :: A має B. + A associates B + :: A has link on B + :: A is linked with B + :: A посилається на B. + A restricts B + :: A use B. + :: A has occasional relation with B. + :: A використовує B. + :: A має обмежений, не чіткий, тимчасовий звязок із B. + +*/ + +const Self = _global_.wTools; +const _global = _global_; +const _ = _global_.wTools; + +const _ObjectHasOwnProperty = Object.hasOwnProperty; +const _ObjectPropertyIsEumerable = Object.propertyIsEnumerable; +// let _nameFielded = _.nameFielded; + +_.assert( _.object.isBasic( _.props ), 'wProto needs Tools/wtools/abase/l1/FieldMapper.s' ); +// _.assert( _.routineIs( _nameFielded ), 'wProto needs Tools/wtools/l3/NameTools.s' ); + +// -- +// prototype +// -- + +/** + * Make united interface for several maps. Access to single map cause read and write to original maps. + * @param {array} protos - maps to united. + * @return {object} united interface. + * @function prototypeUnitedInterface + * @namespace Tools + * @module Tools/base/Proto + */ + +function prototypeUnitedInterface( protos ) +{ + let result = Object.create( null ); + let unitedArraySymbol = Symbol.for( '_unitedArray_' ); + let unitedMapSymbol = Symbol.for( '_unitedMap_' ); + let protoMap = Object.create( null ); + + _.assert( arguments.length === 1 ); + _.assert( _.arrayIs( protos ) ); + + /* */ + + for( let p = 0 ; p < protos.length ; p++ ) + { + let proto = protos[ p ]; + for( let f in proto ) + { + if( f in protoMap ) + throw _.err( 'prototypeUnitedInterface :', 'several objects try to unite have same field :', f ); + protoMap[ f ] = proto; + + let methods = Object.create( null ) + methods[ f + 'Get' ] = get( f ); + methods[ f + 'Set' ] = set( f ); + let names = Object.create( null ); + names[ f ] = f; + _.accessor.declare + ({ + object : result, + names, + methods, + strict : 0, + prime : 0, + }); + + } + } + + /*result[ unitedArraySymbol ] = protos;*/ + result[ unitedMapSymbol ] = protoMap; + + return result; + + /* */ + + function get( propName ) + { + return function unitedGet() + { + return this[ unitedMapSymbol ][ propName ][ propName ]; + } + } + function set( propName ) + { + return function unitedSet( value ) + { + this[ unitedMapSymbol ][ propName ][ propName ] = value; + } + } +} + +// + +/** + * Append prototype to object. Find archi parent and replace its proto. + * @param {object} dstMap - dst object to append proto. + * @function prototypeAppend + * @namespace Tools + * @module Tools/base/Proto + */ + +function prototypeAppend( dstMap ) +{ + + _.assert( _.object.isBasic( dstMap ) ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + let proto = arguments[ a ]; + + _.assert( _.object.isBasic( proto ) ); + + let parent = _.prototypeArchyGet( dstMap ); + Object.setPrototypeOf( parent, proto ); + + } + + return dstMap; +} + +// + +/** + * Returns parent which has default proto. + * @param {object} srcPrototype - dst object to append proto. + * @function prototypeArchyGet + * @namespace Tools + * @module Tools/base/Proto + */ + +function prototypeArchyGet( srcPrototype ) +{ + + _.assert( _.object.isBasic( srcPrototype ) ); + + while( Object.getPrototypeOf( srcPrototype ) !== Object.prototype ) + srcPrototype = Object.getPrototypeOf( srcPrototype ); + + return srcPrototype; +} + +// + +/* +_.prototypeCrossRefer +({ + namespace : _, + entities : + { + System : Self, + }, + names : + { + System : 'LiveSystem', + Node : 'LiveNode', + }, +}); +*/ + +let _protoCrossReferAssociations = Object.create( null ); +function prototypeCrossRefer( o ) +{ + let names = _.props.keys( o.entities ); + let length = names.length; + + let association = _protoCrossReferAssociations[ o.name ]; + if( !association ) + { + _.assert( _protoCrossReferAssociations[ o.name ] === undefined ); + association = _protoCrossReferAssociations[ o.name ] = Object.create( null ); + association.name = o.name; + association.length = length; + association.have = 0; + association.entities = _.props.extend( null, o.entities ); + } + else + { + _.assert( _.arraySetIdentical( _.props.keys( association.entities ), _.props.keys( o.entities ) ), 'cross reference should have same associations' ); + } + + _.assert( association.name === o.name ); + _.assert( association.length === length ); + + for( let e in o.entities ) + { + if( !association.entities[ e ] ) + association.entities[ e ] = o.entities[ e ]; + else if( o.entities[ e ] ) + _.assert( association.entities[ e ] === o.entities[ e ] ); + } + + association.have = 0; + for( let e in association.entities ) + if( association.entities[ e ] ) + association.have += 1; + + if( association.have === association.length ) + { + + for( let src in association.entities ) + for( let dst in association.entities ) + { + if( src === dst ) + continue; + let dstEntity = association.entities[ dst ]; + let srcEntity = association.entities[ src ]; + _.assert( !dstEntity[ src ] || dstEntity[ src ] === srcEntity, 'override of entity', src ); + _.assert( !dstEntity.prototype[ src ] || dstEntity.prototype[ src ] === srcEntity ); + _.classExtend( dstEntity, { Statics : { [ src ] : srcEntity } } ); + _.assert( dstEntity[ src ] === srcEntity ); + _.assert( dstEntity.prototype[ src ] === srcEntity ); + } + + _protoCrossReferAssociations[ o.name ] = null; + + return true; + } + + return false; +} + +prototypeCrossRefer.defaults = +{ + entities : null, + name : null, +} + +// -- +// proxy +// -- + +function proxyNoUndefined( ins ) +{ + + let validator = + { + set : function( obj, k, e ) + { + if( obj[ k ] === undefined ) + throw _.err( 'Map does not have field', k ); + obj[ k ] = e; + return true; + }, + get : function( obj, k ) + { + if( !_.symbolIs( k ) ) + if( obj[ k ] === undefined ) + throw _.err( 'Map does not have field', k ); + return obj[ k ]; + }, + + } + + let result = new Proxy( ins, validator ); + + return result; +} + +// + +function proxyReadOnly( ins ) +{ + + let validator = + { + set : function( obj, k, e ) + { + throw _.err( 'Read only', _.entity.strType( ins ), ins ); + } + } + + let result = new Proxy( ins, validator ); + + return result; +} + +// + +function ifDebugProxyReadOnly( ins ) +{ + + if( !Config.debug ) + return ins; + + return _.proxyReadOnly( ins ); +} + +// + +// function proxyMap( front, back ) +function proxyMap( o ) +{ + + if( arguments.length === 2 ) + o = { front : arguments[ 0 ], back : arguments[ 1 ] } + o = _.routine.options_( proxyMap, o ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( !!o.front ); + _.assert( !!o.back ); + let back = o.back; + + let handler = + { + get : function( front, key, proxy ) + { + if( front[ key ] !== undefined ) + return front[ key ]; + return back[ key ]; + }, + set : function( front, key, val, proxy ) + { + if( front[ key ] !== undefined ) + front[ key ] = val; + else if( back[ key ] !== undefined ) + back[ key ] = val; + else + front[ key ] = val; + return true; + }, + } + + let result = new Proxy( o.front, handler ); + + return result; +} + +proxyMap.defaults = +{ + front : null, + back : null, +} + +// + +function proxyShadow( o ) +{ + + if( arguments.length === 2 ) + o = { front : arguments[ 0 ], back : arguments[ 1 ] } + o = _.routine.options_( proxyShadow, o ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( !!o.front ); + _.assert( !!o.back ); + let front = o.front; + + let handler = + { + get : function( back, key, context ) + { + if( front[ key ] !== undefined ) + return front[ key ]; + return Reflect.get( ... arguments ); + }, + set : function( back, key, val, context ) + { + if( front[ key ] !== undefined ) + { + front[ key ] = val; + return true; + } + return Reflect.set( ... arguments ); + }, + }; + + let shadowProxy = new Proxy( o.back, handler ); + + return shadowProxy; +} + +proxyShadow.defaults = +{ + front : null, + back : null, +} + +// -- +// default +// -- + +/* +apply default to each element of map, if present +*/ + +function defaultApply( src ) +{ + + _.assert( _.object.isBasic( src ) || _.longIs( src ) ); + + let defVal = src[ _.def ]; + + if( !defVal ) + return src; + + _.assert( _.object.isBasic( src ) ); + + if( _.object.isBasic( src ) ) + { + + for( let s in src ) + { + if( !_.object.isBasic( src[ s ] ) ) + continue; + _.props.supplement( src[ s ], defVal ); + } + + } + else + { + + for( let s = 0 ; s < src.length ; s++ ) + { + if( !_.object.isBasic( src[ s ] ) ) + continue; + _.props.supplement( src[ s ], defVal ); + } + + } + + return src; +} + +// + +/* +activate default proxy +*/ + +function defaultProxy( map ) +{ + + _.assert( _.object.isBasic( map ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + let validator = + { + set : function( obj, k, e ) + { + obj[ k ] = _.defaultApply( e ); + return true; + } + } + + let result = new Proxy( map, validator ); + + for( let k in map ) + { + _.defaultApply( map[ k ] ); + } + + return result; +} + +// + +function defaultProxyFlatteningToArray( src ) +{ + let result = []; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.object.isBasic( src ) || _.arrayIs( src ) ); + + function flatten( src ) + { + + if( _.arrayIs( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + flatten( src[ s ] ); + } + else + { + if( _.object.isBasic( src ) ) + result.push( defaultApply( src ) ); + else + result.push( src ); + } + + } + + flatten( src ); + + return result; +} + +// -- +// type +// -- + +class wCallableObject extends Function +{ + constructor() + { + super( 'return this.routine.__call__.apply( this.routine, arguments );' ); + let context = Object.create( null ); + let routine = this.bind( context ); + context.routine = routine; + Object.freeze( context ); + return routine; + } +} + +wCallableObject.shortName = 'CallableObject'; + +_.assert( wCallableObject.shortName === 'CallableObject' ); + +// -- +// fields +// -- + +/** + * @typedef {Object} DefaultFieldsGroups - contains predefined class fields groups. + * @module Tools/base/Proto + */ + +/** + * @typedef {Object} DefaultFieldsGroupsRelations - contains predefined class relationship types. + * @module Tools/base/Proto + */ + +/** + * @typedef {Object} DefaultFieldsGroupsCopyable - contains predefined copyable class fields groups. + * @module Tools/base/Proto + */ + +/** + * @typedef {Object} DefaultFieldsGroupsTight + * @module Tools/base/Proto + */ + +/** + * @typedef {Object} DefaultFieldsGroupsInput + * @module Tools/base/Proto + */ + +/** + * @typedef {Object} DefaultForbiddenNames - contains names of forbidden properties + * @module Tools/base/Proto + */ + +let DefaultFieldsGroups = Object.create( null ); +DefaultFieldsGroups.Groups = 'Groups'; +DefaultFieldsGroups.Composes = 'Composes'; +DefaultFieldsGroups.Aggregates = 'Aggregates'; +DefaultFieldsGroups.Associates = 'Associates'; +DefaultFieldsGroups.Restricts = 'Restricts'; +DefaultFieldsGroups.Medials = 'Medials'; +DefaultFieldsGroups.Statics = 'Statics'; +DefaultFieldsGroups.Copiers = 'Copiers'; +Object.freeze( DefaultFieldsGroups ); + +let DefaultFieldsGroupsRelations = Object.create( null ); +DefaultFieldsGroupsRelations.Composes = 'Composes'; +DefaultFieldsGroupsRelations.Aggregates = 'Aggregates'; +DefaultFieldsGroupsRelations.Associates = 'Associates'; +DefaultFieldsGroupsRelations.Restricts = 'Restricts'; +Object.freeze( DefaultFieldsGroupsRelations ); + +let DefaultFieldsGroupsCopyable = Object.create( null ); +DefaultFieldsGroupsCopyable.Composes = 'Composes'; +DefaultFieldsGroupsCopyable.Aggregates = 'Aggregates'; +DefaultFieldsGroupsCopyable.Associates = 'Associates'; +Object.freeze( DefaultFieldsGroupsCopyable ); + +let DefaultFieldsGroupsTight = Object.create( null ); +DefaultFieldsGroupsTight.Composes = 'Composes'; +DefaultFieldsGroupsTight.Aggregates = 'Aggregates'; +Object.freeze( DefaultFieldsGroupsTight ); + +let DefaultFieldsGroupsInput = Object.create( null ); +DefaultFieldsGroupsInput.Composes = 'Composes'; +DefaultFieldsGroupsInput.Aggregates = 'Aggregates'; +DefaultFieldsGroupsInput.Associates = 'Associates'; +DefaultFieldsGroupsInput.Medials = 'Medials'; +Object.freeze( DefaultFieldsGroupsInput ); + +let DefaultForbiddenNames = Object.create( null ); +DefaultForbiddenNames.Static = 'Static'; +DefaultForbiddenNames.Type = 'Type'; +Object.freeze( DefaultForbiddenNames ); + +// -- +// define +// -- + +let ToolsExtension = +{ + + // prototype + + prototypeUnitedInterface, /* experimental */ + + prototypeAppend, /* experimental */ + prototypeArchyGet, /* experimental */ + + prototypeCrossRefer, /* experimental */ + + // proxy + + proxyNoUndefined, + proxyReadOnly, + ifDebugProxyReadOnly, + proxyMap, + proxyShadow, + + // default + + defaultApply, + defaultProxy, + defaultProxyFlatteningToArray, + + // fields + + DefaultFieldsGroups, + DefaultFieldsGroupsRelations, + DefaultFieldsGroupsCopyable, + DefaultFieldsGroupsTight, + DefaultFieldsGroupsInput, + + DefaultForbiddenNames, + CallableObject : wCallableObject, + +} + +// + +_.props.extend( _, ToolsExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/l1/Proto.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Proto_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Proto_s */ })(); + +/* */ /* begin of file Workpiece_s */ ( function Workpiece_s() { function Workpiece_s_naked() { ( function _Workpiece_s_() { + +'use strict'; + +/** +* @namespace wTools.workpiece +* @extends Tools +* @module Tools/base/Proto +*/ + +const _global = _global_; +const _ = _global_.wTools; +_.workpiece = _.workpiece || Object.create( null );; +const _ObjectHasOwnProperty = Object.hasOwnProperty; + +_.assert( _.object.isBasic( _.props ), 'wProto needs Tools/wtools/abase/l1/FieldMapper.s' ); + +// -- +// prototype +// -- + +function prototypeIsStandard( src ) +{ + + if( !_.workpiece.prototypeIs( src ) ) + return false; + + if( !Object.hasOwnProperty.call( src, 'Composes' ) ) + return false; + + return true; +} + +// + +function prototypeOf( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument, probably you want routine isPrototypeOf' ); + + if( !( 'constructor' in src ) ) + return null; + + let c = _.workpiece.constructorOf( src ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + + return c.prototype; +} + +// + +function prototypeHasField( src, propName ) +{ + let prototype = _.workpiece.prototypeOf( src ); + + _.assert( _.workpiece.prototypeIsStandard( prototype ), 'Expects standard prototype' ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( propName ) ); + + for( let f in _.DefaultFieldsGroupsRelations ) + if( prototype[ f ][ propName ] !== undefined ) + return true; + + return false; +} + +// + +function prototypeAndConstructorOf( o ) +{ + let result = Object.create( null ); + + if( !result.cls ) + if( o.prototype ) + result.cls = o.prototype.constructor; + + if( !result.cls ) + if( o.extend ) + if( o.extend.constructor !== Object.prototype.constructor ) + result.cls = o.extend.constructor; + + if( !result.cls ) + if( o.usingStatics && o.extend && o.extend.Statics ) + if( o.extend.Statics.constructor !== Object.prototype.constructor ) + result.cls = o.extend.Statics.constructor; + + if( !result.cls ) + if( o.supplement ) + if( o.supplement.constructor !== Object.prototype.constructor ) + result.cls = o.supplement.constructor; + + if( !result.cls ) + if( o.usingStatics && o.supplement && o.supplement.Statics ) + if( o.supplement.Statics.constructor !== Object.prototype.constructor ) + result.cls = o.supplement.Statics.constructor; + + if( o.prototype ) + result.prototype = o.prototype; + else if( result.cls ) + result.prototype = result.cls.prototype; + + if( o.prototype ) + _.assert( result.cls === o.prototype.constructor ); + + return result; +} + +// -- +// constructor +// -- + +/** + * Get parent's constructor. + * @function parentOf + * @namespace Tools + * @module Tools/base/Proto + */ + +function parentOf( src ) +{ + let c = _.workpiece.constructorOf( src ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let proto = Object.getPrototypeOf( c.prototype ); + let result = proto ? proto.constructor : null; + + return result; +} + +// + +function constructorIsStandard( cls ) +{ + + _.assert( _.constructorIs( cls ) ); + + let prototype = _.workpiece.prototypeOf( cls ); + + return _.workpiece.prototypeIsStandard( prototype ); +} + +// + +function constructorOf( src ) +{ + let proto; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _ObjectHasOwnProperty.call( src, 'constructor' ) ) + { + proto = src; /* proto */ + } + else if( _ObjectHasOwnProperty.call( src, 'prototype' ) ) + { + if( src.prototype ) + proto = src.prototype; /* constructor */ + else + proto = Object.getPrototypeOf( Object.getPrototypeOf( src ) ); /* instance behind ruotine */ + } + else + { + proto = Object.getPrototypeOf( src ); /* instance */ + } + + if( proto === null ) + return null; + else + return proto.constructor; +} + +// -- +// instance +// -- + +function instanceIsStandard( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( !_.instanceIs( src ) ) + return false; + + let proto = _.workpiece.prototypeOf( src ); + + if( !proto ) + return false; + + return _.workpiece.prototypeIsStandard( proto ); +} + +// + +function instanceLikeStandard( src ) +{ + if( _.primitiveIs( src ) ) + return false; + if( src.Composes ) + return true; + return false; +} + +// -- +// fields group +// -- + +function fieldsGroupsGet( src ) +{ + // _.assert( _.object.isBasic( src ), () => 'Expects map {-src-}, but got ' + _.entity.strType( src ) ); + _.assert( !_.primitiveIs( src ), () => 'Expects map {-src-}, but got ' + _.entity.strType( src ) ); + _.assert( src.Groups === undefined || _.object.isBasic( src.Groups ) ); + + if( src.Groups ) + return src.Groups; + + return _.DefaultFieldsGroups; +} + +// + +function fieldsGroupFor( dst, fieldsGroupName ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( fieldsGroupName ) ); + _.assert( !_.primitiveIs( dst ) ); + + if( !_ObjectHasOwnProperty.call( dst, fieldsGroupName ) ) + { + let field = dst[ fieldsGroupName ]; + dst[ fieldsGroupName ] = Object.create( null ); + if( field ) + Object.setPrototypeOf( dst[ fieldsGroupName ], field ); + } + + if( Config.debug ) + { + let parent = Object.getPrototypeOf( dst ); + if( parent && parent[ fieldsGroupName ] ) + _.assert( Object.getPrototypeOf( dst[ fieldsGroupName ] ) === parent[ fieldsGroupName ] ); + } + + return dst; +} + +// + +/** +* Default options for fieldsGroupDeclare function +* @typedef {object} wTools~protoAddDefaults +* @property {object} [ o.fieldsGroupName=null ] - object that contains class relationship type name. +* Example : { Composes : 'Composes' }. See {@link wTools~DefaultFieldsGroupsRelations} +* @property {object} [ o.dstPrototype=null ] - prototype of class which will get new constant property. +* @property {object} [ o.srcMap=null ] - name/value map of defaults. +* @property {bool} [ o.extending=false ] - to extending defaults if exist. +*/ + +/** + * Adds own defaults to object. Creates new defaults container, if there is no such own. + * @param {wTools~protoAddDefaults} o - options {@link wTools~protoAddDefaults}. + * @private + * + * @example + * const Self = ClassName; +function ClassName( o ) { }; + * _.workpiece.fieldsGroupDeclare + * ({ + * fieldsGroupName : { Composes : 'Composes' }, + * dstPrototype : Self.prototype, + * srcMap : { a : 1, b : 2 }, + * }); + * console.log( Self.prototype ); // returns { Composes: { a: 1, b: 2 } } + * + * @function fieldsGroupDeclare + * @throws {exception} If no argument provided. + * @throws {exception} If( o.srcMap ) is not a Object. + * @throws {exception} If( o ) is extented by unknown property. + * @namespace Tools.workpiece + */ + +function fieldsGroupDeclare( o ) +{ + o = o || Object.create( null ); + + _.routine.options_( fieldsGroupDeclare, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( o.srcMap === null || !_.primitiveIs( o.srcMap ), 'Expects object {-o.srcMap-}, got', _.entity.strType( o.srcMap ) ); + _.assert( _.strIs( o.fieldsGroupName ) ); + // _.assert( _.routineIs( o.filter ) && _.strIs( o.filter.functionFamily ) ); + _.assert( _.props.transformerIs( o.filter ) ); + + _.workpiece.fieldsGroupFor( o.dstPrototype, o.fieldsGroupName ); + + let fieldGroup = o.dstPrototype[ o.fieldsGroupName ]; + + if( o.srcMap ) + _.mapExtendConditional( o.filter, fieldGroup, o.srcMap ); + +} + +fieldsGroupDeclare.defaults = +{ + dstPrototype : null, + srcMap : null, + filter : _.props.mapper.bypass(), + fieldsGroupName : null, +} + +// + +/** + * Adds own defaults( Composes ) to object. Creates new defaults container, if there is no such own. + * @param {array-like} arguments - for arguments details see {@link wTools~protoAddDefaults}. + * + * @example + * const Self = ClassName; +function ClassName( o ) { }; + * let Composes = { tree : null }; + * _.workpiece.fieldsGroupComposesExtend( Self.prototype, Composes ); + * console.log( Self.prototype ); // returns { Composes: { tree: null } } + * + * @function _.workpiece.fieldsGroupComposesExtend + * @throws {exception} If no arguments provided. + * @namespace Tools.workpiece + */ + +function fieldsGroupComposesExtend( dstPrototype, srcMap ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + let fieldsGroupName = 'Composes'; + return _.workpiece.fieldsGroupDeclare + ({ + fieldsGroupName, + dstPrototype, + srcMap, + // filter : _.props.mapper.bypass(), + }); + +} + +// + +/** + * Adds own aggregates to object. Creates new aggregates container, if there is no such own. + * @param {array-like} arguments - for arguments details see {@link wTools~protoAddDefaults}. + * + * @example + * const Self = ClassName; +function ClassName( o ) { }; + * let Aggregates = { tree : null }; + * _.workpiece.fieldsGroupAggregatesExtend( Self.prototype, Aggregates ); + * console.log( Self.prototype ); // returns { Aggregates: { tree: null } } + * + * @function fieldsGroupAggregatesExtend + * @throws {exception} If no arguments provided. + * @namespace Tools.workpiece + */ + +function fieldsGroupAggregatesExtend( dstPrototype, srcMap ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + let fieldsGroupName = 'Aggregates'; + return _.workpiece.fieldsGroupDeclare + ({ + fieldsGroupName, + dstPrototype, + srcMap, + // filter : _.props.mapper.bypass(), + }); + +} + +// + +/** + * Adds own associates to object. Creates new associates container, if there is no such own. + * @param {array-like} arguments - for arguments details see {@link wTools~protoAddDefaults}. + * + * @example + * const Self = ClassName; +function ClassName( o ) { }; + * let Associates = { tree : null }; + * _.workpiece.fieldsGroupAssociatesExtend( Self.prototype, Associates ); + * console.log( Self.prototype ); // returns { Associates: { tree: null } } + * + * @function fieldsGroupAssociatesExtend + * @throws {exception} If no arguments provided. + * @namespace Tools.workpiece + */ + +function fieldsGroupAssociatesExtend( dstPrototype, srcMap ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + let fieldsGroupName = 'Associates'; + return _.workpiece.fieldsGroupDeclare + ({ + fieldsGroupName, + dstPrototype, + srcMap, + // filter : _.props.mapper.bypass(), + }); + +} + +// + +/** + * Adds own restricts to object. Creates new restricts container, if there is no such own. + * @param {array-like} arguments - for arguments details see {@link wTools~protoAddDefaults}. + * + * @example + * const Self = ClassName; +function ClassName( o ) { }; + * let Restricts = { tree : null }; + * _.workpiece.fieldsGroupRestrictsExtend( Self.prototype, Restricts ); + * console.log( Self.prototype ); // returns { Restricts: { tree: null } } + * + * @function _.workpiece.fieldsGroupRestrictsExtend + * @throws {exception} If no arguments provided. + * @namespace Tools.workpiece + */ + +function fieldsGroupRestrictsExtend( dstPrototype, srcMap ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + let fieldsGroupName = 'Restricts'; + return _.workpiece.fieldsGroupDeclare + ({ + fieldsGroupName, + dstPrototype, + srcMap, + // filter : _.props.mapper.bypass(), + }); + +} + +// + +/** + * Adds own defaults( Composes ) to object. Creates new defaults container, if there is no such own. + * @param {array-like} arguments - for arguments details see {@link wTools~protoAddDefaults}. + * + * @example + * const Self = ClassName; +function ClassName( o ) { }; + * let Composes = { tree : null }; + * _.workpiece.fieldsGroupComposesSupplement( Self.prototype, Composes ); + * console.log( Self.prototype ); // returns { Composes: { tree: null } } + * + * @function fieldsGroupComposesSupplement + * @throws {exception} If no arguments provided. + * @namespace Tools.workpiece + */ + +function fieldsGroupComposesSupplement( dstPrototype, srcMap ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + let fieldsGroupName = 'Composes'; + return _.workpiece.fieldsGroupDeclare + ({ + fieldsGroupName, + dstPrototype, + srcMap, + filter : _.props.mapper.dstNotHas(), + }); + +} + +// + +/** + * Adds own aggregates to object. Creates new aggregates container, if there is no such own. + * @param {array-like} arguments - for arguments details see {@link wTools~protoAddDefaults}. + * + * @example + * const Self = ClassName; +function ClassName( o ) { }; + * let Aggregates = { tree : null }; + * _.workpiece.fieldsGroupAggregatesSupplement( Self.prototype, Aggregates ); + * console.log( Self.prototype ); // returns { Aggregates: { tree: null } } + * + * @function _.workpiece.fieldsGroupAggregatesSupplement + * @throws {exception} If no arguments provided. + * @namespace Tools.workpiece + */ + +function fieldsGroupAggregatesSupplement( dstPrototype, srcMap ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + let fieldsGroupName = 'Aggregates'; + return _.workpiece.fieldsGroupDeclare + ({ + fieldsGroupName, + dstPrototype, + srcMap, + filter : _.props.mapper.dstNotHas(), + }); + +} + +// + +/** + * Adds own associates to object. Creates new associates container, if there is no such own. + * @param {array-like} arguments - for arguments details see {@link wTools~protoAddDefaults}. + * + * @example + * const Self = ClassName; +function ClassName( o ) { }; + * let Associates = { tree : null }; + * _.workpiece.fieldsGroupAssociatesSupplement( Self.prototype, Associates ); + * console.log( Self.prototype ); // returns { Associates: { tree: null } } + * + * @function fieldsGroupAssociatesSupplement + * @throws {exception} If no arguments provided. + * @namespace Tools.workpiece + */ + +function fieldsGroupAssociatesSupplement( dstPrototype, srcMap ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + let fieldsGroupName = 'Associates'; + return _.workpiece.fieldsGroupDeclare + ({ + fieldsGroupName, + dstPrototype, + srcMap, + filter : _.props.mapper.dstNotHas(), + }); + +} + +// + +/** + * Adds own restricts to object. Creates new restricts container, if there is no such own. + * @param {array-like} arguments - for arguments details see {@link wTools~protoAddDefaults}. + * + * @example + * const Self = ClassName; +function ClassName( o ) { }; + * let Restricts = { tree : null }; + * _.workpiece.fieldsGroupRestrictsSupplement( Self.prototype, Restricts ); + * console.log( Self.prototype ); // returns { Restricts: { tree: null } } + * + * @function fieldsGroupRestrictsSupplement + * @throws {exception} If no arguments provided. + * @namespace Tools.workpiece + */ + +function fieldsGroupRestrictsSupplement( dstPrototype, srcMap ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + let fieldsGroupName = 'Restricts'; + return _.workpiece.fieldsGroupDeclare + ({ + fieldsGroupName, + dstPrototype, + srcMap, + filter : _.props.mapper.dstNotHas(), + }); + +} + +// + +function fieldsOfRelationsGroupsFromPrototype( src ) +{ + let prototype = src; + let result = Object.create( null ); + + // _.assert( !_.primitiveIs( prototype ) ); + _.assert( !_.primitiveIs( prototype ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + for( let g in _.DefaultFieldsGroupsRelations ) + { + if( src[ g ] ) + _.props.extend( result, src[ g ] ); + } + + return result; +} + +// + +function fieldsOfCopyableGroupsFromPrototype( src ) +{ + let prototype = src; + let result = Object.create( null ); + + _.assert( !_.primitiveIs( prototype ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + for( let g in _.DefaultFieldsGroupsCopyable ) + { + if( src[ g ] ) + _.props.extend( result, src[ g ] ); + } + + return result; +} + +// + +function fieldsOfTightGroupsFromPrototype( src ) +{ + let prototype = src; + let result = Object.create( null ); + + _.assert( !_.primitiveIs( prototype ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + for( let g in _.DefaultFieldsGroupsTight ) + { + if( src[ g ] ) + _.props.extend( result, src[ g ] ); + } + + return result; +} + +// + +function fieldsOfInputGroupsFromPrototype( src ) +{ + let prototype = src; + let result = Object.create( null ); + + _.assert( !_.primitiveIs( prototype ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + for( let g in _.DefaultFieldsGroupsInput ) + { + if( src[ g ] ) + _.props.extend( result, src[ g ] ); + } + + return result; +} + +// + +function fieldsOfRelationsGroups( src ) +{ + let prototype = src; + + if( !_.workpiece.prototypeIs( prototype ) ) + prototype = _.workpiece.prototypeOf( src ); + + _.assert( _.workpiece.prototypeIs( prototype ) ); + _.assert( _.workpiece.prototypeIsStandard( prototype ), 'Expects standard prototype' ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.instanceIs( src ) ) + { + return _.mapOnly_( null, src, _.workpiece.fieldsOfRelationsGroupsFromPrototype( prototype ) ); + } + + return _.workpiece.fieldsOfRelationsGroupsFromPrototype( prototype ); +} + +// + +function fieldsOfCopyableGroups( src ) +{ + let prototype = src; + + if( !_.workpiece.prototypeIs( prototype ) ) + prototype = _.workpiece.prototypeOf( src ); + + _.assert( _.workpiece.prototypeIs( prototype ) ); + _.assert( _.workpiece.prototypeIsStandard( prototype ), 'Expects standard prototype' ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.instanceIs( src ) ) + return _.mapOnly_( null, src, _.workpiece.fieldsOfCopyableGroupsFromPrototype( prototype ) ); + + return _.workpiece.fieldsOfCopyableGroupsFromPrototype( prototype ); +} + +// + +function fieldsOfTightGroups( src ) +{ + let prototype = src; + + if( !_.workpiece.prototypeIs( prototype ) ) + prototype = _.workpiece.prototypeOf( src ); + + _.assert( _.workpiece.prototypeIs( prototype ) ); + _.assert( _.workpiece.prototypeIsStandard( prototype ), 'Expects standard prototype' ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.instanceIs( src ) ) + return _.mapOnly_( null, src, _.workpiece.fieldsOfTightGroupsFromPrototype( prototype ) ); + + return _.workpiece.fieldsOfTightGroupsFromPrototype( prototype ); +} + +// + +function fieldsOfInputGroups( src ) +{ + let prototype = src; + + if( !_.workpiece.prototypeIs( prototype ) ) + prototype = _.workpiece.prototypeOf( src ); + + _.assert( _.workpiece.prototypeIs( prototype ) ); + _.assert( _.workpiece.prototypeIsStandard( prototype ), 'Expects standard prototype' ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.instanceIs( src ) ) + return _.mapOnly_( null, src, _.workpiece.fieldsOfInputGroupsFromPrototype( prototype ) ); + + return _.workpiece.fieldsOfInputGroupsFromPrototype( prototype ); +} + +// + +function fieldsGroupsDeclare( o ) +{ + + _.routine.options_( fieldsGroupsDeclare, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( o.srcMap === null || !_.primitiveIs( o.srcMap ), 'Expects object {-o.srcMap-}, got', _.entity.strType( o.srcMap ) ); + + if( !o.srcMap ) + return; + + if( !o.fieldsGroups ) + o.fieldsGroups = _.workpiece.fieldsGroupsGet( o.dstPrototype ); + + _.assert( _.prototype.isSubPrototypeOf( o.fieldsGroups, _.DefaultFieldsGroups ) ); + + for( let f in o.fieldsGroups ) + { + + if( !o.srcMap[ f ] ) + continue; + + _.workpiece.fieldsGroupDeclare + ({ + fieldsGroupName : f, + dstPrototype : o.dstPrototype, + srcMap : o.srcMap[ f ], + filter : o.filter, + }); + + if( !_.DefaultFieldsGroupsRelations[ f ] ) + continue; + + if( Config.debug ) + { + for( let f2 in _.DefaultFieldsGroupsRelations ) + if( f2 === f ) + { + continue; + } + else for( let k in o.srcMap[ f ] ) + { + _.assert( o.dstPrototype[ f2 ][ k ] === undefined, 'Fields group', '"'+f2+'"', 'already has fields', '"'+k+'"', 'fields group', '"'+f+'"', 'should not have the same' ); + } + } + + } + +} + +fieldsGroupsDeclare.defaults = +{ + dstPrototype : null, + srcMap : null, + fieldsGroups : null, + filter : fieldsGroupDeclare.defaults.filter, +} + +// + +function fieldsGroupsDeclareForEachFilter( o ) +{ + + _.assert( arguments.length === 1 ); + _.routine.assertOptions( fieldsGroupsDeclareForEachFilter, arguments ); + _.map.assertHasNoUndefine( o ); + + let oldFieldsGroups = _.workpiece.fieldsGroupsGet( o.dstPrototype ); + let newFieldsGroups = Object.create( oldFieldsGroups ) + if( ( o.extendMap && o.extendMap.Groups ) || ( o.supplementOwnMap && o.supplementOwnMap.Groups ) || ( o.supplementMap && o.supplementMap.Groups ) ) + { + if( o.supplementMap && o.supplementMap.Groups ) + _.props.supplement( newFieldsGroups, o.supplementMap.Groups ); + if( o.supplementOwnMap && o.supplementOwnMap.Groups ) + _.mapExtendDstNotOwn( newFieldsGroups, o.supplementOwnMap.Groups ); + if( o.extendMap && o.extendMap.Groups ) + _.props.extend( newFieldsGroups, o.extendMap.Groups ); + } + + if( !o.dstPrototype.Groups ) + o.dstPrototype.Groups = Object.create( _.DefaultFieldsGroups ); + + for( let f in newFieldsGroups ) + _.workpiece.fieldsGroupFor( o.dstPrototype, f ); + + _.workpiece.fieldsGroupsDeclare + ({ + dstPrototype : o.dstPrototype, + srcMap : o.extendMap, + fieldsGroups : newFieldsGroups, + filter : _.props.mapper.bypass(), + }); + + _.workpiece.fieldsGroupsDeclare + ({ + dstPrototype : o.dstPrototype, + srcMap : o.supplementOwnMap, + fieldsGroups : newFieldsGroups, + filter : _.props.mapper.dstOwn(), + }); + + _.workpiece.fieldsGroupsDeclare + ({ + dstPrototype : o.dstPrototype, + srcMap : o.supplementMap, + fieldsGroups : newFieldsGroups, + filter : _.props.mapper.dstNotHas(), + }); + +} + +fieldsGroupsDeclareForEachFilter.defaults = +{ + dstPrototype : null, + extendMap : null, + supplementOwnMap : null, + supplementMap : null, +} + +// -- +// instance +// -- + +/* + usage : return _.workpiece.construct( Self, this, arguments ); + replacement for : + + _.assert( arguments.length === 0 || arguments.length === 1 ); + if( !( this instanceof Self ) ) + if( o instanceof Self ) + return o; + else + return new( _.constructorJoin( Self, arguments ) ); + return Self.prototype.init.apply( this, arguments ); + +*/ + +function construct( cls, context, args ) +{ + + _.assert( args.length === 0 || args.length === 1, () => `Expects optional argument, but got ${args.length} arguments` ); + _.assert( arguments.length === 3 ); + _.assert( _.routineIs( cls ) ); + _.assert( _.argumentsArray.like( args ) ); + + let o = args[ 0 ]; + + if( !( context instanceof cls ) ) + if( o instanceof cls ) + { + _.assert( args.length === 1 ); + return o; + } + else + { + if( args.length === 1 && _.argumentsArray.like( args[ 0 ] ) ) + { + let result = []; + for( let i = 0 ; i < args[ 0 ].length ; i++ ) + { + let o = args[ 0 ][ i ]; + if( o === null ) + continue; + if( o instanceof cls ) + result.push( o ); + else + result.push( new( _.constructorJoin( cls, [ o ] ) ) ); + } + return result; + } + else + { + return new( _.constructorJoin( cls, args ) ); + } + } + + // debugger; + // _.assert( 0 ); + return cls.prototype.init.apply( context, args ); +} + +// + +/** + * Is this instance finited. + * @function isFinited + * @param {object} src - instance of any class + * @namespace Tools.workpiece + * @module Tools/base/Proto + */ + +function isFinited( src ) +{ + _.assert( _.instanceIs( src ), () => 'Expects instance, but got ' + _.entity.exportStringDiagnosticShallow( src ) ) + _.assert( !_.primitiveIs( src ) ); + return Object.isFrozen( src ); +} + +// + +function finit( src ) +{ + + _.assert( !Object.isFrozen( src ), () => `Seems instance ${_.workpiece.qualifiedNameTry( src )} is already finited` ); + _.assert( !_.primitiveIs( src ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + // let validator = + // { + // set : function( obj, k, e ) + // { + // debugger; + // throw _.err( 'Attempt ot access to finited instance with field', k ); + // return false; + // }, + // get : function( obj, k, e ) + // { + // debugger; + // throw _.err( 'Attempt ot access to finited instance with field', k ); + // return false; + // }, + // } + // let result = new Proxy( src, validator ); + + Object.freeze( src ); +} + +// + +/** + * Complements instance by its semantic relations : Composes, Aggregates, Associates, Medials, Restricts. + * @param {object} instance - instance to complement. + * + * @example + * const Self = Alpha; +function Alpha( o ) { }; + * + * let Proto = { constructor: Self, Composes : { a : 1, b : 2 } }; + * + * _.classDeclare + * ({ + * constructor: Self, + * extend: Proto, + * }); + * let obj = new Self(); + * console.log( _.workpiece.initFields( obj ) ); //returns Alpha { a: 1, b: 2 } + * + * @return {object} Returns complemented instance. + * @function initFields + * @namespace Tools.workpiece + */ + +function initFields( instance, prototype ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( prototype === undefined || prototype === null ) + prototype = instance; + + _.mapSupplementOwnFromDefinitionStrictlyPrimitives( instance, prototype.Restricts ); + _.mapSupplementOwnFromDefinitionStrictlyPrimitives( instance, prototype.Composes ); + _.mapSupplementOwnFromDefinitionStrictlyPrimitives( instance, prototype.Aggregates ); + _.mapSupplementOwnFromDefinitionStrictlyPrimitives( instance, prototype.Associates ); + + return instance; +} + +// + +function initWithArguments( o ) +{ + + o = _.routine.options_( initWithArguments, arguments ); + _.assert( arguments.length === 1 ); + _.assert( o.args.length === 0 || o.args.length === 1 ); + _.workpiece.initFields( o.instance ); + + Object.preventExtensions( o.instance, o.prototype ); + + if( o.args[ 0 ] ) + o.instance.copy( o.args[ 0 ] ); + + return o.instance; +} + +initWithArguments.defaults = +{ + instance : null, + prototype : null, + args : null, +} + +// + +function initExtending( instance, prototype ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( prototype === undefined ) + prototype = instance; + + _.mapExtendConditional( _.props.mapper.assigning(), instance, prototype.Restricts ); + _.mapExtendConditional( _.props.mapper.assigning(), instance, prototype.Composes ); + _.mapExtendConditional( _.props.mapper.assigning(), instance, prototype.Aggregates ); + _.props.extend( instance, prototype.Associates ); + + return instance; +} + +// + +function initFilter( o ) +{ + + _.routine.options_( initFilter, o ); + _.assertOwnNoConstructor( o ); + _.assert( _.routineIs( o.cls ) ); + _.assert( !o.args || o.args.length === 0 || o.args.length === 1 ); + + let result = Object.create( null ); + + _.workpiece.initFields( result, o.cls.prototype ); + + if( o.args[ 0 ] ) + _.Copyable.prototype.copyCustom.call( o.cls.prototype, + { + proto : o.cls.prototype, + src : o.args[ 0 ], + dst : result, + technique : 'object', + }); + + if( !result.original ) + result.original = _.FileProvider.Default(); + + _.props.extend( result, o.extend ); + + Object.setPrototypeOf( result, result.original ); + + if( o.strict ) + Object.preventExtensions( result ); + + return result; +} + +initFilter.defaults = +{ + cls : null, + parent : null, + extend : null, + args : null, + strict : 1, +} + +// + +function singleFrom( src, cls ) +{ + cls = _.workpiece.constructorOf( cls ); + + _.assert( arguments.length === 2 ); + + if( src instanceof cls ) + return src; + return new( _.constructorJoin( cls, arguments ) ); +} + +// + +function from( srcs, cls ) +{ + cls = _.workpiece.constructorOf( cls ); + + _.assert( arguments.length === 2 ); + + if( srcs instanceof cls ) + { + return srcs; + } + + if( _.argumentsArray.like( srcs ) ) + { + debugger; + var result = _.container.map_( null, srcs, ( src ) => + { + return _.workpiece.singleFrom( src ); + }); + return result; + } + + return _.workpiece.singleFrom.call( srcs, cls ); +} + +// + +function lowClassName( instance ) +{ + _.assert( _.instanceIs( instance ) ); + _.assert( arguments.length === 1 ); + let name = _.workpiece.className( instance ); + name = _.strDecapitalize( name ); + return name; +} + +// + +function className( instance ) +{ + _.assert( _.instanceIs( instance ) ); + _.assert( arguments.length === 1 ); + let cls = _.workpiece.constructorOf( instance ); + _.assert( cls === null || _.strIs( cls.name ) || _.strIs( cls._name ) ); + return cls ? ( cls.name || cls._name ) : ''; +} + +// + +function qualifiedNameTry( instance ) +{ + try + { + let result = _.workpiece.qualifiedName( instance ); + return result; + } + catch( err ) + { + return ''; + } +} + +// + +function qualifiedName( instance ) +{ + _.assert( _.instanceIs( instance ) ); + _.assert( arguments.length === 1 ); + + if( _.routineIs( instance._qualifiedNameGet ) ) + return instance._qualifiedNameGet(); + + if( instance.qualifiedName !== undefined ) + { + _.assert( !_.routineIs( instance.qualifiedName ) ); + return instance.qualifiedName; + } + + return _.workpiece._qualifiedNameGet( instance ); +} + +// + +function _qualifiedNameGet( instance ) +{ + _.assert( _.instanceIs( instance ) ); + _.assert( arguments.length === 1 ); + + let name = ( instance.key || instance.name || '' ); + let index = ''; + + if( _.numberIs( instance.instanceIndex ) ) + name += '#in' + instance.instanceIndex; + if( Object.hasOwnProperty.call( instance, 'id' ) ) + name += '#id' + instance.id; + + let result = _.workpiece.className( instance ) + '::' + name; + + return result; +} + +// // +// +// function qualifiedName( instance ) +// { +// _.assert( _.instanceIs( instance ) ); +// _.assert( arguments.length === 1 ); +// +// let name = ( instance.key || instance.name || '' ); +// let index = ''; +// if( _.numberIs( instance.instanceIndex ) ) +// name += '#in' + instance.instanceIndex; +// if( Object.hasOwnProperty.call( instance, 'id' ) ) +// name += '#id' + instance.id; +// +// let result = _.workpiece.className( instance ) + '::' + name; +// +// return result; +// } + +// + +function uname( instance ) +{ + _.assert( _.instanceIs( instance ) ); + _.assert( arguments.length === 1 ); + let name = _.workpiece.className( instance ); + return '#id' + self.id + '::' + name; +} + +// + +function toStr( instance, options ) +{ + var result = ''; + var o = o || Object.create( null ); + + _.assert( _.instanceIs( instance ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( !o.jsLike && !o.jsonLike ) + result += _.workpiece.qualifiedName( instance ) + '\n'; + + var fields = _.workpiece.fieldsOfTightGroups( instance ); + + var t = _.entity.exportString( fields, o ); + _.assert( _.strIs( t ) ); + result += t; + + return result; +} + +// + +/** + * Make sure src does not have redundant fields. + * @param {object} src - source object of the class. + * @function assertDoesNotHaveReduntantFields + * @namespace Tools.workpiece + */ + +function assertDoesNotHaveReduntantFields( src ) +{ + + let Composes = src.Composes || Object.create( null ); + let Aggregates = src.Aggregates || Object.create( null ); + let Associates = src.Associates || Object.create( null ); + let Restricts = src.Restricts || Object.create( null ); + + _.assert( _.ojbectIs( src ) ) + _.map.assertOwnOnly( src, [ Composes, Aggregates, Associates, Restricts ] ); + + return dst; +} + +// + +function exportStructure( self, ... args ) +{ + let o = _.routine.options_( exportStructure, args ); + + _.assert( _.instanceIs( self ) ); + + if( o.src === null ) + o.src = self; + + if( o.dst === null ) + o.dst = Object.create( null ); + + o.dst = _.replicate + ({ + src : o.src, + dst : o.dst, + srcChanged, + // onSrcChanged, + ascend, + // onAscend : onAscend, + }); + + return o.dst; + + // function onSrcChanged() + function srcChanged() + { + let it = this; + + debugger; + it.Seeker.srcChanged.call( it ); + + if( !it.iterable ) + if( _.instanceIs( it.src ) ) + { + if( it.src === self ) + { + it.src = _.mapOnly_( null, it.src, it.src.Export || it.src.Import ); + it.iterable = _.looker.Looker.ContainerType.aux; + // it.iterable = _.looker.ContainerType.aux; + } + } + + } + + // function onAscend() + function ascend() + { + let it = this; + + if( !it.iterable && _.instanceIs( it.src ) ) + { + it.dst = _.routineCallButOnly( it.src, 'exportStructure', o, [ 'src', 'dst' ] ); + } + else + { + debugger; + _.looker.Looker.Iterator.call( this ); + // _.looker.Looker.Iterator.onAscend.call( this ); + } + + } + +} + +exportStructure.defaults = +{ + src : null, + dst : null, +} + +// + +function exportString( self, ... args ) +{ + let o = _.routine.options_( exportString, args ); + + _.assert( _.instanceIs( self ) ); + _.assert( o.style === 'nice' ); + + o.dst = o.dst || ''; + + if( o.src === null ) + o.src = _.routineCallButOnly( self, 'exportStructure', o, [ 'dst' ] ) + + o.dst += _.workpiece.qualifiedName( self ) + '\n'; + o.dst += _.entity.exportStringNice( o.src ); + + return o.dst; +} + +exportString.defaults = +{ + ... exportStructure.defaults, + dst : '', + src : null, + style : 'nice', + it : null, +} + +// -- +// fields +// -- + +/** + * @typedef {Object} KnownConstructorFields - contains fields allowed for class constructor. + * @property {String} name - full name + * @property {String} _name - private name + * @property {String} shortName - short name + * @property {Object} prototype - prototype object + * @module Tools/base/Proto + */ + +let KnownConstructorFields = +{ + name : null, + _name : null, + shortName : null, + prototype : null, +} + +/** + * @typedef {Object} DefaultFieldsGroups - contains predefined class fields groups. + * @module Tools/base/Proto + */ + +/** + * @typedef {Object} DefaultFieldsGroupsRelations - contains predefined class relationship types. + * @module Tools/base/Proto + */ + +/** + * @typedef {Object} DefaultFieldsGroupsCopyable - contains predefined copyable class fields groups. + * @module Tools/base/Proto + */ + +/** + * @typedef {Object} DefaultFieldsGroupsTight + * @module Tools/base/Proto + */ + +/** + * @typedef {Object} DefaultFieldsGroupsInput + * @module Tools/base/Proto + */ + +/** + * @typedef {Object} DefaultForbiddenNames - contains names of forbidden properties + * @module Tools/base/Proto + */ + +let DefaultFieldsGroups = Object.create( null ); +DefaultFieldsGroups.Groups = 'Groups'; +DefaultFieldsGroups.Composes = 'Composes'; +DefaultFieldsGroups.Aggregates = 'Aggregates'; +DefaultFieldsGroups.Associates = 'Associates'; +DefaultFieldsGroups.Restricts = 'Restricts'; +DefaultFieldsGroups.Medials = 'Medials'; +DefaultFieldsGroups.Statics = 'Statics'; +DefaultFieldsGroups.Copiers = 'Copiers'; +Object.freeze( DefaultFieldsGroups ); + +let DefaultFieldsGroupsRelations = Object.create( null ); +DefaultFieldsGroupsRelations.Composes = 'Composes'; +DefaultFieldsGroupsRelations.Aggregates = 'Aggregates'; +DefaultFieldsGroupsRelations.Associates = 'Associates'; +DefaultFieldsGroupsRelations.Restricts = 'Restricts'; +Object.freeze( DefaultFieldsGroupsRelations ); + +let DefaultFieldsGroupsCopyable = Object.create( null ); +DefaultFieldsGroupsCopyable.Composes = 'Composes'; +DefaultFieldsGroupsCopyable.Aggregates = 'Aggregates'; +DefaultFieldsGroupsCopyable.Associates = 'Associates'; +Object.freeze( DefaultFieldsGroupsCopyable ); + +let DefaultFieldsGroupsTight = Object.create( null ); +DefaultFieldsGroupsTight.Composes = 'Composes'; +DefaultFieldsGroupsTight.Aggregates = 'Aggregates'; +Object.freeze( DefaultFieldsGroupsTight ); + +let DefaultFieldsGroupsInput = Object.create( null ); +DefaultFieldsGroupsInput.Composes = 'Composes'; +DefaultFieldsGroupsInput.Aggregates = 'Aggregates'; +DefaultFieldsGroupsInput.Associates = 'Associates'; +DefaultFieldsGroupsInput.Medials = 'Medials'; +Object.freeze( DefaultFieldsGroupsInput ); + +let DefaultForbiddenNames = Object.create( null ); +DefaultForbiddenNames.Static = 'Static'; +DefaultForbiddenNames.Type = 'Type'; +Object.freeze( DefaultForbiddenNames ); + +// -- +// define +// -- + +let Extension = +{ + + // prototype + + prototypeIs : _.prototypeIs, + prototypeIsStandard, + prototypeOf, + prototypeHasField, + prototypeAndConstructorOf, + + // constructor + + parentOf, + constructorIs : _.constructorIs, + constructorIsStandard, + constructorOf, + classGet : constructorOf, + + // instance + + instanceIs : _.instanceIs, + instanceIsStandard, + instanceLikeStandard, + + // fields group + + fieldsGroupsGet, + fieldsGroupFor, /* experimental */ + fieldsGroupDeclare, /* experimental */ + + fieldsGroupComposesExtend, /* experimental */ + fieldsGroupAggregatesExtend, /* experimental */ + fieldsGroupAssociatesExtend, /* experimental */ + fieldsGroupRestrictsExtend, /* experimental */ + + fieldsGroupComposesSupplement, /* experimental */ + fieldsGroupAggregatesSupplement, /* experimental */ + fieldsGroupAssociatesSupplement, /* experimental */ + fieldsGroupRestrictsSupplement, /* experimental */ + + fieldsOfRelationsGroupsFromPrototype, + fieldsOfCopyableGroupsFromPrototype, + fieldsOfTightGroupsFromPrototype, + fieldsOfInputGroupsFromPrototype, + + fieldsOfRelationsGroups, + fieldsOfCopyableGroups, + fieldsOfTightGroups, + fieldsOfInputGroups, + + fieldsGroupsDeclare, + fieldsGroupsDeclareForEachFilter, + + // + + construct, + + isFinited, + finit, + + initFields, + initWithArguments, + initExtending, + initFilter, /* deprecated */ + + singleFrom, + from, + + lowClassName, + className, + qualifiedNameTry, + qualifiedName, + _qualifiedNameGet, + uname, + toStr, + + assertDoesNotHaveReduntantFields, + + // + + exportStructure, + exportString, + + // + + KnownConstructorFields, + + DefaultFieldsGroups, + DefaultFieldsGroupsRelations, + DefaultFieldsGroupsCopyable, + DefaultFieldsGroupsTight, + DefaultFieldsGroupsInput, + + DefaultForbiddenNames, + +} + +// + +/* _.props.extend */Object.assign( _.workpiece, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/l1/Workpiece.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Workpiece_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Workpiece_s */ })(); + +/* */ /* begin of file Accessor_s */ ( function Accessor_s() { function Accessor_s_naked() { ( function _Accessor_s_() { + +'use strict'; + +const Self = _global_.wTools; +const _global = _global_; +const _ = _global_.wTools; + +/** + * @summary Collection of getters + * @namespace wTools.accessor.getter + * @extends Tools.accessor + * @module Tools/base/Proto + */ + + /** + * @summary Collection of setters + * @namespace wTools.accessor.setter + * @extends Tools.accessor + * @module Tools/base/Proto + */ + + /** + * @summary Collection of putters + * @namespace wTools.accessor.putter + * @extends Tools.accessor + * @module Tools/base/Proto + */ + +/** + * @summary Collection of setters + * @namespace wTools.accessor.suite + * @extends Tools.accessor + * @module Tools/base/Proto + */ + +// -- +// declare +// -- + +/** + * Registers provided accessor. + * Writes accessor's descriptor into accessors map of the prototype ( o.proto ). + * Supports several combining methods: `rewrite`, `supplement`, `append`. + * * Adds diagnostic information to descriptor if running in debug mode. + * @param {Object} o - options map + * @param {String} o.name - accessor's name + * @param {Object} o.proto - target prototype object + * @param {String} o.declaratorName + * @param {Array} o.declaratorArgs + * @param {String} o.declaratorKind + * @param {String} o.combining - combining method + * @private + * @function _register + * @namespace Tools.accessor + */ + +function _register( o ) +{ + + _.routine.options_( _register, arguments ); + _.assert( _.workpiece.prototypeIsStandard( o.proto ), 'Expects formal prototype' ); + _.assert( _.strDefined( o.declaratorName ) ); + _.assert( _.arrayIs( o.declaratorArgs ) ); + _.workpiece.fieldsGroupFor( o.proto, '_Accessors' ); + + let accessors = o.proto._Accessors; + + if( o.combining && o.combining !== 'rewrite' && o.combining !== 'supplement' ) + debugger; + + if( Config.debug ) + if( !o.combining ) + { + let stack = accessors[ o.name ] ? accessors[ o.name ].stack : ''; + _.assert + ( + !accessors[ o.name ], + 'defined at' + '\n', + stack, + '\naccessor', o.name, 'of', o.proto.constructor.name + ); + if( accessors[ o.name ] ) + debugger; + } + + _.assert( !o.combining || o.combining === 'rewrite' || o.combining === 'append' || o.combining === 'supplement', 'not supported ( o.combining )', o.combining ); + _.assert( _.strIs( o.name ) ); + + if( accessors[ o.name ] && o.combining === 'supplement' ) + return; + + let descriptor = + { + name : o.name, + declaratorName : o.declaratorName, + declaratorArgs : o.declaratorArgs, + declaratorKind : o.declaratorKind, + combining : o.combining, + } + + // yyy + // if( Config.debug ) + // descriptor.stack = _.introspector.stack(); + + if( o.combining === 'append' ) + { + if( _.arrayIs( accessors[ o.name ] ) ) + accessors[ o.name ].push( descriptor ); + else + accessors[ o.name ] = [ descriptor ]; + } + + accessors[ o.name ] = descriptor; + + return descriptor; +} + +_register.defaults = +{ + name : null, + proto : null, + declaratorName : null, + declaratorArgs : null, + declaratorKind : null, + combining : 0, +} + +// + +/** + * @summary Supplements target object( dst ) with accessors from source object( src ). + * + * @description + * Both objects should have accessorts map defined. + * Ignores accessor that is already declared on destination object( dst ). + * + * @param {Object} src - source object + * @param {Object} dst - destination object + * + * @throws {Exception} If number of arguments is not supported. + * @throws {Exception} If combining method of source accessor is unknown. + * @throws {Exception} If accessor.declaratorArgs is not a Array. + * @throws {Exception} If one of object doesn't have _Accessors map + * @function supplement + * + * @namespace Tools.accessor + */ + +function supplement( dst, src ) +{ + + _.workpiece.fieldsGroupFor( dst, '_Accessors' ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( Object.hasOwnProperty.call( dst, '_Accessors' ), 'supplement : dst should has _Accessors map' ); + _.assert( Object.hasOwnProperty.call( src, '_Accessors' ), 'supplement : src should has _Accessors map' ); + + /* */ + + for( let a in src._Accessors ) + { + + let accessor = src._Accessors[ a ]; + + if( _.object.isBasic( accessor ) ) + supplement( a, accessor ); + else for( let i = 0 ; i < accessor.length ; i++ ) + supplement( a, accessor[ i ] ); + + } + + /* */ + + function supplement( name, accessor ) + { + + _.assert( _.arrayIs( accessor.declaratorArgs ) ); + _.assert( !accessor.combining || accessor.combining === 'rewrite' || accessor.combining === 'supplement' || accessor.combining === 'append', 'not implemented' ); + + if( _.object.isBasic( dst._Accessors[ name ] ) ) + return; + + if( accessor.declaratorName !== 'accessor' ) + { + _.assert( _.routineIs( dst[ accessor.declaratorName ] ), 'dst does not have accessor maker', accessor.declaratorName ); + dst[ accessor.declaratorName ].apply( dst, accessor.declaratorArgs ); + } + else + { + _.assert( accessor.declaratorArgs.length === 1 ); + let optionsForAccessor = _.props.extend( null, accessor.declaratorArgs[ 0 ] ); + optionsForAccessor.object = dst; + if( !optionsForAccessor.methods ) + optionsForAccessor.methods = dst; + _.accessor.declare( optionsForAccessor ); + } + + } + +} + +// -- +// etc +// -- + +/** + * Returns true if source object( proto ) has accessor with name( name ). + * @param {Object} proto - target object + * @param {String} name - name of accessor + * @function has + * @namespace Tools.accessor + */ + +function has( proto, name ) +{ + let accessors = proto._Accessors; + if( !accessors ) + return false; + return !!accessors[ name ]; +} + +// + +function suiteMakerFrom_functor( fop ) +{ + + if( arguments.length === 2 ) + fop = { getterFunctor : arguments[ 0 ], setterFunctor : arguments[ 1 ] } + + _.routine.options_( suiteMakerFrom_functor, fop ); + + let defaults; + if( fop.getterFunctor ) + defaults = _.props.extend( null, fop.getterFunctor.defaults ); + else + defaults = _.props.extend( null, fop.setterFunctor.defaults ); + + if( Config.debug ) + { + if( fop.getterFunctor ) + _.entity.identicalShallow( defaults, _.props.extend( null, fop.getterFunctor.defaults ) ) + // _.assert( _.entityIdentical( defaults, _.props.extend( null, fop.getterFunctor.defaults ) ) ); + if( fop.setterFunctor ) + _.entity.identicalShallow( defaults, _.props.extend( null, fop.setterFunctor.defaults ) ) + // _.assert( _.entityIdentical( defaults, _.props.extend( null, fop.setterFunctor.defaults ) ) ); + /* xxx : use _.identicalShallow() */ + } + + let _head = fop.getterFunctor.head || fop.setterFunctor.head; + if( _head ) + accessorMaker.head = head; + + accessorMaker.defaults = defaults; + + return accessorMaker; + + /* */ + + function head( routine, args ) + { + let o2 = _head( routine, args ); + return o2; + } + + /* */ + + function accessorMaker( o ) + { + let r = Object.create( null ); + + if( _head ) + o = head( accessorMaker, arguments ); + else + o = _.routine.options_( accessorMaker, arguments ); + + if( fop.setterFunctor ) + if( fop.setterFunctor.body ) + r.set = fop.setterFunctor.body( o ); + else + r.set = fop.setterFunctor( o ); + + if( fop.getterFunctor ) + if( fop.getterFunctor.body ) + r.get = fop.getterFunctor.body( o ); + else + r.get = fop.getterFunctor( o ); + + return r; + } + +} + +suiteMakerFrom_functor.defaults = +{ + getterFunctor : null, + setterFunctor : null, +} + +// -- +// meta +// -- + +function _DefinesGenerate( dst, src, kind ) +{ + if( dst === null ) + dst = Object.create( null ); + + _.assert( arguments.length === 3 ); + + for( let s in src ) + { + dst[ s ] = _DefineGenerate( src[ s ], kind ); + } + + return dst; +} + +// + +function _DefineGenerate( original, kind ) +{ + _.assert( _.routineIs( original ) ); + + let r = + { + [ original.name ] : function() + { + let definition = _.define[ kind ]({ val : arguments, routine : original }); + _.assert( _.definitionIs( definition ) ); + return definition; + } + } + + let routine = r[ original.name ]; + + _.routineExtend( routine, original ); + _.assert( arguments.length === 2 ); + + routine.originalFunctor = original; + + _.assert( _.routineIs( _.define[ kind ] ) ); + + return routine; +} + +// -- +// relations +// -- + +let DefaultAccessorsMap = Object.create( null ); +DefaultAccessorsMap.Accessors = _.accessor.declare; +DefaultAccessorsMap.Forbids = _.accessor.forbid; +DefaultAccessorsMap.AccessorsForbid = _.accessor.forbid; +DefaultAccessorsMap.AccessorsReadOnly = _.accessor.readOnly; + +_.assert( _.routineIs( _.accessor.declare ) ); +_.assert( _.routineIs( _.accessor.forbid ) ); +_.assert( _.routineIs( _.accessor.readOnly ) ); + +let Forbids = +{ + _ArrayDescriptor : '_ArrayDescriptor', + ArrayDescriptor : 'ArrayDescriptor', + _ArrayDescriptors : '_ArrayDescriptors', + ArrayDescriptors : 'ArrayDescriptors', + arrays : 'arrays', + arrayOf : 'arrayOf', +} + +// + +let AccessorExtension = +{ + + // declare + + _register, + + supplement, + + // etc + + has, + + // meta + + suiteMakerFrom_functor, + _DefinesGenerate, + _DefineGenerate, + + // fields + + DefaultAccessorsMap, + +} + +// + +let ToolsExtension = +{ +} + +// -- +// extend +// -- + +_.accessor = _.accessor || Object.create( null ); +_.props.supplement( _, ToolsExtension ); +/* _.props.extend */Object.assign( _.accessor, AccessorExtension ); + +_.accessor.forbid( _, Forbids ); +_.accessor.forbid( _.accessor, Forbids ); + +_.accessor.getter = _.accessor.getter || Object.create( null ); +_.accessor.graber = _.accessor.graber || Object.create( null ); +_.accessor.setter = _.accessor.setter || Object.create( null ); +_.accessor.putter = _.accessor.putter || Object.create( null ); +_.accessor.suite = _.accessor.suite || Object.create( null ); +_.accessor.define = _.accessor.define || Object.create( null ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/l3/Accessor.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Accessor_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Accessor_s */ })(); + +/* */ /* begin of file Class_s */ ( function Class_s() { function Class_s_naked() { ( function _Class_s_() { + +'use strict'; + +const Self = _global_.wTools; +const _global = _global_; +const _ = _global_.wTools; + +const _ObjectHasOwnProperty = Object.hasOwnProperty; +const _ObjectPropertyIsEumerable = Object.propertyIsEnumerable; +// let _nameFielded = _.nameFielded; + +_.assert( _.object.isBasic( _.props ), 'wProto needs Tools/wtools/abase/l1/FieldMapper.s' ); +// _.assert( _.routineIs( _nameFielded ), 'wProto needs Tools/wtools/l3/NameTools.s' ); + +// -- +// mixin +// -- + +/** + * Make mixin which could be mixed into prototype of another object. + * @param {object} o - options. + * @function _mixinDelcare + * @namespace Tools + * @module Tools/base/Proto + */ + +function _mixinDelcare( o ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.mapIs( o ) || _.routineIs( o ) ); + _.assert( _.routineIs( o.onMixinApply ) || o.onMixinApply === undefined || o.onMixinApply === null, 'Expects routine {-o.onMixinApply-}, but got', _.entity.strType( o ) ); + _.assert( _.strDefined( o.name ), 'mixin should have name' ); + _.assert( _.object.isBasic( o.extend ) || o.extend === undefined || o.extend === null ); + _.assert( _.object.isBasic( o.supplementOwn ) || o.supplementOwn === undefined || o.supplementOwn === null ); + _.assert( _.object.isBasic( o.supplement ) || o.supplement === undefined || o.supplement === null ); + _.assertOwnNoConstructor( o ); + _.routine.options_( _mixinDelcare, o ); + + o.mixin = function mixin( dstClass ) + { + let md = this.__mixin__; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.routineIs( dstClass ), 'Expects constructor' ); + _.assert( dstClass === dstClass.prototype.constructor ); + _.map.assertHasOnly( this, [ _.KnownConstructorFields, { mixin : 'mixin', __mixin__ : '__mixin__' }, this.prototype.Statics || {} ] ); + + if( md.onMixinApply ) + md.onMixinApply( md, dstClass ); + else + _.mixinApply( md, dstClass.prototype ); + if( md.onMixinEnd ) + md.onMixinEnd( md, dstClass ); + + return dstClass; + } + + /* */ + + if( !o.prototype ) + { + let got = _.workpiece.prototypeAndConstructorOf( o ); + + if( got.prototype ) + o.prototype = got.prototype; + else + o.prototype = Object.create( null ); + + _.classExtend + ({ + cls : got.cls || null, + prototype : o.prototype, + extend : o.extend || null, + supplementOwn : o.supplementOwn || null, + supplement : o.supplement || null, + }); + + } + + _.assert( !o.prototype.mixin, 'not tested' ); + o.prototype.mixin = o.mixin; + if( o.prototype.constructor ) + { + _.assert( !o.prototype.constructor.mixin || o.prototype.constructor.mixin === o.mixin, 'not tested' ); + o.prototype.constructor.mixin = o.mixin; + } + + Object.freeze( o ); + return o; +} + +_mixinDelcare.defaults = +{ + + name : null, + shortName : null, + prototype : null, + + extend : null, + supplementOwn : null, + supplement : null, + functors : null, + + onMixinApply : null, + onMixinEnd : null, + +} + +// + +function mixinDelcare( o ) +{ + let result = Object.create( null ); + + _.assert( o.mixin === undefined ); + + let md = result.__mixin__ = _._mixinDelcare.apply( this, arguments ); + result.name = md.name; + result.shortName = md.shortName; + result.prototype = md.prototype; + result.mixin = md.mixin; + + Object.freeze( result ); + return result; +} + +mixinDelcare.defaults = Object.create( _mixinDelcare.defaults ); + +// + +/** + * Mixin methods and fields into prototype of another object. + * @param {object} o - options. + * @function mixinApply + * @namespace Tools + * @module Tools/base/Proto + */ + +function mixinApply( mixinDescriptor, dstPrototype ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( !_.primitiveIs( dstPrototype ), () => 'Second argument {-dstPrototype-} does not look like prototype, got ' + _.entity.strType( dstPrototype ) ); + _.assert( _.routineIs( mixinDescriptor.mixin ), 'First argument does not look like mixin descriptor' ); + _.assert( _.object.isBasic( mixinDescriptor ) ); + _.assert( Object.isFrozen( mixinDescriptor ), 'First argument does not look like mixin descriptor' ); + _.map.assertHasOnly( mixinDescriptor, _.MixinDescriptorFields ); + + /* mixin into routine */ + + if( !_.mapIs( dstPrototype ) ) + { + _.assert( dstPrototype.constructor.prototype === dstPrototype, 'mixin :', 'Expects prototype with own constructor field' ); + _.assert( dstPrototype.constructor.name.length > 0 || dstPrototype.constructor._name.length > 0, 'mixin :', 'constructor should has name' ); + _.assert( _.routineIs( dstPrototype.init ) ); + } + + /* extend */ + + _.assert( _.mapOnlyOwnKey( dstPrototype, 'constructor' ) ); + _.assert( dstPrototype.constructor.prototype === dstPrototype ); + _.classExtend + ({ + cls : dstPrototype.constructor, + extend : mixinDescriptor.extend, + supplementOwn : mixinDescriptor.supplementOwn, + supplement : mixinDescriptor.supplement, + functors : mixinDescriptor.functors, + }); + + /* mixins map */ + + if( !_ObjectHasOwnProperty.call( dstPrototype, '_mixinsMap' ) ) + { + dstPrototype._mixinsMap = Object.create( dstPrototype._mixinsMap || null ); + _.props.conceal( dstPrototype, '_mixinsMap' ); + } + + _.assert + ( + !dstPrototype._mixinsMap[ mixinDescriptor.name ], + 'Attempt to mixin same mixin ' + _.strQuote( mixinDescriptor.name ) + + ' several times into ' + _.strQuote( dstPrototype.constructor.name ) + ); + + dstPrototype._mixinsMap[ mixinDescriptor.name ] = 1; +} + +// + +function mixinHas( proto, mixin ) +{ + if( _.constructorIs( proto ) ) + proto = _.workpiece.prototypeOf( proto ); + + _.assert( _.workpiece.prototypeIsStandard( proto ) ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + let result; + + if( _.strIs( mixin ) ) + { + result = proto._mixinsMap && proto._mixinsMap[ mixin ]; + } + else + { + _.assert( _.routineIs( mixin.mixin ), 'Expects mixin, but got not mixin', _.entity.strType( mixin ) ); + _.assert( _.strDefined( mixin.name ), 'Expects mixin, but got not mixin', _.entity.strType( mixin ) ); + result = proto._mixinsMap && proto._mixinsMap[ mixin.name ]; + } + + return !!result; +} + +// -- +// class +// -- + +/** +* @typedef {object} wTools~prototypeOptions +* @property {routine} [o.cls=null] - constructor for which prototype is needed. +* @property {routine} [o.parent=null] - constructor of parent class. +* @property {object} [o.extend=null] - extend prototype by this map. +* @property {object} [o.supplement=null] - supplement prototype by this map. +* @property {object} [o.static=null] - static fields of a class. +* @property {boolean} [o.usingPrimitiveExtension=false] - extends class with primitive fields from relationship descriptors. +* @property {boolean} [o.usingOriginalPrototype=false] - makes prototype using original constructor prototype. +*/ + +/** + * Make prototype for constructor repairing relationship : Composes, Aggregates, Associates, Medials, Restricts. + * Execute optional extend / supplement if such o present. + * @param {wTools~prototypeOptions} o - options {@link wTools~prototypeOptions}. + * @returns {object} Returns constructor's prototype based on( o.parent ) prototype and complemented by fields, static and non-static methods. + * + * @example + * const Parent = function Alpha(){ }; + * Parent.prototype.init = function( ) + * { + * let self = this; + * self.c = 5; + * }; + * + * const Self = Betta; + * function Betta( o ) + * { + * return _.workpiece.construct( Self, this, arguments ); + * } + * + * function init() + * { + * let self = this; + * Parent.prototype.init.call( this ); + * _.mapExtendConditional( _.props.mapper.srcOwn(), self, Composes ); + * } + * + * let Composes = + * { + * a : 1, + * b : 2, + * } + * + * let Proto = + * { + * init, + * Composes + * } + * + * _.classDeclare + * ({ + * cls : Self, + * parent : Parent, + * extend : Proto, + * }); + * + * let betta = new Betta(); + * console.log( proto === Self.prototype ); //returns true + * console.log( Parent.prototype.isPrototypeFor( betta ) ); //returns true + * console.log( betta.a, betta.b, betta.c ); //returns 1 2 5 + * + * @function classDeclare + * @throws {exception} If no argument provided. + * @throws {exception} If( o ) is not a Object. + * @throws {exception} If( o.cls ) is not a Routine. + * @throws {exception} If( o.cls.name ) is not defined. + * @throws {exception} If( o.cls.prototype ) has not own constructor. + * @throws {exception} If( o.cls.prototype ) has restricted properties. + * @throws {exception} If( o.parent ) is not a Routine. + * @throws {exception} If( o.extend ) is not a Object. + * @throws {exception} If( o.supplement ) is not a Object. + * @throws {exception} If( o.parent ) is equal to( o.extend ). + * @throws {exception} If function cant rewrite constructor using original prototype. + * @throws {exception} If( o.usingOriginalPrototype ) is false and ( o.cls.prototype ) has manually defined properties. + * @throws {exception} If( o.cls.prototype.constructor ) is not equal( o.cls ). + * @namespace Tools + * @module Tools/base/Proto + */ + +/* +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); +*/ + +function classDeclare( o ) +{ + let result; + + if( o.withClass === undefined ) + o.withClass = true; + + if( o.cls && !o.name ) + o.name = o.cls.name; + + if( o.cls && !o.shortName ) + o.shortName = o.cls.shortName; + + /* */ + + let has = {} + has.constructor = 'constructor'; + + let hasNot = + { + Parent : 'Parent', + Self : 'Self', + } + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.object.isBasic( o ) ); + _.assertOwnNoConstructor( o, 'options for classDeclare should have no constructor' ); + _.assert( !( 'parent' in o ) || o.parent !== undefined, 'parent is "undefined", something is wrong' ); + + if( o.withClass ) + { + + _.assert( _.routineIs( o.cls ), 'Expects {-o.cls-}' ); + _.assert( _.routineIs( o.cls ), 'classDeclare expects constructor' ); + _.assert( _.strIs( o.cls.name ) || _.strIs( o.cls._name ), 'constructor should have name' ); + _.assert( _ObjectHasOwnProperty.call( o.cls.prototype, 'constructor' ) ); + _.assert( !o.name || o.cls.name === o.name || o.cls._name === o.name, 'class has name', o.cls.name + ', but options', o.name ); + _.assert( !o.shortName || !o.cls.shortName|| o.cls.shortName === o.shortName, 'class has short name', o.cls.shortName + ', but options', o.shortName ); + + _.map.assertOwnAll( o.cls.prototype, has, 'classDeclare expects constructor' ); + _.map.assertOwnNone( o.cls.prototype, hasNot ); + _.map.assertOwnNone( o.cls.prototype, _.DefaultForbiddenNames ); + + if( o.extend && _ObjectHasOwnProperty.call( o.extend, 'constructor' ) ) + _.assert( o.extend.constructor === o.cls ); + + } + else + { + _.assert( !o.cls ); + } + + _.assert( _.routineIs( o.parent ) || o.parent === undefined || o.parent === null, () => 'Wrong type of parent : ' + _.entity.strType( 'o.parent' ) ); + _.assert( _.object.isBasic( o.extend ) || o.extend === undefined ); + _.assert( _.object.isBasic( o.supplement ) || o.supplement === undefined ); + _.assert( o.parent !== o.extend || o.extend === undefined ); + + if( o.extend ) + { + _.assert( o.extend.cls === undefined ); + _.assertOwnNoConstructor( o.extend ); + } + if( o.supplementOwn ) + { + _.assert( o.supplementOwn.cls === undefined ); + _.assertOwnNoConstructor( o.supplementOwn ); + } + if( o.supplement ) + { + _.assert( o.supplement.cls === undefined ); + _.assertOwnNoConstructor( o.supplement ); + } + + _.routine.options_( classDeclare, o ); + + /* */ + + let prototype; + if( !o.parent ) + o.parent = null; + + /* make prototype */ + + if( o.withClass ) + { + + if( o.usingOriginalPrototype ) + { + + prototype = o.cls.prototype; + _.assert( o.parent === null || o.parent === Object.getPrototypeOf( o.cls.prototype ) ); + + } + else + { + if( o.cls.prototype ) + { + _.assert( Object.keys( o.cls.prototype ).length === 0, 'misuse of classDeclare, prototype of constructor has properties which where put there manually', Object.keys( o.cls.prototype ) ); + _.assert( o.cls.prototype.constructor === o.cls ); + } + if( o.parent ) + { + prototype = o.cls.prototype = Object.create( o.parent.prototype ); + } + else + { + prototype = o.cls.prototype = Object.create( null ); + } + } + + /* constructor */ + + prototype.constructor = o.cls; + + if( o.parent ) + { + Object.setPrototypeOf( o.cls, o.parent ); + } + + /* extend */ + + _.classExtend + ({ + cls : o.cls, + extend : o.extend, + supplementOwn : o.supplementOwn, + supplement : o.supplement, + usingPrimitiveExtension : o.usingPrimitiveExtension, + usingStatics : 1, + allowingExtendStatics : o.allowingExtendStatics, + }); + + /* statics */ + + _.assert( _.routineIs( prototype.constructor ) ); + _.assert( _.object.isBasic( prototype.Statics ) ); + _.map.assertHasAll( prototype.constructor, prototype.Statics ); + _.assert( prototype === o.cls.prototype ); + _.assert( _ObjectHasOwnProperty.call( prototype, 'constructor' ), 'prototype should own constructor' ); + _.assert( _.routineIs( prototype.constructor ), 'prototype should has own constructor' ); + + /* mixin tracking */ + + if( !_ObjectHasOwnProperty.call( prototype, '_mixinsMap' ) ) + { + prototype._mixinsMap = Object.create( prototype._mixinsMap || null ); + } + + _.assert( !prototype._mixinsMap[ o.cls.name ] ); + + prototype._mixinsMap[ o.cls.name ] = 1; + + result = o.cls; + + /* handler */ + + if( prototype.OnClassMakeEnd_meta ) + prototype.OnClassMakeEnd_meta.call( prototype, o ); + + if( o.onClassMakeEnd ) + o.onClassMakeEnd.call( prototype, o ); + + } + + /* */ + + if( o.withMixin ) + { + + let mixinOptions = _.props.extend( null, o ); + + _.assert( !o.usingPrimitiveExtension ); + _.assert( !o.usingOriginalPrototype ); + _.assert( !o.parent ); + _.assert( !o.cls || !!o.withClass ); + + delete mixinOptions.parent; + delete mixinOptions.cls; + delete mixinOptions.withMixin; + delete mixinOptions.withClass; + delete mixinOptions.usingPrimitiveExtension; + delete mixinOptions.usingOriginalPrototype; + delete mixinOptions.allowingExtendStatics; + delete mixinOptions.onClassMakeEnd; + + if( mixinOptions.extend ) + mixinOptions.extend = _.props.extend( null, mixinOptions.extend ); + if( mixinOptions.supplement ) + mixinOptions.supplement = _.props.extend( null, mixinOptions.supplement ); + if( mixinOptions.supplementOwn ) + mixinOptions.supplementOwn = _.props.extend( null, mixinOptions.supplementOwn ); + + mixinOptions.prototype = prototype; /* zzz : remove? */ + + _._mixinDelcare( mixinOptions ); + o.cls.__mixin__ = mixinOptions; + o.cls.mixin = mixinOptions.mixin; + + _.assert( mixinOptions.extend === null || mixinOptions.extend.constructor === undefined ); + _.assert( mixinOptions.supplement === null || mixinOptions.supplement.constructor === undefined ); + _.assert( mixinOptions.supplementOwn === null || mixinOptions.supplementOwn.constructor === undefined ); + + } + + /* */ + + if( Config.debug ) + if( prototype ) + { + let descriptor = Object.getOwnPropertyDescriptor( prototype, 'constructor' ); + _.assert( descriptor.writable || descriptor.set ); + _.assert( descriptor.configurable ); + } + + return result; +} + +classDeclare.defaults = +{ + cls : null, + parent : null, + + onClassMakeEnd : null, + onMixinApply : null, + onMixinEnd : null, + + extend : null, + supplementOwn : null, + supplement : null, + functors : null, + + name : null, + shortName : null, + + usingPrimitiveExtension : false, + usingOriginalPrototype : false, + allowingExtendStatics : false, + + withMixin : false, + withClass : true, + +} + +// + +/** + * Extends and supplements( o.cls ) prototype by fields and methods repairing relationship : Composes, Aggregates, Associates, Medials, Restricts. + * + * @param {wTools~prototypeOptions} o - options {@link wTools~prototypeOptions}. + * @returns {object} Returns constructor's prototype complemented by fields, static and non-static methods. + * + * @example + * const Self = Betta; +function Betta( o ) { }; + * let Statics = { staticFunction : function staticFunction(){ } }; + * let Composes = { a : 1, b : 2 }; + * let Proto = { Composes, Statics }; + * + * let proto = _.classExtend + * ({ + * cls : Self, + * extend : Proto, + * }); + * console.log( Self.prototype === proto ); //returns true + * + * @function classExtend + * @throws {exception} If no argument provided. + * @throws {exception} If( o ) is not a Object. + * @throws {exception} If( o.cls ) is not a Routine. + * @throws {exception} If( prototype.cls ) is not a Routine. + * @throws {exception} If( o.cls.name ) is not defined. + * @throws {exception} If( o.cls.prototype ) has not own constructor. + * @throws {exception} If( o.parent ) is not a Routine. + * @throws {exception} If( o.extend ) is not a Object. + * @throws {exception} If( o.supplement ) is not a Object. + * @throws {exception} If( o.static) is not a Object. + * @throws {exception} If( o.cls.prototype.Constitutes ) is defined. + * @throws {exception} If( o.cls.prototype ) is not equal( prototype ). + * @namespace Tools + * @module Tools/base/Proto + */ + +function classExtend( o ) +{ + + if( arguments.length === 2 ) + o = { cls : arguments[ 0 ], extend : arguments[ 1 ] }; + + if( !o.prototype ) + o.prototype = o.cls.prototype; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.object.isBasic( o ) ); + _.assert( !_ObjectHasOwnProperty.call( o, 'constructor' ) ); + _.assertOwnNoConstructor( o ); + _.assert( _.object.isBasic( o.extend ) || o.extend === undefined || o.extend === null ); + _.assert( _.object.isBasic( o.supplementOwn ) || o.supplementOwn === undefined || o.supplementOwn === null ); + _.assert( _.object.isBasic( o.supplement ) || o.supplement === undefined || o.supplement === null ); + _.assert( _.routineIs( o.cls ) || _.object.isBasic( o.prototype ), 'Expects class constructor or class prototype' ); + + /* + mixin could have none class constructor + */ + + if( o.cls ) + { + + _.assert( _.routineIs( o.cls ), 'Expects constructor of class ( o.cls )' ); + _.assert( _.strIs( o.cls.name ) || _.strIs( o.cls._name ), 'Class constructor should have name' ); + _.assert( !!o.prototype ); + + } + + if( o.extend ) + { + _.assert( o.extend.cls === undefined ); + _.assertOwnNoConstructor( o.extend ); + } + if( o.supplementOwn ) + { + _.assert( o.supplementOwn.cls === undefined ); + _.assertOwnNoConstructor( o.supplementOwn ); + } + if( o.supplement ) + { + _.assert( o.supplement.cls === undefined ); + _.assertOwnNoConstructor( o.supplement ); + } + + _.routine.options_( classExtend, o ); + + // _.assert( _.object.isBasic( o.prototype ) ); + _.assert( !_.primitiveIs( o.prototype ) && !_.routineIs( o.prototype ) ); + + /* fields groups */ + + _.workpiece.fieldsGroupsDeclareForEachFilter + ({ + dstPrototype : o.prototype, + extendMap : o.extend, + supplementOwnMap : o.supplementOwn, + supplementMap : o.supplement, + }); + + /* get constructor */ + + if( !o.cls ) + o.cls = _.workpiece.prototypeAndConstructorOf( o ).cls; + + /* */ + + let staticsOwn = _.props.onlyOwn( o.prototype.Statics ); + let staticsAll = staticsAllGet(); + let fieldsGroups = _.workpiece.fieldsGroupsGet( o.prototype ); + +/* + +to prioritize ordinary facets adjustment order should be + +- static extend +- ordinary extend +- ordinary supplement +- static supplement + +*/ + + /* static extend */ + + if( o.extend && o.extend.Statics ) + declareStaticsForMixin( o.extend.Statics, _.props.extend.bind( _.props ) ); + + /* ordinary extend */ + + if( o.extend ) + fieldsDeclare( _.props.extend.bind( _.props ), o.extend ); + + /* ordinary supplementOwn */ + + if( o.supplementOwn ) + fieldsDeclare( _.mapExtendDstNotOwn, o.supplementOwn ); + + /* ordinary supplement */ + + if( o.supplement ) + fieldsDeclare( _.props.supplement.bind( _.props ), o.supplement ); + + /* static supplementOwn */ + + if( o.supplementOwn && o.supplementOwn.Statics ) + declareStaticsForMixin( o.supplementOwn.Statics, _.mapExtendDstNotOwn ); + + /* static supplement */ + + if( o.supplement && o.supplement.Statics ) + declareStaticsForMixin( o.supplement.Statics, _.props.supplement.bind( _.props ) ); + + /* primitive extend */ + + if( o.usingPrimitiveExtension ) + { + debugger; + for( let f in _.DefaultFieldsGroupsRelations ) + if( f !== 'Statics' ) + if( _.mapOnlyOwnKey( o.prototype, f ) ) + _.mapExtendConditional( _.props.mapper.srcOwnPrimitive(), o.prototype, o.prototype[ f ] ); + } + + /* accessors */ + + if( o.supplement ) + declareAccessors( o.supplement ); + if( o.supplementOwn ) + declareAccessors( o.supplementOwn ); + if( o.extend ) + declareAccessors( o.extend ); + + /* statics */ + + let fieldsOfRelationsGroups = _.workpiece.fieldsOfRelationsGroupsFromPrototype( o.prototype ); + + if( o.supplement && o.supplement.Statics ) + declareStaticsForClass( o.supplement.Statics, 1, 0 ); + if( o.supplementOwn && o.supplementOwn.Statics ) + declareStaticsForClass( o.supplementOwn.Statics, 1, 1 ); + if( o.extend && o.extend.Statics ) + declareStaticsForClass( o.extend.Statics, 0, 0 ); + + /* functors */ + + if( o.functors ) + for( let m in o.functors ) + { + let func = o.functors[ m ].call( o, o.prototype[ m ] ); + _.assert( _.routineIs( func ), 'not tested' ); + o.prototype[ m ] = func; + } + + /* validation */ + + /* + mixin could could have none class constructor + */ + + if( o.cls ) + { + _.assert( o.prototype === o.cls.prototype ); + _.assert( _ObjectHasOwnProperty.call( o.prototype, 'constructor' ), 'prototype should has own constructor' ); + _.assert( _.routineIs( o.prototype.constructor ), 'prototype should has own constructor' ); + _.assert( o.cls === o.prototype.constructor ); + } + + _.assert( _.object.isBasic( o.prototype.Statics ) ); + + return o.prototype; + + /* */ + + function fieldsDeclare( extend, src ) + { + let map = _.mapBut_( null, src, fieldsGroups ); + for( let s in staticsAll ) + if( map[ s ] === staticsAll[ s ] ) + delete map[ s ]; + extend( o.prototype, map ); + + // if( _global_.debugger ) + // debugger; + // let symbols = Object.getOwnPropertySymbols( src ); debugger; + // for( let s in staticsAll ) + // if( symbols[ s ] === staticsAll[ s ] ) + // delete symbols[ s ]; + // extend( o.prototype, symbols ); + + if( Config.debug ) + if( !o.allowingExtendStatics ) + if( Object.getPrototypeOf( o.prototype.Statics ) ) + { + map = _.mapBut_( null, map, staticsOwn ); + + let keys = _.props.keys( _.mapOnly_( null, map, Object.getPrototypeOf( o.prototype.Statics ) ) ); + if( keys.length ) + { + _.assert( 0, 'attempt to extend static field', keys ); + } + } + } + + /* */ + + function declareStaticsForMixin( statics, extend ) + { + + if( !o.usingStatics ) + return; + + extend( staticsAll, statics ); + + /* is pure mixin */ + if( o.prototype.constructor ) + return; + + if( o.usingStatics && statics ) + { + extend( o.prototype, statics ); + if( o.cls ) + extend( o.cls, statics ); + } + + } + + /* */ + + function staticsAllGet() + { + let staticsAll = _.props.extend( null, o.prototype.Statics ); + if( o.supplement && o.supplement.Statics ) + _.props.supplement( staticsAll, o.supplement.Statics ); + if( o.supplementOwn && o.supplementOwn.Statics ) + _.mapExtendDstNotOwn( staticsAll, o.supplementOwn.Statics ); + if( o.extend && o.extend.Statics ) + _.props.extend( staticsAll, o.extend.Statics ); + return staticsAll; + } + + /* */ + + function declareStaticsForClass( statics, dstNotHasOnly, dstNotOwnOnly ) + { + + /* is class */ + if( !o.prototype.constructor ) + return; + if( !o.usingStatics ) + return; + + for( let s in statics ) + { + + if( !_ObjectHasOwnProperty.call( o.prototype.Statics, s ) ) + continue; + + _.staticDeclare + ({ + name : s, + value : o.prototype.Statics[ s ], + prototype : o.prototype, + // extending : !dstNotHasOnly, + dstNotHasOnly : dstNotHasOnly, + dstNotOwnOnly : dstNotOwnOnly, + fieldsOfRelationsGroups, + }); + + } + + } + + /* */ + + function declareAccessors( src ) + { + for( let d in _.accessor.DefaultAccessorsMap ) + if( src[ d ] ) + { + _.accessor.DefaultAccessorsMap[ d ]( o.prototype, src[ d ] ); + } + } + +} + +classExtend.defaults = +{ + cls : null, + prototype : null, + + extend : null, + supplementOwn : null, + supplement : null, + functors : null, + + usingStatics : true, + usingPrimitiveExtension : false, + allowingExtendStatics : false, +} + +// + +function staticDeclare( o ) +{ + + if( !( 'value' in o ) ) + o.value = o.prototype.Statics[ o.name ]; + + if( _.definitionIs( o.value ) ) + { + _.props.extend( o, o.value.toVal( o.value.val ) ); + } + + _.routine.options_( staticDeclare, arguments ); + _.assert( _.strIs( o.name ) ); + _.assert( arguments.length === 1 ); + + if( !o.fieldsOfRelationsGroups ) + o.fieldsOfRelationsGroups = _.workpiece.fieldsOfRelationsGroupsFromPrototype( o.prototype ); + + let pd = _.props.descriptorOf( o.prototype, o.name ); + let cd = _.props.descriptorOf( o.prototype.constructor, o.name ); + + if( pd.object !== o.prototype ) + pd.descriptor = null; + + if( cd.object !== o.prototype.constructor ) + cd.descriptor = null; + + if( o.name === 'constructor' ) + return; + + let symbol = Symbol.for( o.name ); + let aname = _.accessor._propertyGetterSetterNames( o.name ); + let methods = Object.create( null ); + + // if( o.name === 'UsingUniqueNames' ) + // debugger; + + /* */ + + let prototype = o.prototype; + if( o.writable ) + methods[ aname.set ] = function set( src ) + { + /* + should assign fields to the original class / prototype + not descendant + */ + prototype[ symbol ] = src; + prototype.constructor[ symbol] = src; + } + methods[ aname.get ] = function get() + { + return this[ symbol ]; + } + + /* */ + + if( o.fieldsOfRelationsGroups[ o.name ] === undefined ) + if( !pd.descriptor || ( !o.dstNotHasOnly && pd.descriptor.value === undefined ) ) + { + + if( cd.descriptor ) + { + o.prototype[ o.name ] = o.value; + } + else + { + o.prototype[ symbol ] = o.value; + + _.accessor.declare + ({ + object : o.prototype, + methods, + names : o.name, + combining : 'rewrite', + configurable : true, + enumerable : false, + strict : false, + writable : o.writable, + }); + + } + } + + /* */ + + if( !cd.descriptor || ( !o.dstNotHasOnly && cd.descriptor.value === undefined ) ) + { + if( pd.descriptor ) + { + o.prototype.constructor[ o.name ] = o.value; + } + else + { + o.prototype.constructor[ symbol ] = o.value; + + _.accessor.declare + ({ + object : o.prototype.constructor, + methods, + names : o.name, + combining : 'rewrite', + enumerable : true, + configurable : true, + prime : false, + strict : false, + writable : o.writable, + }); + + } + + } + + /* */ + + return true; +} + +var defaults = staticDeclare.defaults = Object.create( null ); + +defaults.name = null; +defaults.value = null; +defaults.prototype = null; +defaults.fieldsOfRelationsGroups = null; +defaults.dstNotHasOnly = 1; /**/ +defaults.dstNotOwnOnly = 0; /* !!! not used yet */ +defaults.writable = 1; + +// -- +// fields +// -- + +/** + * @typedef {Object} KnownConstructorFields - contains fields allowed for class constructor. + * @property {String} name - full name + * @property {String} _name - private name + * @property {String} shortName - short name + * @property {Object} prototype - prototype object + * @namespace Tools + * @module Tools/base/Proto + */ + +let KnownConstructorFields = +{ + name : null, + _name : null, + shortName : null, + prototype : null, +} + +/** + * @typedef {Object} MixinDescriptorFields - fields of mixin descriptor. + * @property {String} name - full name + * @namespace Tools + * @module Tools/base/Proto + */ + +let MixinDescriptorFields = +{ + + name : null, + shortName : null, + prototype : null, + + extend : null, + supplementOwn : null, + supplement : null, + functors : null, + + onMixinApply : null, + onMixinEnd : null, + mixin : null, + +} + +// -- +// definiton +// -- + +let Extension = +{ + + // mixin + + _mixinDelcare, + mixinDelcare, + mixinApply, + mixinHas, + + // class + + classDeclare, + classExtend, + staticDeclare, + + // + + KnownConstructorFields, + MixinDescriptorFields, + +} + +// + +_.props.extend( _, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/l5/Class.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Class_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Class_s */ })(); + +/* */ /* begin of file Collection_s */ ( function Collection_s() { function Collection_s_naked() { ( function _Collection_s_() { + +'use strict'; + +const Self = _global_.wTools; +const _global = _global_; +const _ = _global_.wTools; + +// -- +// getter / setter functors +// -- + +function setterMapCollection_functor( o ) +{ + + _.map.assertHasOnly( o, setterMapCollection_functor.defaults ); + _.assert( _.strIs( o.name ) ); + _.assert( _.routineIs( o.elementMaker ) ); + let symbol = Symbol.for( o.name ); + let elementMakerOriginal = o.elementMaker; + let elementMaker = o.elementMaker; + let friendField = o.friendField; + + if( friendField ) + elementMaker = function elementMaker( src ) + { + src[ friendField ] = this; + return elementMakerOriginal.call( this, src ); + } + + return function _setterMapCollection( src ) + { + let self = this; + + _.assert( _.object.isBasic( src ) ); + + if( self[ symbol ] ) + { + + if( src !== self[ symbol ] ) + for( let d in self[ symbol ] ) + delete self[ symbol ][ d ]; + + } + else + { + + self[ symbol ] = Object.create( null ); + + } + + for( let d in src ) + { + if( src[ d ] !== null ) + self[ symbol ][ d ] = elementMaker.call( self, src[ d ] ); + } + + return self[ symbol ]; + } + +} + +setterMapCollection_functor.defaults = +{ + name : null, + elementMaker : null, + friendField : null, +} + +// + +function setterArrayCollection_functor( o ) +{ + + if( _.strIs( arguments[ 0 ] ) ) + o = { name : arguments[ 0 ] } + + _.routine.options_( setterArrayCollection_functor, o ); + _.assert( _.strIs( o.name ) ); + _.assert( arguments.length === 1 ); + _.assert( _.routineIs( o.elementMaker ) || o.elementMaker === null ); + + let symbol = Symbol.for( o.name ); + let elementMaker = o.elementMaker; + let friendField = o.friendField; + + if( !elementMaker ) + elementMaker = function( src ){ return src } + + let elementMakerOriginal = elementMaker; + + if( friendField ) + elementMaker = function elementMaker( src ) + { + src[ friendField ] = this; + return elementMakerOriginal.call( this, src ); + } + + return function _setterArrayCollection( src ) + { + let self = this; + + _.assert( src !== undefined ); + _.assert( arguments.length === 1 ); + + if( src !== null ) + src = _.array.as( src ); + + _.assert( _.arrayIs( src ) ); + + if( self[ symbol ] ) + { + + if( src !== self[ symbol ] ) + self[ symbol ].splice( 0, self[ symbol ].length ); + + } + else + { + + self[ symbol ] = []; + + } + + if( src === null ) + return self[ symbol ]; + + if( src !== self[ symbol ] ) + for( let d = 0 ; d < src.length ; d++ ) + { + if( src[ d ] !== null ) + self[ symbol ].push( elementMaker.call( self, src[ d ] ) ); + } + else for( let d = 0 ; d < src.length ; d++ ) + { + if( src[ d ] !== null ) + src[ d ] = elementMaker.call( self, src[ d ] ); + } + + return self[ symbol ]; + } + +} + +setterArrayCollection_functor.defaults = +{ + name : null, + elementMaker : null, + friendField : null, +} + +// + +/** + * Makes a setter that makes a shallow copy of (src) before assigning. + * @param {Object} o - options map + * @param {Object} o.name - name of property + * @returns {Function} Returns setter function. + * @function own + * @namespace Tools.accessor.setter + */ + +function setterOwn_functor( op ) +{ + let symbol = Symbol.for( op.name ); + + _.routine.options_( setterOwn_functor, arguments ); + + return function ownSet( src ) + { + let self = this; + + _.assert( arguments.length === 1 ); + + self[ symbol ] = _.entity.make( src ); + + return self[ symbol ]; + } + +} + +setterOwn_functor.defaults = +{ + name : null, +} + +// + +function setterFriend_functor( o ) +{ + + let name = _.nameUnfielded( o.name ).coded; + let friendName = o.friendName; + let maker = o.maker; + let symbol = Symbol.for( name ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( name ) ); + _.assert( _.strIs( friendName ) ); + _.assert( _.routineIs( maker ), 'Expects maker {-o.maker-}' ); + _.map.assertHasOnly( o, setterFriend_functor.defaults ); + + return function setterFriend( src ) + { + + let self = this; + _.assert( src === null || _.object.isBasic( src ), 'setterFriend : expects null or object, but got ' + _.entity.strType( src ) ); + + if( !src ) + { + + self[ symbol ] = src; + return; + + } + else if( !self[ symbol ] ) + { + + if( _.mapIs( src ) ) + { + let o2 = Object.create( null ); + o2[ friendName ] = self; + o2.name = name; + self[ symbol ] = maker( o2 ); + self[ symbol ].copy( src ); + } + else + { + self[ symbol ] = src; + } + + } + else + { + + if( self[ symbol ] !== src ) + self[ symbol ].copy( src ); + + } + + if( self[ symbol ][ friendName ] !== self ) + self[ symbol ][ friendName ] = self; + + return self[ symbol ]; + } + +} + +setterFriend_functor.defaults = +{ + name : null, + friendName : null, + maker : null, +} + +// + +function setterCopyable_functor( o ) +{ + + let name = _.nameUnfielded( o.name ).coded; + let maker = o.maker; + let symbol = Symbol.for( name ); + let debug = o.debug; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( name ) ); + _.assert( _.routineIs( maker ) ); + _.map.assertHasOnly( o, setterCopyable_functor.defaults ); + + return function setterCopyable( data ) + { + let self = this; + + if( debug ) + debugger; + + if( data === null ) + { + if( self[ symbol ] && self[ symbol ].finit ) + self[ symbol ].finit(); + self[ symbol ] = null; + return self[ symbol ]; + } + + if( !_.object.isBasic( self[ symbol ] ) ) + { + + self[ symbol ] = maker( data ); + + } + else if( _.object.isBasic( self[ symbol ] ) && !self[ symbol ].copy ) + { + self[ symbol ] = maker( data ); + } + else + { + + if( self[ symbol ] !== data ) + { + _.assert( _.routineIs( self[ symbol ].copy ) ); + self[ symbol ].copy( data ); + } + + } + + return self[ symbol ]; + } + +} + +setterCopyable_functor.defaults = +{ + name : null, + maker : null, + debug : 0, +} + +// + +/** + * Makes a setter that makes a buffer from (src) before assigning. + * @param {Object} o - options map + * @param {Object} o.name - name of property + * @param {Object} o.bufferConstructor - buffer constructor + * @returns {Function} Returns setter function. + * @function bufferCoerceFrom + * @namespace Tools.accessor.setter + */ + +function setterBufferFrom_functor( o ) +{ + + let name = _.nameUnfielded( o.name ).coded; + let bufferConstructor = o.bufferConstructor; + let symbol = Symbol.for( name ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( name ) ); + _.assert( _.routineIs( bufferConstructor ) ); + _.routine.options_( setterBufferFrom_functor, o ); + + return function setterBufferFrom( data ) + { + let self = this; + + if( data === null || data === false ) + { + data = null; + } + else + { + data = _.bufferCoerceFrom({ src : data, bufferConstructor }); + } + + self[ symbol ] = data; + return data; + } + +} + +setterBufferFrom_functor.defaults = +{ + name : null, + bufferConstructor : null, +} + +// + +function setterChangesTracking_functor( o ) +{ + + let name = Symbol.for( _.nameUnfielded( o.name ).coded ); + let nameOfChangeFlag = Symbol.for( _.nameUnfielded( o.nameOfChangeFlag ).coded ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options_( setterChangesTracking_functor, o ); + + throw _.err( 'not tested' ); + + return function setterChangesTracking( data ) + { + let self = this; + + if( data === self[ name ] ) + return; + + self[ name ] = data; + self[ nameOfChangeFlag ] = true; + + return data; + } + +} + +setterChangesTracking_functor.defaults = +{ + name : null, + nameOfChangeFlag : 'needsUpdate', + bufferConstructor : null, +} + +// + +/** + * @summary Allows to get read and write access to property of inner container. + * @param {Object} o + * @param {String} o.name + * @param {Number} o.index + * @param {String} o.storageName + * @function toElement + * @namespace Tools.accessor.suite + */ + +function toElementSet_functor( o ) +{ + _.assert( 0, 'not tested' ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.object.isBasic( o.names ) ); + _.assert( _.strIs( o.name ) ); + _.assert( _.strIs( o.storageName ) ); + _.assert( _.numberIs( o.index ) ); + _.routine.options_( toElementSet_functor, o ); + + debugger; + + let index = o.index; + let storageName = o.storageName; + let name = o.name; + let aname = _.accessor._propertyGetterSetterNames( name ); + + _.assert( _.numberIs( index ) ); + _.assert( index >= 0 ); + + return function accessorToElementSet( src ) + { + this[ storageName ][ index ] = src; + } + + return r; +} + +toElementSet_functor.defaults = +{ + name : null, + index : null, + storageName : null, +} + +// + +function symbolPut_functor( o ) +{ + o = _.routine.options_( symbolPut_functor, arguments ); + let symbol = Symbol.for( o.propName ); + return function put( val ) + { + this[ symbol ] = val; + return val; + } +} + +symbolPut_functor.defaults = +{ + propName : null, +} + +symbolPut_functor.identity = { 'accessor' : true, 'put' : true, 'functor' : true }; +// symbolPut_functor.identity = [ 'accessor', 'put', 'functor' ]; + +// + +function toElementGet_functor( o ) +{ + _.assert( 0, 'not tested' ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.object.isBasic( o.names ) ); + _.assert( _.strIs( o.name ) ); + _.assert( _.strIs( o.storageName ) ); + _.assert( _.numberIs( o.index ) ); + _.routine.options_( toElementGet_functor, o ); + + debugger; + + let index = o.index; + let storageName = o.storageName; + let name = o.name; + let aname = _.accessor._propertyGetterSetterNames( name ); + + _.assert( _.numberIs( index ) ); + _.assert( index >= 0 ); + + return function accessorToElementGet() + { + return this[ storageName ][ index ]; + } +} + +toElementGet_functor.defaults = +{ + name : null, + index : null, + storageName : null, +} + +// + +function withSymbolGet_functor( o ) /* xxx : deprecate in favor of toValueGet_functor */ +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options_( withSymbolGet_functor, o ); + _.assert( _.strDefined( o.propName ) ); + + let spaceName = o.propName; + let setter = Object.create( null ); + let getter = Object.create( null ); + let symbol = Symbol.for( spaceName ); + + return function toStructure() + { + let helper = this[ symbol ]; + if( !helper ) + { + helper = this[ symbol ] = proxyMake( this ); + } + return helper; + } + + /* */ + + function proxyMake( original ) + { + let handlers = + { + get( original, propName, proxy ) + { + let method = getter[ propName ]; + if( method ) + return end(); + + if( propName === spaceName ) + { + method = getter[ propName ] = function get( value ) + { + return undefined; + } + return end(); + } + + let symbol = _.symbolIs( propName ) ? propName : Symbol.for( propName ); + method = getter[ propName ] = function get( value ) + { + return this[ symbol ]; + } + return end(); + + function end() + { + return method.call( original ); + } + + }, + set( original, propName, value, proxy ) + { + let method = setter[ propName ]; + if( method ) + return end(); + + let symbol = _.symbolIs( propName ) ? propName : Symbol.for( propName ); + method = setter[ propName ] = function put( value ) + { + this[ symbol ] = value; + } + return end(); + + function end() + { + method.call( original, value ); + return true; + } + }, + }; + + let proxy = new Proxy( original, handlers ); + + return proxy; + } + +} + +withSymbolGet_functor.defaults = +{ + propName : null, +} + +withSymbolGet_functor.identity = { 'accessor' : true, 'get' : true, 'functor' : true }; +// withSymbolGet_functor.identity = [ 'accessor', 'getter', 'functor' ]; + +// + +function toStructureGet_functor( o ) /* xxx : deprecate in favor of toValueGet_functor */ +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options_( toStructureGet_functor, o ); + _.assert( _.strDefined( o.propName ) ); + + let spaceName = o.propName; + let setter = Object.create( null ); + let getter = Object.create( null ); + let symbol = Symbol.for( spaceName ); + + return function toStructure() + { + let helper = this[ symbol ]; + if( !helper ) + { + helper = this[ symbol ] = proxyMake( this ); + } + return helper; + } + + /* */ + + function proxyMake( original ) + { + let handlers = + { + get( original, propName, proxy ) + { + let method = getter[ propName ]; + if( method ) + return end(); + + if( propName === spaceName ) + { + method = getter[ propName ] = function get( value ) + { + return undefined; + } + return end(); + } + + let symbol = _.symbolIs( propName ) ? propName : Symbol.for( propName ); + if( original.hasField( propName ) || Object.hasOwnProperty.call( original, symbol ) ) + { + // debugger; + method = getter[ propName ] = function get( value ) + { + // debugger; + return this[ symbol ]; + } + return end(); + } + + method = getter[ propName ] = function get( value ) + { + return this[ propName ]; + } + return end(); + + function end() + { + return method.call( original ); + } + + }, + set( original, propName, value, proxy ) + { + let method = setter[ propName ]; + if( method ) + return end(); + + let putName1 = '_' + propName + 'Put'; + if( original[ putName1 ] ) + { + method = setter[ propName ] = function put( value ) + { + return this[ putName1 ]( value ); + } + return end(); + } + + let putName2 = propName + 'Put'; + if( original[ putName2 ] ) + { + method = setter[ propName ] = function put( value ) + { + return this[ putName2 ]( value ); + } + return end(); + } + + let symbol = _.symbolIs( propName ) ? propName : Symbol.for( propName ); + if( original.hasField( propName ) || Object.hasOwnProperty.call( original, symbol ) ) + { + method = setter[ propName ] = function put( value ) + { + this[ symbol ] = value; + } + return end(); + } + + method = setter[ propName ] = function put( value ) + { + this[ propName ] = value; + } + + return end(); + + function end() + { + method.call( original, value ); + return true; + } + }, + }; + + let proxy = new Proxy( original, handlers ); + + return proxy; + } + +} + +toStructureGet_functor.defaults = +{ + propName : null, +} + +toStructureGet_functor.identity = { 'accessor' : true, 'get' : true, 'functor' : true }; +// toStructureGet_functor.identity = [ 'accessor', 'getter', 'functor' ]; + +// + +function toValueGet_functor( o ) +{ + + _.routine.options_( toValueGet_functor, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strDefined( o.propName ) ); + _.assert( _.longHas( [ 'grab', 'get', 'suite' ], o.accessorKind ) ); + + let spaceName = o.propName; + let setter = Object.create( null ); + let getter = Object.create( null ); + let symbol = Symbol.for( spaceName ); + + if( o.accessor.configurable === null ) + o.accessor.configurable = 1; + let configurable = o.accessor.configurable; + if( configurable === null ) + configurable = _.accessor.DeclarationDefaults.configurable; + _.assert( _.boolLike( configurable ) ); + + if( o.accessorKind === 'suite' ) + { + let result = + { + get : toValueGet_functor, + set : false, + put : false, + } + return result; + } + + return function toStructure() + { + let helper; + + if( configurable ) + { + helper = proxyMake( this ); + let o2 = + { + enumerable : false, + configurable : false, + value : helper + } + Object.defineProperty( this, spaceName, o2 ); + } + else + { + helper = this[ symbol ]; + if( !helper ) + { + helper = this[ symbol ] = proxyMake( this ); + } + } + + return helper; + } + + /* */ + + function proxyMake( original ) + { + let handlers = + { + get( original, propName, proxy ) + { + let method = getter[ propName ]; + if( method ) + return end(); + + if( propName === spaceName ) + { + method = getter[ propName ] = function get( value ) + { + return undefined; + } + return end(); + } + + if( _.symbolIs( propName ) ) + { + let symbol = propName; + method = getter[ propName ] = function get( value ) + { + return this[ symbol ]; + } + return end(); + } + + let getName1 = '_' + propName + 'Get'; + let getName2 = '' + propName + 'Get'; + + if( _.routineIs( original[ getName1 ] ) ) + { + method = getter[ propName ] = function get() + { + return this[ getName1 ](); + } + return end(); + } + + if( _.routineIs( original[ getName2 ] ) ) + { + method = getter[ propName ] = function get() + { + return this[ getName2 ](); + } + return end(); + } + + let symbol = Symbol.for( propName ); + method = getter[ propName ] = function get() + { + return this[ symbol ]; + } + return end(); + + function end() + { + return method.call( original ); + } + + }, + set( original, propName, value, proxy ) + { + let method = setter[ propName ]; + if( method ) + return end(); + + let putName1 = '_' + propName + 'Put'; + if( original[ putName1 ] ) + { + method = setter[ propName ] = function put( value ) + { + return this[ putName1 ]( value ); + } + return end(); + } + + let putName2 = propName + 'Put'; + if( original[ putName2 ] ) + { + method = setter[ propName ] = function put( value ) + { + return this[ putName2 ]( value ); + } + return end(); + } + + let symbol = _.symbolIs( propName ) ? propName : Symbol.for( propName ); + method = setter[ propName ] = function put( value ) + { + this[ symbol ] = value; + } + + return end(); + + function end() + { + method.call( original, value ); + return true; + } + }, + }; + + let proxy = new Proxy( original, handlers ); + + return proxy; + } + +} + +toValueGet_functor.defaults = +{ + propName : null, + accessor : null, + accessorKind : null, +} + +toValueGet_functor.identity = { 'accessor' : true, suite : true, 'get' : true, 'functor' : true }; +// toValueGet_functor.identity = [ 'accessor', 'suite', 'getter', 'functor' ]; + +// + +let toElementSuite = _.accessor.suiteMakerFrom_functor( toElementGet_functor, toElementSet_functor ); + +// + +/** + * Makes a setter that is an alias for other property. + * @param {Object} o - options map + * @param {Object} o.original - name of source property + * @param {Object} o.alias - name of alias + * @returns {Function} Returns setter function. + * @function alias + * @namespace Tools.accessor.setter + */ + +function alias_head( routine, args ) +{ + + let o = args[ 0 ]; + if( _.strIs( args[ 0 ] ) ) + o = { originalName : args[ 0 ] } + + _.routine.options_( routine, o ); + + _.assert( args.length === 1, 'Expects single argument' ); + _.assert( _.strIs( o.originalName ) ); + + return o; +} + +// + +function aliasSetter_functor_body( o ) +{ + let container = o.container; + let originalName = o.originalName; + + _.routine.assertOptions( aliasSetter_functor_body, arguments ); + + if( _.strIs( container ) ) + return function aliasSet( src ) + { + let self = this; + self[ container ][ originalName ] = src; + return self[ container ][ originalName ]; + } + else if( _.objectLike( container ) || _.routineLike( container ) ) + return function aliasSet( src ) + { + let self = this; + return container[ originalName ] = src; + } + else if( container === null ) + return function aliasSet( src ) + { + let self = this; + self[ originalName ] = src; + return self[ originalName ]; + } + else _.assert( 0, `Unknown type of container ${_.entity.strType( container )}` ); + +} + +aliasSetter_functor_body.defaults = +{ + container : null, + originalName : null, + // aliasName : null, + // propName : null, +} + +let aliasSet_functor = _.routine.uniteCloning_replaceByUnite( alias_head, aliasSetter_functor_body ); + +// + +/** + * Makes a getter that is an alias for other property. + * @param {Object} o - options map + * @param {Object} o.original - name of source property + * @param {Object} o.alias - name of alias + * @returns {Function} Returns getter function. + * @function alias + * @namespace Tools.accessor.getter + */ + +function aliasGet_functor_body( o ) +{ + + let container = o.container; + let originalName = o.originalName; + // let aliasName = o.aliasName; + + _.routine.assertOptions( aliasGet_functor_body, arguments ); + + if( _.strIs( container ) ) + return function aliasGet( src ) + { + let self = this; + return self[ container ][ originalName ]; + } + else if( _.objectLike( container ) || _.routineLike( container ) ) + return function aliasGet( src ) + { + let self = this; + return container[ originalName ]; + } + else if( container === null ) + return function aliasGet( src ) + { + let self = this; + return self[ originalName ]; + } + else _.assert( 0, `Unknown type of container ${_.entity.strType( container )}` ); + +} + +aliasGet_functor_body.defaults = Object.create( aliasSet_functor.defaults ); + +let aliasGetter_functor = _.routine.uniteCloning_replaceByUnite( alias_head, aliasGet_functor_body ); + +// + +let aliasSuite = _.accessor.suiteMakerFrom_functor( aliasGetter_functor, aliasSet_functor ); + +// -- +// relations +// -- + +let Getter = +{ + + alias : aliasGetter_functor, + toElement : toElementGet_functor, + toStructure : toStructureGet_functor, + toValue : toValueGet_functor, + withSymbol : withSymbolGet_functor, + +} + +// + +let Setter = +{ + + mapCollection : setterMapCollection_functor, + arrayCollection : setterArrayCollection_functor, + + own : setterOwn_functor, + friend : setterFriend_functor, + copyable : setterCopyable_functor, + bufferCoerceFrom : setterBufferFrom_functor, + changesTracking : setterChangesTracking_functor, + + alias : aliasSet_functor, + toElement : toElementSet_functor, + +} + +// + +let Putter = +{ + + symbol : symbolPut_functor, + +} + +// + +let Suite = +{ + + toElement : toElementSuite, + alias : aliasSuite, + toValue : toValueGet_functor, + +} + +// -- +// extend +// -- + +_.accessor.getter = _.accessor.getter || Object.create( null ); +/* _.props.extend */Object.assign( _.accessor.getter, Getter ); + +_.accessor.setter = _.accessor.setter || Object.create( null ); +/* _.props.extend */Object.assign( _.accessor.setter, Setter ); + +_.accessor.putter = _.accessor.putter || Object.create( null ); +/* _.props.extend */Object.assign( _.accessor.putter, Putter ); + +_.accessor.suite = _.accessor.suite || Object.create( null ); +/* _.props.extend */Object.assign( _.accessor.suite, Suite ); + +_.accessor.define.getter = _.accessor._DefinesGenerate( _.accessor.define.getter || null, _.accessor.getter, 'getter' ); +_.accessor.define.setter = _.accessor._DefinesGenerate( _.accessor.define.setter || null, _.accessor.setter, 'setter' ); +_.accessor.define.putter = _.accessor._DefinesGenerate( _.accessor.define.putter || null, _.accessor.putter, 'putter' ); +_.accessor.define.suite = _.accessor._DefinesGenerate( _.accessor.define.suite || null, _.accessor.suite, 'accessor' ); + +_.assert( _.routineIs( _.accessor.define.getter.alias ) ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/l5/Collection.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Collection_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Collection_s */ })(); + +/* */ /* begin of file Like_s */ ( function Like_s() { function Like_s_naked() { ( function _Like_s_() { + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + +} + +const _global = _global_; +const _ = _global_.wTools; +const _ObjectHasOwnProperty = Object.hasOwnProperty; + +_.assert( !_.lconstruction ) + +// + +const Parent = null; +const Self = function wLike( o ) +{ +} + +Self.shortName = 'Like'; + +// -- +// helper +// -- + +function like() +{ + var helper = new Self(); + var proto = Object.create( null ); + var location; + + Object.defineProperty( proto, 'copy', + { + enumerable : false, + configurable : false, + writable : false, + value : function copy( o ) + { + // debugger; + _.assert( arguments.length === 1, 'Expects single argument' ); + _.props.extend( this, o ); + return this; + } + }); + + Object.defineProperty( proto, 'constructor', + { + enumerable : false, + configurable : false, + writable : false, + value : function Construction( o ) + { + _.assert( arguments.length === 0 || arguments.length === 1, 'lconstruction expects one or none argument' ); + + if( !( this instanceof proto.constructor ) ) + if( o instanceof proto.constructor ) + return o; + else + return new( _.constructorJoin( proto.constructor, arguments ) ); + + _.map.assertHasOnly( this, proto, 'Prototype of the object ' + ( location ? 'defined at\n' + location + '\n' : '' ) + 'does not have requested fields.' ); + + _.mapComplement( this, proto ); + Object.preventExtensions( this ); + + if( o ) + _.props.extend( this, o ); + + return this; + } + }); + + var allClasses = [ proto ]; + for( var a = 0 ; a < arguments.length ; a++ ) + { + var arg = arguments[ a ]; + _.assert( !!arg[ symbolForAllClasses ] ); + if( arg[ symbolForAllClasses ] ) + _.arrayAppendArrayOnce( allClasses, arg[ symbolForAllClasses ] ); + } + + proto.constructor.prototype = proto; + + Object.defineProperty( proto, symbolForParents, + { + enumerable : false, + configurable : false, + writable : false, + value : _.longSlice( arguments ), + }); + + Object.defineProperty( proto, symbolForAllClasses, + { + enumerable : false, + configurable : false, + writable : false, + value : allClasses, + }); + + Object.defineProperty( proto, symbolForClass, + { + enumerable : false, + configurable : false, + writable : false, + value : proto, + }); + + /* */ + + helper.proto = proto; + helper.usingPrototype = false; + + Object.freeze( helper ); + + if( arguments.length > 0 ) + _.props.extend( null, proto, ... arguments ); + // _.props.extend.apply( _, Array.prototype.concat.apply( [ proto ], arguments ) ); + + return helper; +} + +// + +function name( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + return this; +} + +// + +function also( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.props.extend( this.proto, src ); + return this; +} + +// + +function but( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.mapDelete( this.proto, src ); + return this; +} + +// + +function _endGet() +{ + return this.proto; +} + +// + +function isLike( instance, parent ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + if( !instance[ symbolForAllClasses ] ) + return false; + return instance[ symbolForAllClasses ].indexOf( parent ) !== -1; +} + +// + +function is( instance ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + if( !instance ) + return false; + if( !instance.constructor ) + return false; + if( instance.constructor.name === 'Construction' ) + return true; +} + +// -- +// var +// -- + +var symbolForParents = Symbol.for( 'parents' ); +var symbolForClass = Symbol.for( 'class' ); +var symbolForAllClasses = Symbol.for( 'allClasses' ); + +// -- +// declare +// -- + +const LconstructionExtension = +{ + is, + isLike, +} + +_.assert( !_.lconstruction ); +_.lconstruction = Object.create( null ); +/* _.props.extend */Object.assign( _.lconstruction, LconstructionExtension ); + +// -- +// declare +// -- + +const ToolsExtension = +{ + like, +} + +_.props.extend( _, ToolsExtension ); + +// -- +// declare +// -- + +const Proto = +{ + name, + also, + but, + _endGet, +} + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); + +_.accessor.readOnly +({ + object : Self.prototype, + names : { end : {} }, +}); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/l5/Like.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wProto/proto/wtools/abase/l3_proto/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Like_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Like_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wRegexpObject/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wRegexpObject/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wRegexpObject */ ( function wRegexpObject() { function wRegexpObject_naked() { +module.exports = require( '../wtools/amid/l1/regexp/RegexpObject.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wRegexpObject', 'wregexpobject' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wRegexpObject/proto/node_modules/wRegexpObject' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wRegexpObject/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wRegexpObject_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wRegexpObject */ })(); + +/* */ /* begin of file RegexpObject_s */ ( function RegexpObject_s() { function RegexpObject_s_naked() { ( function _RegexpObject_s_() +{ + +'use strict'; + +/** + * Class which encapsulates a trivial logical combination( expression ) and regular expressions which may be applied to a string to tell does that string satisfies regular expressions as well as the logic. RegexpObject provides functionality to compose, combine several instances of the class, extend it, apply to a string and other. Use it to treat multiple conditions as a single object. Refactoring required. + @module Tools/mid/RegexpObject + */ + +/** + * */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + _.include( 'wCopyable' ); +} + +// + +/** + * @classdesc Class which encapsulates a trivial logical combination( expression ) and regular expressions + * which may be applied to a string to tell does that string satisfies regular expressions as well as the logic. + * @class wRegexpObject + * @module Tools/mid/RegexpObject + */ + +/** + * The complete RegexpObject object. + * @typedef {Object} wRegexpObject + * @property {RegExp[]} includeAny - Array of RegExps, to check matching any of them; + * @property {RegExp[]} includeAll - Array of RegExps, to check matching all of them; + * @property {RegExp[]} excludeAny - Array of RegExps, to check mismatch any of them; + * @property {RegExp[]} excludeAll - Array of RegExps, to check mismatch all of them; + * @module Tools/mid/RegexpObject + */ + +const _ = _global_.wTools; +const Parent = null; +const Self = wRegexpObject; +function wRegexpObject( src, defaultMode ) +{ + if( !( this instanceof Self ) ) + if( src instanceof Self ) + return src; + else + return new( _.constructorJoin( Self, arguments ) ); + return Self.prototype.init.apply( this, arguments ); + // return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'RegexpObject'; + +// + +/** +* @summary Make RegexpObject from different type sources. +* @description +* All strings in sources will be turned into RegExps. +* * If passed RegexpObject or map with properties similar to RegexpObject but with string in values, then the second +* parameter is not required; +* * If passed single RegExp/String or array of RegExps/Strings, then method will return RegexpObject with +* `defaultMode` as key, and array of RegExps created from first parameter as value. +* * If passed array of RegexpObject, mixed with ordinary RegExps/Strings, the result object will be created by merging +* with anding (see [and]{@link wTools#and}) RegexpObjects and RegExps that associates +* with `defaultMode` key. +* +* @example + let src = [ + /hello/, + 'world', + { + includeAny : [ 'yellow', 'blue', 'red' ], + includeAll : [ /red/, /green/, /brown/ ], + excludeAny : [ /yellow/, /white/, /grey/ ], + excludeAll : [ /red/, /green/, /blue/ ] + } + ]; + _.wRegexpObject( src, 'excludeAll' ); + + // { + // includeAny: [ /yellow/, /blue/, /red/ ], + // includeAll: [ /red/, /green/, /brown/ ], + // excludeAny: [ /yellow/, /white/, /grey/ ], + // excludeAll: [ /hello/, /world/ ] + // } +* @param {RegexpObject|String|RegExp|RegexpObject[]|String[]|RegExp[]} src Source for making RegexpObject +* @param {String} [defaultMode] Key for result RegexpObject map. Can be one of next strings: 'includeAny', +'includeAll', 'excludeAny' or 'excludeAll'. +* @returns {RegexpObject} Result RegexpObject +* @throws {Error} Missing arguments if call without argument +* @throws {Error} Missing arguments if passed array without `defaultMode` +* @throws {Error} Unknown mode `defaultMode` +* @throws {Error} Unknown src if first argument is not array, map, string or regexp. +* @throws {Error} Unexpected if type of array element is not string regexp or RegexpObject. +* @throws {Error} Unknown regexp filters if passed map has unexpected properties (see RegexpObject). +* @routine init +* @class wRegexpObject +* @namespace wTools +* @module Tools/mid/RegexpObject +*/ + +function init( src, defaultMode ) +{ + let self = this; + + _.workpiece.initFields( self ); + + if( self.Self === Self ) + Object.preventExtensions( self ); + + /**/ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.object.isBasic( src ) || _.arrayIs( src ) || _.regexpIs( src ) || _.strIs( src ) || src === null, () => 'Unknown type of arguments ' + _.entity.strType( src ) ); + + /**/ + + if( _.regexpIs( src ) ) + src = [ src ]; + + if( _.strIs( src ) ) + src = [ new RegExp( _.regexpEscape( src ) ) ]; + + if( src === null ) + src = []; + + /**/ + + if( _.arrayIs( src ) ) + { + + src = _.arrayFlatten( [], src ); + + let ar = []; + for( let s = 0 ; s < src.length ; s += 1 ) + { + if( _.regexpIs( src[ s ] ) || _.strIs( src[ s ] ) ) + ar.push( _.regexpFrom( src[ s ] ) ); + else if( _.object.isBasic( src[ s ] ) ) + self = Self.Or( self, Self( src[ s ] ) ); + else _.assert( 0, 'Unexpected' ); + } + + if( ar.length ) + { + + defaultMode = defaultMode || 'includeAny'; + _.assert( arguments.length <= 2, 'Expects second argument as default mode, for example "includeAny"' ); + _.assert( !!self.Names[ defaultMode ], 'Unknown mode :', defaultMode ); + + if( self[ defaultMode ] && self[ defaultMode ].length ) + { + let r = {}; + r[ defaultMode ] = ar; + //Self.And( self, r ); + Self.Or( self, r ); + } + else + { + self[ defaultMode ] = ar; + } + } + + } + else if( _.object.isBasic( src ) ) + { + + for( let k in src ) + { + if( !Reflect.hasOwnProperty.call( src, k ) ) + continue; + let e = src[ k ]; + self[ k ] = _.regexpArrayMake( e ); + } + + // _.eachOwn( src, function onEach( e, k ) + // { + // if( e === null ) + // { + // debugger; + // throw _.err( 'not tested' ); + // delete self[ k ]; + // return; + // } + // self[ k ] = _.regexpArrayMake( e ); + // }); + + } + else _.assert( 0, 'wRegexpObject :', 'unknown src', src ); + + _.map.assertOwnOnly( self, self.Names, 'Unknown regexp fields' ); + + if( Config.debug ) + self.validate(); + + return self; +} + +// + +function validate() +{ + let self = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + for( let f in Composes ) + { + _.assert( _.arrayIs( self[ f ] ) ); + for( let i = 0 ; i < self[ f ].length ; i++ ) + { + _.assert( _.regexpIs( self[ f ][ i ] ), 'Regexp object expects regexps, but got', _.entity.strType( self[ f ][ i ] ) ); + } + } + +} + +// + +/** + * Test the `ins` string by condition specified in `src`. If all condition are met, return true + * _test( options, str ); // true + * @param {Object} src Object with options for test + * @param {Regexp[]} [src.excludeAll] Array with regexps for testing. If all of the regexps match at `ins` method + * return the "excludeAll" string, otherwise checks next property in the `src` object + * @param {Regexp[]} [src.excludeAny] Array with regexps for testing. If any of them match `ins` string` method return + * it source string, otherwise checks next property in the `src` object + * @param {Regexp[]} [src.includeAll] Array with regexps for testing. If all of them match `ins` string method check + * next property in `src` object, otherwise return source of regexp that don't match. + * @param {Regexp[]} [src.includeAny] Array with regexps for testing. If no one regexp don't match method return + * "inlcude none from includeAny" string. Else method return true; + * @param {String} ins String for testing + * @returns {String|boolean} If all reason match, return true, otherwise return string with fail reason + * @throws {Error} Throw an 'Expects string' error if `ins` is not string + * @throws {Error} Throw an 'Expects object' error if `src` is not object + * @method _test + * @class wRegexpObject + * @namespace wTools + * @module Tools/mid/RegexpObject +*/ + +//function _test( src, ins ) +function _test( ins ) +{ + let src = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( !_.strIs( ins ) ) + throw _.err( 'test :', 'Expects string as second argument', ins ); + + if( src.excludeAll ) + { + let r = _.regexpArrayAll( src.excludeAll, ins, false ); + if( r === true ) + return 'excludeAll'; + } + + if( src.excludeAny ) + { + let r = _.regexpArrayAny( src.excludeAny, ins, false ); + if( r !== false ) + return src.excludeAny[ r ].source; + } + + if( src.includeAll ) + { + let r = _.regexpArrayAll( src.includeAll, ins, true ); + if( r !== true ) + return src.includeAll[ r ].source; + } + + if( src.includeAny ) + { + let r = _.regexpArrayAny( src.includeAny, ins, true ); + if( r === false ) + return 'include none from includeAny'; + } + + return true; +} + +// + +/** + * Function for testing `ins` string for different regexps combination. If all condition passed in `src` object are + * met method return true + * + * @example + * let str = "The RGB color model is an additive color model in which red, green, + * and blue light are added together in various ways to reproduce a broad array of colors"; + * regArr1 = [/red/, /green/, /blue/], + * regArr2 = [/yellow/, /blue/, /red/], + * regArr3 = [/yellow/, /white/, /greey/], + * options = { + * includeAny : regArr2, + * includeAll : regArr1, + * excludeAny : regArr3, + * excludeAll : regArr2 + * }; + * + * wTools.test( options, str ); // true + * @param {Object} src Map object in wich keys are strings each of them mean different condition for test, and values + * are the arrays of regexps; + * @param {Regexp[]} [src.excludeAll] Array with regexps for testing. If all of the regexps match at `ins` method + * return false + * @param {Regexp[]} [src.excludeAny] Array with regexps for testing. If any of them match `ins` string` method return + * false + * @param {Regexp[]} [src.includeAll] Array with regexps for testing. If any of them don't match `ins` string method + * return false + * @param {Regexp[]} [src.includeAny] Array with regexps for testing. If no one of regexps don't match `ins` string + * method return false + * @param ins String for testing + * @returns {boolean} If all test passed return true; + * @throws {Error} Throw an 'Expects string' error if `ins` is not string + * @throws {Error} Throw an 'Expects object' error if `src` is not object + * @method test + * @class wRegexpObject + * @namespace wTools + * @module Tools/mid/RegexpObject +*/ + +function test( ins ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let result = self._test( ins ); + + if( _.strIs( result ) ) + return false; + + if( result === true ) + return true; + + throw _.err( 'unexpected' ); +} + +// + +/** + * @summary Function for testing `ins` string for different regexps combination. If all condition passed in `src` object are + * met method return true + * + * @example + * let str = "The RGB color model is an additive color model in which red, green, + * and blue light are added together in various ways to reproduce a broad array of colors"; + * regArr1 = [/red/, /green/, /blue/], + * regArr2 = [/yellow/, /blue/, /red/], + * regArr3 = [/yellow/, /white/, /greey/], + * options = { + * includeAny : regArr2, + * includeAll : regArr1, + * excludeAny : regArr3, + * excludeAll : regArr2 + * }; + * + * wTools.test( options, str ); // true + * @param {Object} src Map object in wich keys are strings each of them mean different condition for test, and values + * are the arrays of regexps; + * @param {Regexp[]} [src.excludeAll] Array with regexps for testing. If all of the regexps match at `ins` method + * return false + * @param {Regexp[]} [src.excludeAny] Array with regexps for testing. If any of them match `ins` string` method return + * false + * @param {Regexp[]} [src.includeAll] Array with regexps for testing. If any of them don't match `ins` string method + * return false + * @param {Regexp[]} [src.includeAny] Array with regexps for testing. If no one of regexps don't match `ins` string + * method return false + * @param ins String for testing + * @returns {boolean} If all test passed return true; + * @throws {Error} Throw an 'Expects string' error if `ins` is not string + * @throws {Error} Throw an 'Expects object' error if `src` is not object + * @function test + * @module Tools/mid/RegexpObject.wRegexpObject. +*/ + +function Test( self, ins ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + self = Self( self, 'includeAll' ); + return self.test( ins ); +} + +// + +/** + * @summary Merge several RegexpObjects extending one by others. + * @description Order of extending make difference because joining of some parameters without lose is not possible. + * o.anding gives a hint in what direction the lost should be made. + * @param {object} o - options of merging. + * @param {RegexpObject} options.dst RegexpObject to merge in. + * @param {RegexpObject} options.srcs RegexpObjects to merge from. + * @param {Boolean} options.anding Shrinking or broadening mode. + Joining of some parameters without lose is not possible. + This parameter gives a hint in what direction the lost should be made. + * @returns {RegexpObject} Returns merged RegexpObject. + * @throws {Error} If in options missed any of 'dst', 'srcs' or 'anding' properties + * @throws {Error} If options.dst is not object + * @throws {Error} If options.srcs is not longIs object + * @throws {Error} If options.srcs element is not RegexpObject object + * @method _Extend + * @class wRegexpObject + * @namespace wTools + * @module Tools/mid/RegexpObject + */ + +function _Extend( o ) +{ + + if( o.dst === null ) + o.dst = new Self( [] ); + + _.routine.options_( _Extend, o ); + _.assert( _.object.isBasic( o.dst ) ); + _.assert( _.longIs( o.srcs ) ); + _.assert( _.longHas( [ 'extend', 'or', 'and' ], o.mode ) ); + + o.srcs = _.arrayFlatten( [], o.srcs ); + + let result = o.dst; + for( let n in Names ) + if( !result[ n ] ) + result[ n ] = []; + result = Self( result ); + + for( let s = 0 ; s < o.srcs.length ; s++ ) + { + let src = o.srcs[ s ]; + + if( src === null ) + { + continue; + } + else if( !_.object.isBasic( src ) ) + { + // src = Self( src, o.anding ? 'includeAll' : 'includeAny' ); + src = Self( src, o.mode === 'and' ? 'includeAll' : 'includeAny' ); + } + + _.map.assertOwnOnly( src, Names ); + + // let toExtend = o.anding ? RegexpModeNamesToExtendMap : Names; + let toExtend = o.mode === 'and' ? RegexpModeNamesToExtendMap : Names; + + for( let n in toExtend ) + if( src[ n ] ) + if( ( _.arrayIs( src[ n ] ) && src[ n ].length ) || !_.arrayIs( src[ n ] ) ) + { + result[ n ] = _.arrayFlattenOnce( result[ n ], [ src[ n ] ], _.regexpIdentical ); + } + + if( o.mode === 'and' ) + for( let n in RegexpModeNamesToReplaceMap ) + if( src[ n ] ) + if( ( _.arrayIs( src[ n ] ) && src[ n ].length ) || !_.arrayIs( src[ n ] ) ) + { + if( _.regexpIs( src[ n ] ) ) + result[ n ] = [ src[ n ] ]; + else + result[ n ] = src[ n ]; + } + + } + + /* normalize */ + + for( let r in result ) + for( let i = 0; i < result[ r ].length ; i++ ) + { + let element = result[ r ][ i ]; + if( _.strIs( element ) ) + result[ r ][ i ] = new RegExp( _.regexpEscape( element ) ); + } + + /* */ + + _.assert( result instanceof Self ); + if( Config.debug ) + result.validate(); + + return result; +} + +_Extend.defaults = +{ + dst : null, + srcs : null, + // anding : true, + mode : 'extend', +} + +// + +function Extension( dst ) +{ + + let result = this._Extend + ( { + dst : null, + srcs : _.longSlice( arguments, 0 ), + mode : 'extend', + // anding : 1, + } ); + + return result; +} + +// + +/** + * @summary Extends `result` of RegexpObjects by merging other RegexpObjects. + * @description + * The properties such as includeAll, excludeAny are complemented from appropriate properties in source objects + * by merging all of them; + * Properties includeAny and excludeAll are always replaced by appropriate properties from sources without merging, + * + * @example + * let dest = { + * includeAny : [/yellow/, /blue/], + * includeAll : [/red/], + * excludeAny : [/yellow/], + * excludeAll : [/red/] + * }, + * + * src1 = { + * includeAll : [/green/], + * excludeAny : [/white/], + * excludeAll : [/green/, /blue/] + * }, + * src2 = { + * includeAny : [/red/], + * includeAll : [/brown/], + * excludeAny : [/greey/], + * } + * + * RegexpObject.And( dest, src1, src2 ); + * + * //{ + * // includeAny : [/red/], + * // includeAll : [/red/, /green/, /brown/], + * // excludeAny : [/yellow/, /white/, /greey/], + * // excludeAll : [/green/, /blue/] + * //}; + * @param {RegexpObject} result RegexpObject to merge in. + * @param {...RegexpObject} [src] RegexpObjects to merge from. + * @returns {RegexpObject} Reference to `result` parameter; + * @throws {Error} If missed arguments + * @throws {Error} If arguments are not RegexpObject + * @function And + * @module Tools/mid/RegexpObject.wRegexpObject. +*/ + +function And( dst ) +{ + + let result = this._Extend + ( { + dst : null, + srcs : _.longSlice( arguments, 0 ), + // anding : 1, + mode : 'and', + } ); + + return result; +} + +// + +/** + * @summary Extends `result` of RegexpObjects by merging other RegexpObjects. + * @description Appropriate properties such as includeAny, includeAll, excludeAny and excludeAll are complemented from appropriate + * properties in source objects by merging; + * + * @example + * let dest = { + * includeAny : [/yellow/, /blue/], + * includeAll : [/red/], + * excludeAny : [/yellow/], + * excludeAll : [/red/] + * }, + * + * src1 = { + * includeAll : [/green/], + * excludeAny : [/white/], + * excludeAll : [/green/, /blue/] + * }, + * src2 = { + * includeAny : [/red/], + * includeAll : [/brown/], + * excludeAny : [/greey/], + * } + * + * wTools.Or( dest, src1, src2 ); + * + * //{ + * // includeAny : [/yellow/, /blue/, /red/], + * // includeAll : [/red/, /green/, /brown/], + * // excludeAny : [/yellow/, /white/, /greey/], + * // excludeAll : [/red/, /green/, /blue/] + * //}; + * @param {RegexpObject} result RegexpObject to merge in. + * @param {...RegexpObject} [src] RegexpObjects to merge from. + * @returns {RegexpObject} Reference to `result` parameter; + * @throws {Error} If missed arguments + * @throws {Error} If arguments are not RegexpObject + * @function Or + * @module Tools/mid/RegexpObject.wRegexpObject. + */ + +function Or( dst ) +{ + + let result = this._Extend + ( { + dst : null, + srcs : _.longSlice( arguments, 0 ), + // anding : 0, + mode : 'or', + } ); + + return result; +} + +// + +function extend() +{ + let self = this; + + self._Extend + ( { + dst : self, + srcs : arguments, + // anding : 1, + mode : 'extend', + } ); + + return self; +} + +// + +function and() +{ + let self = this; + + self._Extend + ( { + dst : self, + srcs : arguments, + // anding : 1, + mode : 'and', + } ); + + return self; +} + +// + +function or() +{ + let self = this; + + self._Extend + ( { + dst : self, + srcs : arguments, + mode : 'or' + // anding : 0, + } ); + + // debugger; + // throw _.err( 'not tested' ); + + return self; +} + +// + +/** + * @description + * Create RegexpObject, that represents the subtraction for match`s/mismatched with the input RegexpObject object + * e.g. if { includeAll: [ /red/, /green/, /blue/ ] } represents subset of all strings that contains each 'red', 'green' + * and 'blue' words, then result of but() - { excludeAll: [ /red/, /green/, /blue/ ]} will represent the + * subset of all strings that does not contains at least one of those worlds. + * + * @example + * let options = + * { + * includeAny : [/yellow/, /blue/, /red/], + * includeAll : [/red/, /green/, /blue/], + * excludeAny : [/yellow/, /white/, /grey/], + * excludeAll : [/black/, /brown/, /pink/] + * }; + * + * _.RegexpObject.But( options ); + * + * // { + * // "includeAny":[/yellow/, /white/, /grey/], + * // "excludeAny":[/yellow/, /blue/, /red/], + * // "excludeAll":[/red/, /green/, /blue/], + * // "includeAll":[/black/, /brown/, /pink/] + * // } + * + * @param {...RegexpObject|...String|...RegExp} [src] Input RegexpObject map/maps. If passed primitive values, they will + * be interpreted as value for `includeAny` property of RegexpObject. If objects more than one, their includeAny and + * excludeAny properties will be merged. Notice: if objects more than one and every has includeAll/excludeAll arrays + * with more than one elements, method will throw error. + * @returns {RegexpObject} Result RegexpObject map. + * @throws {Error} If objects more than one and every has includeAll/excludeAll arrays with more than one elements + * throws 'cant combineMethodUniform such regexp objects with "but" combiner' + * @method But + * @class wRegexpObject + * @namespace wTools + * @module Tools/mid/RegexpObject + */ + +function But() +{ + let result = Self( [], Self.Names.includeAny ); + + for( let a = 0, al = arguments.length ; a < al ; a++ ) + { + let argument = arguments[ a ]; + let src = Self( argument, Self.Names.includeAny ); + + if( src.includeAny ) result.excludeAny = _.arrayAppendArray( result.excludeAny || [], src.includeAny ); + if( src.excludeAny ) result.includeAny = _.arrayAppendArray( result.includeAny || [], src.excludeAny ); + + if( src.includeAll && src.includeAll.length ) + { + if( src.includeAll.length === 1 ) + { + result.excludeAny = _.arrayAppendArray( result.excludeAny || [], src.includeAll ); + } + else if( !result.excludeAll || result.excludeAll.length === 0 ) + { + result.excludeAll = _.arrayAppendArray( result.excludeAll || [], src.includeAll ); + } + else throw _.err( 'Cant combineMethodUniform such regexp objects with "but" combiner' ); + } + + if( src.excludeAll && src.excludeAll.length ) + { + if( src.excludeAll.length === 1 ) + { + result.includeAny = _.arrayAppendArray( result.includeAny || [], src.excludeAll ); + } + else if( !result.includeAll || result.includeAll.length === 0 ) + { + result.includeAll = _.arrayAppendArray( result.includeAll || [], src.excludeAll ); + } + else throw _.err( 'Cant combineMethodUniform such regexp objects with "but" combiner' ); + } + + } + + return result; +} + +// + +/** + * @description + * Creates array of RegexpObjects, that will be associated with some ordered set of subsets of strings. + * Accepts array of strings. They will be used as base for RegexpObjects. The empty string in array will be + * converted into RegexpObject that associates with subset what is the subtraction of all possible subsets of strings + * and union of subsets which match other words in array. + * If several arrays are passed in the method, the result will be cartesian product of appropriates arrays described + * above. + * @example + * + * let arr1 = ['red', 'blue'], + * arr2 = ['', 'green']; + * + * wTools.Order(arr1, arr2); + * // [ + * // { + * // includeAny:[], + * // includeAll:[/red/], + * // excludeAny:[/green/], + * // excludeAll:[]}, + * // + * // { + * // includeAny:[], + * // includeAll:[/red/, /green/], + * // excludeAny:[], + * // excludeAll:[]}, + * // + * // { + * // includeAny:[], + * // includeAll:[/blue/], + * // excludeAny:[/green/], + * // excludeAll:[]}, + * // + * // { + * // includeAny:[], + * // includeAll:[/blue/, /green/], + * // excludeAny:[], + * // excludeAll:[] + * // } + * // ] + * @param {...String[]} ordering аrray/аrrays of strings + * @returns {RegexpObject[]} аrray of RegexpObject that represent resulting ordering + * @throws {Error} Unexpected type, if passed arguments is not arrays. + * @method Order + * @class wRegexpObject + * @namespace wTools + * @module Tools/mid/RegexpObject + */ + +function Order( ordering ) +{ + let res = []; + + if( arguments.length === 1 && arguments[ 0 ].length === 0 ) + return res; + + for( let a = 0 ; a < arguments.length ; a++ ) + { + let argument = arguments[ a ]; + if( _.arrayIs( argument[ 0 ] ) ) + for( let i = 0 ; i < argument.length ; i++ ) + res.push( _OrderingExclusion( argument[ i ] ) ); + else if( _.strIs( argument[ 0 ] ) ) + res.push( _OrderingExclusion( argument ) ); + else throw _.err( 'unexpected' ); + } + + if( res.length === 1 ) + return res[ 0 ]; + + let result = []; + _.permutation.eachSample + ({ + leftToRight : 0, + sets : res, + onEach : function( sample, index ) + { + let mask = Self.And( {}, sample[ 0 ] ); + for( let s = 1 ; s < sample.length ; s++ ) + Self.And( mask, sample[ s ] ); + result.push( mask ); + } + }); + + return result; +} + +// + +/** + * @description + * Wrap strings passed in `ordering` array into RegexpObjects. + * Any non empty string in input array turns into RegExp which is wraped into array and assign to includeAll, + * property of appropriate object. An empty string in array are replaced by merged subtractions for all created + * RegexpObjects objects. + * + * @param {String[]} ordering - array of strings. + * @returns {RegexpObject[]} Returns array of RegexpObject + * @private + * @throws {Error} If no arguments, or arguments more than 1. + * @method _OrderingExclusion + * @class wRegexpObject + * @namespace wTools + * @module Tools/mid/RegexpObject + */ + +function _OrderingExclusion( ordering ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( !ordering || _.arrayIs( ordering ) ); + + if( !ordering ) + return []; + + if( !ordering.length ) + return ordering; + + let result = []; + + for( let o = 0 ; o < ordering.length ; o++ ) + { + _.assert( _.strIs( ordering[ o ] ) ); + if( ordering[ o ] === '' ) + continue; + result.push( Self( ordering[ o ], Names.includeAll ) ); + } + + let nomask = {}; + for( let r = 0 ; r < result.length ; r++ ) + { + Self.And( nomask, Self.But( result[ r ] ) ); + } + + for( let o = 0 ; o < ordering.length ; o++ ) + { + if( ordering[ o ] === '' ) + result.splice( o, 0, nomask ); + } + + return result; +} + +// + +function isEmpty() +{ + let self = this; + + if( self.includeAny.length > 0 ) + return false; + if( self.includeAll.length > 0 ) + return false; + if( self.excludeAny.length > 0 ) + return false; + if( self.excludeAll.length > 0 ) + return false; + + return true; +} + +// + +function compactField( it ) +{ + let self = this; + + if( it.dst === null ) + return; + + if( _.arrayIs( it.dst ) && !it.dst.length ) + return; + + return it.dst; +} + +// + +function _equalAre( it ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + + it.continue = false; + + if( !it.src ) + return end( false ); + if( !it.src2 ) + return end( false ); + + if( it.strictTyping ) + if( !( it.src instanceof Self ) ) + return end( false ); + if( it.strictTyping ) + if( !( it.src2 instanceof Self ) ) + return end( false ); + + if( it.containing ) + { + + for( let n in self.Names ) + { + if( !it.src[ n ] || !it.src[ n ].length ) + if( !it.src2[ n ] || !it.src2[ n ].length ) + continue; + // if( !it.equal( it.src[ n ], it.src2[ n ] ) ) + if( !it.reperform( it.src[ n ], it.src2[ n ] ) ) + return end( false ); + } + + } + else + { + for( let n in self.Names ) + if( !it.reperform( it.src[ n ], it.src2[ n ] ) ) + // if( !_.entity.identicalShallow( it.src[ n ], it.src2[ n ] ) ) + return end( false ); + } + + return end( true ); + + function end( result ) + { + it.result = result; + } +} + +// -- +// class let +// -- + +// let Names = _.namesCoded +let Names = +{ + includeAny : 'includeAny', + includeAll : 'includeAll', + excludeAny : 'excludeAny', + excludeAll : 'excludeAll', +} + +// let RegexpModeNamesToExtendMap = _.namesCoded +let RegexpModeNamesToExtendMap = +{ + includeAll : 'includeAll', + excludeAny : 'excludeAny', +} + +// let RegexpModeNamesToReplaceMap = _.namesCoded +let RegexpModeNamesToReplaceMap = +{ + includeAny : 'includeAny', + excludeAll : 'excludeAll', +} + +// -- +// relations +// -- + +let Composes = +{ + includeAny : _.define.own( [] ), + includeAll : _.define.own( [] ), + excludeAny : _.define.own( [] ), + excludeAll : _.define.own( [] ), +} + +let Aggregates = +{ +} + +let Associates = +{ +} + +let Restricts = +{ +} + +let Statics = +{ + + Test, + + _Extend, + Extension, + And, + Or, + + But, + + Order, + _OrderingExclusion, + + Names, + RegexpModeNamesToExtendMap, + RegexpModeNamesToReplaceMap, + +} + +// -- +// declare +// -- + +let ExtendRoutines = +{ + + init, + validate, + + _test, + test, + + _Extend, + Extension, + And, + Or, + + extend, + and, + or, + + Order, + _OrderingExclusion, + + isEmpty, + compactField, + + _equalAre, + + // relations + + Composes, + Aggregates, + Associates, + Restricts, + +} + +// + +let SupplementRoutines = +{ + Statics, +} + +// + +_.classDeclare +( { + cls : Self, + parent : Parent, + extend : ExtendRoutines, + supplement : SupplementRoutines, +} ); + +_.Copyable.mixin( Self ); + +Self.prototype[ Symbol.for( 'equalAre' ) ] = _equalAre; + +// -- +// export +// -- + +_global_[ Self.name ] = _[ Self.shortName ] = Self; + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wRegexpObject/proto/wtools/amid/l1/regexp/RegexpObject.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wRegexpObject/proto/wtools/amid/l1/regexp' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, RegexpObject_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file RegexpObject_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wTools */ ( function wTools() { function wTools_naked() { +const _ = module.exports = require( '../wtools/abase/l1/Include.s' ); +_.module.predeclare +({ + alias : [ 'wTools', 'wtools' ], + entryPath : [ __dirname + '/Tools', __filename ], +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/node_modules/wTools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wTools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wTools */ })(); + +/* */ /* begin of file wTools_l1 */ ( function wTools_l1() { function wTools_l1_naked() { +const _ = module.exports = require( '../wtools/abase/l0/Include1.s' ); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/node_modules/wTools.l1' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wTools_l1_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wTools_l1 */ })(); + +/* */ /* begin of file wTools_l3 */ ( function wTools_l3() { function wTools_l3_naked() { +const _ = module.exports = require( '../wtools/abase/l0/Include3.s' ); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/node_modules/wTools.l3' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wTools_l3_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wTools_l3 */ })(); + +/* */ /* begin of file wTools_l5 */ ( function wTools_l5() { function wTools_l5_naked() { +const _ = module.exports = require( '../wtools/abase/l0/Include5.s' ); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/node_modules/wTools.l5' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wTools_l5_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wTools_l5 */ })(); + +/* */ /* begin of file wTools_l7 */ ( function wTools_l7() { function wTools_l7_naked() { +const _ = module.exports = require( '../wtools/abase/l0/Include7.s' ); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/node_modules/wTools.l7' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wTools_l7_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wTools_l7 */ })(); + +/* */ /* begin of file Include_s */ ( function Include_s() { function Include_s_naked() { //#! /usr/bin/env node +( function _l0_Include_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + module[ 'exports' ] = require( './Include7.s' ); + require( './l8/Setup.s' ); +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/Include.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Include_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Include_s */ })(); + +/* */ /* begin of file Include1_s */ ( function Include1_s() { function Include1_s_naked() { //#! /usr/bin/env node +( function _l0_Include1_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + + require( './l0/l0/Global.s' ); + require( './l0/l3/Config.s' ); + require( './l0/l3/Predefined.s' ); + module[ 'exports' ] = require( './l0/l5/Setup.s' ); + + require( './l1/1Diagnostic.s' ); + require( './l1/2Long.s' ); + require( './l1/2Props.s' ); + require( './l1/3Blank.s' ); + require( './l1/5ArgumentsArray.s' ); + require( './l1/5BufferTyped.s' ); + require( './l1/Array.s' ); + require( './l1/ArraySet.s' ); + require( './l1/Auxiliary.s' ); + require( './l1/BigInt.s' ); + require( './l1/Bool.s' ); + require( './l1/Buffer.s' ); + require( './l1/BufferBytes.s' ); + require( './l1/BufferNode.s' ); + require( './l1/BufferRaw.s' ); + require( './l1/BuffersTyped.s' ); + require( './l1/BufferView.s' ); + require( './l1/Class.s' ); + require( './l1/Constructible.s' ); + require( './l1/Container.s' ); + require( './l1/ContainerAdapter.s' ); + require( './l1/Countable.s' ); + require( './l1/Ct.s' ); + require( './l1/Date.s' ); + require( './l1/Entity.s' ); + require( './l1/Escape.s' ); + require( './l1/Event.s' ); + require( './l1/Functional.s' ); + require( './l1/Functor.s' ); + require( './l1/Fuzzy.s' ); + require( './l1/Global.s' ); + require( './l1/HashMap.s' ); + require( './l1/Interval.s' ); + require( './l1/Intervalc.s' ); + require( './l1/Intervall.s' ); + require( './l1/Intervalo.s' ); + require( './l1/Introspector.s' ); + require( './l1/Itself.s' ); + require( './l1/Logger.s' ); + require( './l1/Logic.s' ); + require( './l1/LogicNode.s' ); + require( './l1/Seeker.s' ); + require( './l1/Map.s' ); + require( './l1/Module.s' ); + require( './l1/Number.s' ); + require( './l1/Object.s' ); + require( './l1/Primitive.s' ); + require( './l1/Process.s' ); + require( './l1/Pair.s' ); + require( './l1/Path.s' ); + require( './l1/Printer.s' ); + require( './l1/PropertyTransformer.s' ); + require( './l1/Prototype.s' ); + require( './l1/Regexp.s' ); + require( './l1/Routine.s' ); + require( './l1/Set.s' ); + require( './l1/Sorted.s' ); + require( './l1/Str.s' ); + require( './l1/Stringer.s' ); + require( './l1/StrLines.s' ); + require( './l1/Symbol.s' ); + require( './l1/Time.s' ); + require( './l1/Type.s' ); + require( './l1/Units.s' ); + require( './l1/Unroll.s' ); + require( './l1/Vector.s' ); + require( './l1/Wrap.s' ); + require( './l1/zErr.s' ); + +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/Include1.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Include1_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Include1_s */ })(); + +/* */ /* begin of file Include3_s */ ( function Include3_s() { function Include3_s_naked() { //#! /usr/bin/env node +( function _l0_Include3_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + module[ 'exports' ] = require( './Include1.s' ); + + require( './l3/1Wrap.s' ); + require( './l3/1LogicNode.s' ); + require( './l3/2Props.s' ); + require( './l3/3Blank.s' ); + require( './l3/3Long.s' ); + require( './l3/3Path.s' ); + require( './l3/ArgumentsArray.s' ); + require( './l3/Array.s' ); + require( './l3/ArraySet.s' ); + require( './l3/Auxiliary.s' ); + require( './l3/Bool.s' ); + require( './l3/Buffer.s' ); + require( './l3/BuffersTyped.s' ); + require( './l3/BufferTyped.s' ); + require( './l3/Container.s' ); + require( './l3/ContainerAdapter.s' ); + require( './l3/Countable.s' ); + require( './l3/Diagnostic.s' ); + require( './l3/Entity.s' ); + require( './l3/Event.s' ); + require( './l3/Escape.s' ); + require( './l3/HashMap.s' ); + require( './l3/Itself.s' ); + require( './l3/Logic.s' ); + require( './l3/Map.s' ); + require( './l3/Module.s' ); + require( './l3/Number.s' ); + require( './l3/Object.s' ); + require( './l3/Primitive.s' ); + require( './l3/Process.s' ); + require( './l3/Regexp.s' ); + require( './l3/Routine.s' ); + require( './l3/Seeker.s' ); + require( './l3/Set.s' ); + require( './l3/Str.s' ); + require( './l3/Stringer.s' ); + require( './l3/Time.s' ); + require( './l3/Unroll.s' ); + require( './l3/Vector.s' ); + require( './l3/zErr.s' ); + +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/Include3.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Include3_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Include3_s */ })(); + +/* */ /* begin of file Include5_s */ ( function Include5_s() { function Include5_s_naked() { //#! /usr/bin/env node +( function _l0_Include5_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + module[ 'exports' ] = require( './Include3.s' ); + + require( './l5/1Seeker.s' ); + require( './l5/ArgumentsArray.s' ); + require( './l5/Array.s' ); + require( './l5/ArraySet.s' ); + require( './l5/Auxiliary.s' ); + require( './l5/BigInt.s' ); + require( './l5/Bool.s' ); + require( './l5/Buffer.s' ); + require( './l5/Constructible.s' ); + require( './l5/Container.s' ); + require( './l5/Countable.s' ); + require( './l5/Ct.s' ); + require( './l5/Date.s' ); + require( './l5/Diagnostic.s' ); + require( './l5/Entity.s' ); + require( './l5/Err.s' ); + require( './l5/Escape.s' ); + require( './l5/Event.s' ); + require( './l5/Functional.s' ); + require( './l5/Fuzzy.s' ); + require( './l5/Global.s' ); + require( './l5/HashMap.s' ); + require( './l5/Interval.s' ); + require( './l5/Intervalc.s' ); + require( './l5/Intervall.s' ); + require( './l5/Intervalo.s' ); + require( './l5/Introspector.s' ); + require( './l5/Itself.s' ); + require( './l5/Logic.s' ); + require( './l5/Long.s' ); + require( './l5/Map.s' ); + require( './l5/Number.s' ); + require( './l5/Object.s' ); + require( './l5/Pair.s' ); + require( './l5/Path.s' ); + require( './l5/Permutation.s' ); + require( './l5/Primitive.s' ); + require( './l5/Printer.s' ); + require( './l5/Process.s' ); + require( './l5/Props.s' ); + require( './l5/PropertyTransformer.s' ); + require( './l5/Prototype.s' ); + require( './l5/Regexp.s' ); + require( './l5/Routine.s' ); + require( './l5/Set.s' ); + require( './l5/Sorted.s' ); + require( './l5/Str.s' ); + require( './l5/Stringer.s' ); + require( './l5/Symbol.s' ); + require( './l5/Time.s' ); + require( './l5/Type.s' ); + require( './l5/Units.s' ); + require( './l5/Unroll.s' ); + require( './l5/Vector.s' ); + require( './l5/zModule.s' ); + +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/Include5.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Include5_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Include5_s */ })(); + +/* */ /* begin of file Include7_s */ ( function Include7_s() { function Include7_s_naked() { //#! /usr/bin/env node +( function _l0_Include7_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + module[ 'exports' ] = require( './Include5.s' ); + + // require( './l6/l1/LongDescriptor.s' ); + // require( './l6/l3/Compose.s' ); + // require( './l6/l3/PropertyTransformers.s' ); + // require( './l6/l3/LongContext.s' ); + + require( './l6/Compose.s' ); + require( './l6/PropertyTransformers.s' ); + + require( './l7/ArgumentsArray.s' ); + require( './l7/Array.s' ); + require( './l7/ArraySet.s' ); + require( './l7/Auxiliary.s' ); + require( './l7/BigInt.s' ); + require( './l7/Bool.s' ); + require( './l7/Buffer.s' ); + require( './l7/Constructible.s' ); + require( './l7/Container.s' ); + require( './l7/Countable.s' ); + require( './l7/Ct.s' ); + require( './l7/Date.s' ); + require( './l7/Diagnostic.s' ); + require( './l7/Entity.s' ); + require( './l7/Err.s' ); + require( './l7/Escape.s' ); + require( './l7/Event.s' ); + require( './l7/Functional.s' ); + require( './l7/Fuzzy.s' ); + require( './l7/Global.s' ); + require( './l7/HashMap.s' ); + require( './l7/Interval.s' ); + require( './l7/Intervalc.s' ); + require( './l7/Intervall.s' ); + require( './l7/Intervalo.s' ); + require( './l7/Introspector.s' ); + require( './l7/Logic.s' ); + require( './l7/Seeker.s' ); + require( './l7/Long.s' ); + require( './l7/Map.s' ); + require( './l7/Module.s' ); + require( './l7/Number.s' ); + require( './l7/Object.s' ); + require( './l7/Pair.s' ); + require( './l7/Path.s' ); + require( './l7/Primitive.s' ); + require( './l7/Printer.s' ); + require( './l7/Process.s' ); + require( './l7/Props.s' ); + require( './l7/PropertyTransformer.s' ); + require( './l7/Prototype.s' ); + require( './l7/Regexp.s' ); + require( './l7/Routine.s' ); + require( './l7/Set.s' ); + require( './l7/Sorted.s' ); + require( './l7/Str.s' ); + require( './l7/Stringer.s' ); + require( './l7/Symbol.s' ); + require( './l7/Time.s' ); + require( './l7/Type.s' ); + require( './l7/Units.s' ); + require( './l7/Unroll.s' ); + require( './l7/Vector.s' ); + +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/Include7.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Include7_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Include7_s */ })(); + +/* */ /* begin of file Global_s */ ( function Global_s() { function Global_s_naked() { ( function _Global_s_() +{ + +'use strict'; + +// global + +let _global = get(); +if( !_global._globals_ ) +{ + _global._globals_ = Object.create( null ); + _global._globals_.real = _global._realGlobal_ || _global; + _global._realGlobal_ = _global; + _global._global_ = _global; +} + +// + +function get() +{ + let _global = undefined; + if( typeof _global_ !== 'undefined' && _global_._global_ === _global_ ) + _global = _global_; + else if( typeof globalThis !== 'undefined' && globalThis.globalThis === globalThis ) + _global = globalThis; + else if( typeof Global !== 'undefined' && Global.Global === Global ) + _global = Global; + else if( typeof global !== 'undefined' && global.global === global ) + _global = global; + else if( typeof window !== 'undefined' && window.window === window ) + _global = window; + else if( typeof self !== 'undefined' && self.self === self ) + _global = self; + return _global; +} + +// + +function _new( name, global ) +{ + + if( _realGlobal_._globals_[ name ] ) + throw Error( `Global namespace::${name} already exists!` ); + + let global2 = _realGlobal_._globals_[ name ] = Object.create( global || _realGlobal_ ); + global2.__GLOBAL_NAME__ = name; + global2.wTools = Object.create( null ); + global2.wTools.global = Object.create( null ); + global2.wTools.global.current = global2; + global2.wTools.module = Object.create( null ); + global2.wTools.module.nativeFilesMap = Object.create( null ); + + for( let name in ModuleFileNative._cache ) + { + if( filePathIsBin( name ) ) + global2.wTools.module.nativeFilesMap[ name ] = ModuleFileNative._cache[ name ]; + } + + return global2; +} + +// + +function open( name ) +{ + + if( !_global_.wTools.global.current ) + throw Error( 'Global namespace is not setup' ); + if( !_global_.wTools.module.nativeFilesMap ) + throw Error( 'Global namespace is not setup' ); + + if( !_globals_[ name ] ) + throw Error( `Global namespace::${name} deos not exist!` ); + if( !_global_.__GLOBAL_NAME__ ) + throw Error( `Current global namespace deos not have name!` ); + if( _global_.wTools.module.nativeFilesMap !== ModuleFileNative._cache ) + throw Error( `Current global have native module files map of different global` ); + + _realGlobal_.wTools.global._stack.push + ({ + name : _global_.__GLOBAL_NAME__, + global : _global_, + moduleNativeFilesMap : ModuleFileNative._cache, + }); + + let global2 = _globals_[ name ]; + _realGlobal_._global_ = global2; + ModuleFileNative._cache = global2.wTools.module.nativeFilesMap; + + return global2; +} + +// + +function makeAndOpen( module, name ) +{ + const _global = __.global.new( name, _global_ ); + __.global.open( name ); + __.module.fileSetEnvironment( module, name ); + return _global; +} + +// + +function close( name ) +{ + + if( name !== _global_.__GLOBAL_NAME__ ) + throw Error( `Current global is ${_global_.__GLOBAL_NAME__}, not ${name}` ); + if( _global_.wTools.module.nativeFilesMap !== ModuleFileNative._cache ) + throw Error( `Current global have native module files map of different global` ); + if( !_realGlobal_.wTools.global._stack.length ) + throw Error( `Nothing to close` ); + + let was = _realGlobal_.wTools.global._stack.pop(); + ModuleFileNative._cache = was.moduleNativeFilesMap; + _realGlobal_._global_ = was.global; +} + +// + +function fileSetEnvironment( moduleFile, name ) +{ + let moduleNativeFile = __.module.fileNativeFrom( moduleFile ); + let global2 = _globals_[ name ]; + + if( name === null ) + { + moduleNativeFile._virtualEnvironment = null; + return; + } + + if( !!moduleNativeFile._virtualEnvironment ) + throw Error( `Module already have virtual environment ${moduleNativeFile._virtualEnvironment.name}` ); + if( !_globals_[ name ] ) + throw Error( `Global namespace::${name} deos not exist!` ); + if( !global2.wTools.module.nativeFilesMap ) + throw Error( `Global namespace::${name} deos not have defined module.nativeFilesMap!` ); + + let env = moduleNativeFile._virtualEnvironment = Object.create( null ); + env.name = global2.__GLOBAL_NAME__; + env.global = global2; + env.moduleNativeFilesMap = global2.wTools.module.nativeFilesMap; + + // /* yyy */ + // debugger; + + // let moduleFileName = moduleNativeFile.filename || moduleNativeFile.id; + // if( global2.wTools.module.nativeFilesMap[ moduleFileName ] && global2.wTools.module.nativeFilesMap[ moduleFileName ] !== moduleNativeFile ) + // throw Error( `Namespace::${name} already has native module file :: ${moduleFileName} in nativeFilesMap` ); + // global2.wTools.module.nativeFilesMap[ moduleFileName ] = moduleNativeFile; + + // if( global2.wTools.module.filesMap && moduleNativeFile.universal && global2.wTools.path && global2.wTools.path.canonize ) + // { + // let moduleFileName2 = global2.wTools.path.canonize( moduleFileName ); + // if( global2.wTools.module.filesMap[ moduleFileName2 ] && global2.wTools.module.filesMap[ moduleFileName2 ] !== moduleNativeFile.universal ) + // throw Error( `Namespace::${name} already has universal module file :: ${moduleFileName2} in filesMap` ); + // global2.wTools.module.filesMap[ moduleFileName2 ] = moduleNativeFile; + // } + +} + +// + +function fileResetEnvironment( moduleFile, name ) +{ + let moduleNativeFile = __.module.fileNativeFrom( moduleFile ); + + if( !moduleNativeFile._virtualEnvironment ) + throw Error( `Module deos not have virtual environment` ); + if( moduleNativeFile._virtualEnvironment.name !== name ) + throw Error( `Not global::${name} is not associated global` ) + + delete moduleNativeFile._virtualEnvironment; + +} + +// + +function setup( global, name ) +{ + + if( !name ) + throw Error( 'Expects name of the global' ); + if( Object.hasOwnProperty.call( global, '__GLOBAL_NAME__' ) && global.__GLOBAL_NAME__ !== name ) + throw Error( `The global have name ${global.__GLOBAL_NAME__}, not ${name}` ); + global.__GLOBAL_NAME__ = Object.hasOwnProperty.call( global, '__GLOBAL_NAME__' ) ? global.__GLOBAL_NAME__ : name; + + global.wTools = Object.hasOwnProperty.call( global, 'wTools' ) ? global.wTools : Object.create( null ); + + global.wTools.global = global.wTools.global || Object.create( null ); + if( global.wTools.global.current && global.wTools.global.current !== global ) + throw Error( 'The global refers to different global. Something wrong!' ); + global.wTools.global.current = global.wTools.global.current || global; + + global.wTools.module = global.wTools.module || Object.create( null ); + if( typeof module !== 'undefined' ) + if( typeof module !== 'undefined' ) + global.wTools.module.nativeFilesMap = global.wTools.module.nativeFilesMap || require( 'module' )._cache; + + if( !global.wTools.module.rootFileNative ) + { + let rootFileNative = global.wTools.module.rootFileNative = module; + while( __.module.fileNativeParent( rootFileNative ) ) + rootFileNative = __.module.fileNativeParent( rootFileNative ); + global.wTools.module.rootFileNative = rootFileNative; + } + + const ModuleFileNative = require( 'module' ); + if( !global.wTools.module.nativeFilesMap ) + global.wTools.module.nativeFilesMap = ModuleFileNative._cache; + +} + +// + +/* qqq xxx : cover */ +function fileNativeIs( src ) +{ + if( !src ) + return false; + if( !ModuleFileNative ) + return true; + return src instanceof ModuleFileNative; +} + +// + +/* qqq xxx : cover */ +function fileUniversalIs( src ) +{ + if( !src ) + return false; + if( Reflect.hasOwnProperty( src, 'constructor' ) ) + return false; + return src[ ModuleFileSymbol ] === true; +} + +// + +function fileNativeFrom( src ) +{ + if( __.module.fileNativeIs( src ) ) + return src; + if( __.module.fileUniversalIs( src ) ) + return src.moduleNativeFile || undefined; + return undefined; +} + +// + +function fileNativeParent( file ) +{ + if( file.parent && file.parent.id !== undefined ) + return file.parent; +} + +// + +function filePathIsBin( filePath ) +{ + const regexp = /\.node$/; + return regexp.test( filePath ); +} + +// + +const ModuleFileSymbol = Symbol.for( 'ModuleFile' ); +const ModuleFileNative = typeof module !== 'undefined' ? require( 'module' ) : null; +const __ = _realGlobal_.wTools = _realGlobal_.wTools || Object.create( null ); +__.global = __.global || Object.create( null ); +__.module = __.module || Object.create( null ); + +__.global._stack = __.global._stack || []; +__.global.get = __.global.get || get; +__.global.new = __.global.new || _new; +__.global.open = __.global.open || open; +__.global.makeAndOpen = __.global.makeAndOpen || makeAndOpen; +__.global.close = __.global.close || close; +__.global.setup = __.global.setup || setup; + +__.module.fileSetEnvironment = __.module.fileSetEnvironment || fileSetEnvironment; +__.module.fileResetEnvironment = __.module.fileResetEnvironment || fileResetEnvironment; +__.module.fileNativeIs = __.module.fileNativeIs || fileNativeIs; +__.module.fileUniversalIs = __.module.fileUniversalIs || fileUniversalIs; +__.module.fileNativeFrom = __.module.fileNativeFrom || fileNativeFrom; +__.module.fileNativeParent = __.module.fileNativeParent || fileNativeParent; +__.module.filePathIsBin = __.module.filePathIsBin || filePathIsBin; + +if( _global_ === _realGlobal_ ) +__.global.setup( _realGlobal_, 'real' ); + +// + +})(); +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l0/l0/Global.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l0/l0' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Global_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Global_s */ })(); + +/* */ /* begin of file Config_s */ ( function Config_s() { function Config_s_naked() { ( function _Config_s_() +{ + +'use strict'; + +// real global + +if( !_realGlobal_.Config ) +_realGlobal_.Config = { debug : true } +if( _realGlobal_.Config.debug === undefined ) +_realGlobal_.Config.debug = true; +if( _realGlobal_.Config.interpreter === undefined ) +if( ( ( typeof module !== 'undefined' ) && ( typeof process !== 'undefined' ) ) ) +_realGlobal_.Config.interpreter = 'njs'; +else +_realGlobal_.Config.interpreter = 'browser'; +if( _realGlobal_.Config.isWorker === undefined ) +if( typeof self !== 'undefined' && self.self === self && typeof importScripts !== 'undefined' ) +_realGlobal_.Config.isWorker = true; +else +_realGlobal_.Config.isWorker = false; + +// current global + +if( !_global_.Config ) +_global_.Config = Object.create( _realGlobal_.Config ) +if( _global_.Config.debug === undefined ) +_global_.Config.debug = true; +if( _global_.Config.interpreter === undefined ) +_global_.Config.interpreter = _realGlobal_.Config.interpreter; +if( _global_.Config.isWorker === undefined ) +_global_.Config.isWorker = _realGlobal_.Config.isWorker + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l0/l3/Config.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Config_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Config_s */ })(); + +/* */ /* begin of file Predefined_s */ ( function Predefined_s() { function Predefined_s_naked() { ( function _Predefined_s_() +{ + +'use strict'; + +// global + +const _global = _global_; + +// verification + +if( _global_.__GLOBAL_NAME__ === 'real' ) +{ + if( _global_.wTools && _global_.wTools.Module ) + { + debugger; + throw new Error( 'module::wTools was included several times' ); + } +} + +// setup current global namespace + +if( !_global.__GLOBAL_NAME__ ) +throw Error( 'Current global does not have name. Something wrong!' ); + +const Self = _global.wTools; +let _ = Self; +Self.__GLOBAL_NAME__ = _global.__GLOBAL_NAME__; +Self.tools = Self; + +// name conflict + +// if( _global_.__GLOBAL_NAME__ === 'real' ) +// if( _global_._ ) +// { +// _global_.Underscore = _global_._; +// delete _global_._; +// } + +// special tokens + +Self.def = Symbol.for( 'def' ); +Self.null = Symbol.for( 'null' ); +Self.undefined = Symbol.for( 'undefined' ); +Self.void = Symbol.for( 'void' ); +Self.nothing = Symbol.for( 'nothing' ); +Self.anything = Symbol.for( 'anything' ); +Self.maybe = Symbol.for( 'maybe' ); +Self.unknown = Symbol.for( 'unknown' ); +Self.dont = Symbol.for( 'dont' ); +// Self.unroll = Symbol.for( 'unroll' ); /* xxx : qqq : ask */ +Self.self = Symbol.for( 'self' ); +Self.optional = Symbol.for( 'optional' ); + +// type aliases + +_realGlobal_.U64x = BigUint64Array; +_realGlobal_.U32x = Uint32Array; +_realGlobal_.U16x = Uint16Array; +_realGlobal_.U8x = Uint8Array; +_realGlobal_.U8xClamped = Uint8ClampedArray; +_realGlobal_.Ux = _realGlobal_.U32x; + +_realGlobal_.I64x = BigInt64Array; +_realGlobal_.I32x = Int32Array; +_realGlobal_.I16x = Int16Array; +_realGlobal_.I8x = Int8Array; +_realGlobal_.Ix = _realGlobal_.I32x; + +_realGlobal_.F64x = Float64Array; +_realGlobal_.F32x = Float32Array; +_realGlobal_.Fx = _realGlobal_.F32x; + +if( typeof Buffer !== 'undefined' ) +_realGlobal_.BufferNode = Buffer; +_realGlobal_.BufferRaw = ArrayBuffer; +if( typeof SharedArrayBuffer !== 'undefined' ) +_realGlobal_.BufferRawShared = SharedArrayBuffer; +_realGlobal_.BufferView = DataView; + +_realGlobal_.HashMap = Map; +_realGlobal_.HashMapWeak = WeakMap; + +// -- +// export +// -- + +// _global[ 'wTools' ] = Self; +_global.wTools = Self; +// _global.wBase = Self; + +// if( typeof module !== 'undefined' ) +// module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l0/l3/Predefined.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Predefined_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Predefined_s */ })(); + +/* */ /* begin of file Setup_s */ ( function Setup_s() { function Setup_s_naked() { ( function _Setup_s_() +{ + +'use strict'; + +/** + Collection of general purpose tools for solving problems. Fundamentally extend JavaScript without spoiling, so may be used solely or in conjunction with another module of such kind. Tools contain hundreds of routines to operate effectively with Array, SortedArray, Map, RegExp, Buffer, Time, String, Number, Routine, Error and other fundamental types. The module provides advanced tools for diagnostics and errors handling. Use it to have a stronger foundation for the application. + @module Tools/base/Fundamental +*/ + +/** + * wTools - Generic purpose tools of base level for solving problems in Java Script. + * @namespace Tools + * @module Tools/base/Fundamental + */ + +const _global = _global_; +const _ = _global.wTools; +const Self = _.setup = _.setup || Object.create( null ); + +_.error = _.error || Object.create( null ); +_.process = _.process || Object.create( null ); + +// -- +// setup +// -- + +function _handleUncaught1() +{ + + debugger; + let args = _.error._handleUncaughtHead( arguments ); + let result = _.error._handleUncaught2.apply( this, args ); + + if( _.error._handleUncaught0 ) + _.error._handleUncaught0.apply( this, arguments ); + + return result; +} + +// + +function _handleUncaughtPromise1( err, promise ) +{ + let o = Object.create( null ); + o.promise = promise; + o.err = err; + o.origination = 'uncaught promise error'; + let result = _.error._handleUncaught2.call( this, o ); + return result; +} + +// + +function _handleUncaught2( o ) +{ + return _.error._handleUncaught2Minimal( o ); +} + +// + +function _handleUncaught2Minimal( o ) +{ + if( !o.origination ) + o.origination = 'uncaught error'; + o.prefix = `--------------- ${o.origination} --------------->\n`; + o.postfix = `--------------- ${o.origination} ---------------<\n`; + let errStr = o.err.toString(); + + try + { + errStr = o.err.toString(); + } + catch( err2 ) + { + debugger; + console.error( err2 ); + } + + console.error( o.prefix ); + console.error( errStr ); + console.error( '' ); + console.error( `_realGlobal_._setupUncaughtErrorHandlerDone : ${_realGlobal_._setupUncaughtErrorHandlerDone}` ); + console.error( '' ); + console.error( o.err ? o.err.stack : '' ); + console.error( o.postfix ); + + processExit(); + + /* */ + + function processExit() + { + try + { + if( _global.process ) + { + if( !process.exitCode ) + process.exitCode = -1; + } + } + catch( err2 ) + { + } + } + +} + +// + +function _setupUncaughtErrorHandler2() +{ + + if( _realGlobal_._setupUncaughtErrorHandlerDone ) + return; + + _realGlobal_._setupUncaughtErrorHandlerDone = 1; + + if( _realGlobal_.process && typeof _realGlobal_.process.on === 'function' ) + { + + _realGlobal_.process.on( 'uncaughtException', _.error._handleUncaught1 ); + _realGlobal_.process.on( 'unhandledRejection', _.error._handleUncaughtPromise1 ); + _.error._handleUncaughtHead = _handleUncaughtHeadNode; + if( Config.interpreter === 'browser' ) + _.error._handleUncaughtHead = _handleUncaughtHeadBrowser; + } + else if( Object.hasOwnProperty.call( _realGlobal_, 'onerror' ) ) + { + _.error._handleUncaught0 = _realGlobal_.onerror; + _realGlobal_.onerror = _.error._handleUncaught1; + _.error._handleUncaughtHead = _handleUncaughtHeadBrowser; + } + + /* */ + + function _handleUncaughtHeadBrowser( args ) + { + debugger; + let [ message, sourcePath, lineno, colno, error ] = args; + let err = error || message; + return [ { err : new Error( args[ 0 ] ), args } ]; + } + + /* */ + + function _handleUncaughtHeadNode( args ) + { + return [ { err : args[ 0 ], args } ]; + } + + /* */ + +} + +// + +function _setup2() +{ + + _.error._setupUncaughtErrorHandler2(); + +} + +// -- +// extend +// -- + +let ErrorExtension = +{ + + _handleUncaughtHead : null, + _handleUncaught0 : null, + _handleUncaught1, + _handleUncaughtPromise1, + _handleUncaught2, + _handleUncaught2Minimal, + + _setupUncaughtErrorHandler2, + _setup2, + +} + +let SetupExtension = +{ + +} + +Object.assign( _.error, ErrorExtension ); +Object.assign( _.setup, SetupExtension ); + +_.error._setup2(); + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l0/l5/Setup.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Setup_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Setup_s */ })(); + +/* */ /* begin of file _1Diagnostic_s */ ( function _1Diagnostic_s() { function _1Diagnostic_s_naked() { ( function _l1_1Diagnostic_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.diagnostic = _.diagnostic || Object.create( null ); + +// -- +// +// -- + +function _err() +{ + return new Error( ... arguments ); +} + +// -- +// surer +// -- + +/* xxx : solve problem exporting routines using __boolLike */ +function __boolLike( src ) +{ + let type = Object.prototype.toString.call( src ); + return type === '[object Boolean]' || type === '[object Number]'; +} + +// + +function _sureDebugger( condition ) +{ + if( !_.error.breakpointOnAssertEnabled ) + return; + debugger; /* eslint-disable-line no-debugger */ +} + +// + +function sure( condition, ... args ) +{ + + if( !condition || !__boolLike( condition ) ) + { + _sureDebugger( condition ); + if( !_._err ) + throw Error( ... args ); + if( arguments.length === 1 ) + throw _._err + ({ + args : [ 'Assertion fails' ], + level : 2, + }); + else if( arguments.length === 2 ) + throw _._err + ({ + args : [ arguments[ 1 ] ], + level : 2, + }); + else + throw _._err + ({ + args : Array.prototype.slice.call( arguments, 1 ), + level : 2, + }); + } + + return; +} + +// + +function sureBriefly( condition, ... args ) +{ + + if( !condition || !__boolLike( condition ) ) + { + _sureDebugger( condition ); + if( !_._err ) + throw Error( ... args ); + if( arguments.length === 1 ) + throw _._err + ({ + args : [ 'Assertion fails' ], + level : 2, + brief : 1, + }); + else if( arguments.length === 2 ) + throw _._err + ({ + args : [ arguments[ 1 ] ], + level : 2, + brief : 1, + }); + else + throw _._err + ({ + args : Array.prototype.slice.call( arguments, 1 ), + level : 2, + brief : 1, + }); + } + + return; +} + +// + +function sureWithoutDebugger( condition, ... args ) +{ + + if( !condition || !__boolLike( condition ) ) + { + if( !_._err ) + throw Error( ... args ); + if( arguments.length === 1 ) + throw _._err + ({ + args : [ 'Assertion fails' ], + level : 2, + }); + else if( arguments.length === 2 ) + throw _._err + ({ + args : [ arguments[ 1 ] ], + level : 2, + }); + else + throw _._err + ({ + args : Array.prototype.slice.call( arguments, 1 ), + level : 2, + }); + } + + return; +} + +// -- +// +// -- + +/** + * Checks condition passed by argument( condition ). Works only in debug mode. Uses StackTrace level 2. + * + * @see {@link wTools.err err} + * + * If condition is true routine returns without exceptions, otherwise routine generates and throws exception. By default generates error with message 'Assertion fails'. + * Also generates error using message(s) or existing error object(s) passed after first argument. + * + * @param {*} condition - condition to check. + * @param {String|Error} [ msgs ] - error messages for generated exception. + * + * @example + * let x = 1; + * _.assert( _.strIs( x ), 'incorrect variable type->', typeof x, 'Expects string' ); + * + * // log + * // caught eval (:2:8) + * // incorrect variable type-> number expects string + * // Error + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assert (file://.../wTools/staging/Base.s:4041) + * // at add (:2) + * // at :1 + * + * @example + * function add( x, y ) + * { + * _.assert( arguments.length === 2, 'incorrect arguments count' ); + * return x + y; + * } + * add(); + * + * // log + * // caught add (:3:14) + * // incorrect arguments count + * // Error + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assert (file://.../wTools/staging/Base.s:4035) + * // at add (:3:14) + * // at :6 + * + * @example + * function divide ( x, y ) + * { + * _.assert( y != 0, 'divide by zero' ); + * return x / y; + * } + * divide( 3, 0 ); + * + * // log + * // caught at divide (:2:29) + * // divide by zero + * // Error + * // at _err (file:///.../wTools/staging/Base.s:1418:13) + * // at wTools.errLog (file://.../wTools/staging/Base.s:1462:13) + * // at divide (:2:29) + * // at :1:1 + * @throws {Error} If passed condition( condition ) fails. + * @function assert + * @namespace Tools + */ + +// + +function assert( condition, ... args ) +{ + + if( Config.debug === false ) + return true; + + if( condition !== true ) + { + _assertDebugger( condition, arguments ); + if( !_._err ) + throw Error( ... args ); + if( arguments.length === 1 ) + throw _._err + ({ + args : [ 'Assertion fails' ], + level : 2, + }); + else if( arguments.length === 2 ) + throw _._err + ({ + args : [ arguments[ 1 ] ], + level : 2, + }); + else + throw _._err + ({ + args : Array.prototype.slice.call( arguments, 1 ), + level : 2, + }); + } + + return true; + + function _assertDebugger( condition, args ) + { + if( !_.error.breakpointOnAssertEnabled ) + return; + debugger; /* eslint-disable-line no-debugger */ + } + +} + +// + +function assertWithoutBreakpoint( condition, ... args ) +{ + + if( Config.debug === false ) + return true; + + if( !condition || !__boolLike( condition ) ) + { + if( !_._err ) + throw Error( ... args ); + if( arguments.length === 1 ) + throw _._err + ({ + args : [ 'Assertion fails' ], + level : 2, + }); + else if( arguments.length === 2 ) + throw _._err + ({ + args : [ arguments[ 1 ] ], + level : 2, + }); + else + throw _._err + ({ + args : Array.prototype.slice.call( arguments, 1 ), + level : 2, + }); + } + + return; +} + +// + +function assertNotTested( src ) +{ + _.assert( false, 'not tested : ' + stack( 1 ) ); +} + +// + +/** + * If condition failed, routine prints warning messages passed after condition argument + * @example + * function checkAngles( a, b, c ) + * { + * _.assertWarn( (a + b + c) === 180, 'triangle with that angles does not exists' ); + * }; + * checkAngles( 120, 23, 130 ); + * + * // log 'triangle with that angles does not exists' + * + * @param condition Condition to check. + * @param messages messages to print. + * @function assertWarn + * @namespace Tools + */ + +function assertWarn( condition ) +{ + + if( Config.debug ) + return; + + if( !condition || !__boolLike( condition ) ) + { + console.warn.apply( console, [].slice.call( arguments, 1 ) ); + } + +} + +// -- +// declare +// -- + +if( Config.debug ) +Object.defineProperty( _, 'debugger', +{ + enumerable : false, + configurable : true, + set : function( val ) + { + let debuggerSymbol = Symbol.for( 'debugger' ); + if( _[ debuggerSymbol ] === val ) + return; + _[ debuggerSymbol ] = val; + for( let k in _globals_ ) + if( _globals_[ k ].wTools[ debuggerSymbol ] !== val ) + _globals_[ k ].wTools[ debuggerSymbol ] = val; + }, + get : function() + { + let debuggerSymbol = Symbol.for( 'debugger' ); + let val = _[ debuggerSymbol ]; + if( val ) + debugger; /* eslint-disable-line no-debugger */ + return val; + }, +}); + +// -- +// diagnostic extension +// -- + +let DiagnosticExtension = +{ + + // sure + + sure, + sureBriefly, + sureWithoutDebugger, + + // assert + + assert, + assertWithoutBreakpoint, + assertNotTested, + assertWarn, + +} + +// + +Object.assign( _.diagnostic, DiagnosticExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + // + + _err, + + // sure + + sure, + sureBriefly, + sureWithoutDebugger, + + // assert + + assert, + assertWithoutBreakpoint, + assertNotTested, + assertWarn, + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/1Diagnostic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, _1Diagnostic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file _1Diagnostic_s */ })(); + +/* */ /* begin of file _2Long_s */ ( function _2Long_s() { function _2Long_s_naked() { ( function _l1_Long_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( _.long === undefined ); +_.assert( _.withLong === undefined ); +_.long = _.long || Object.create( null ); +_.long.namespaces = _.long.namespaces || Object.create( null ); +_.long.toolsNamespacesByType = _.long.toolsNamespacesByType || Object.create( null ); +_.long.toolsNamespacesByName = _.long.toolsNamespacesByName || Object.create( null ); +_.long.toolsNamespaces = _.long.toolsNamespacesByName; +_.withLong = _.long.toolsNamespacesByType; + +// -- +// dichotomy +// -- + +/** + * The routine longIs() determines whether the passed value is an array-like or an Array. + * Imortant : longIs returns false for Object, even if the object has length field. + * + * If {-srcMap-} is an array-like or an Array, true is returned, + * otherwise false is. + * + * @param { * } src - The object to be checked. + * + * @example + * _.longIs( [ 1, 2 ] ); + * // returns true + * + * @example + * _.longIs( 10 ); + * // returns false + * + * @example + * let isArr = ( function() { + * return _.longIs( arguments ); + * } )( 'Hello there!' ); + * // returns true + * + * @returns { boolean } Returns true if {-srcMap-} is an array-like or an Array. + * @function longIs. + * @namespace Tools + */ + +// function is( src ) +// { +// if( Array.isArray( src ) ) +// return true +// if( _.bufferTyped.is( src ) ) +// return true; +// if( Object.prototype.toString.call( src ) === '[object Arguments]' ) +// return true; +// +// return false; +// } + +function is_functor() +{ + let result; + const TypedArray = Object.getPrototypeOf( Int8Array ); + //const iteratorSymbol = Symbol.iterator; + + if( _global_.BufferNode ) + result = isNjs; + else + result = isBrowser; + result.functor = is_functor; + return result; + + function isNjs( src ) + { + if( Array.isArray( src ) ) + return true + + if( src instanceof TypedArray ) + { + if( src instanceof BufferNode ) + return false; + return true; + } + isNjs.functor = is_functor; + + // if( arguments[ iteratorSymbol ] === undefined ) + // return false; + if( Object.prototype.toString.call( src ) === '[object Arguments]' ) + return true; + + return false; + } + + function isBrowser( src ) + { + if( Array.isArray( src ) ) + return true + + if( src instanceof TypedArray ) + return true; + + // if( arguments[ iteratorSymbol ] === undefined ) + // return false; + if( Object.prototype.toString.call( src ) === '[object Arguments]' ) + return true; + + return false; + } + isBrowser.functor = is_functor; + +} + +const is = is_functor(); + +// + +function isOld( src ) +{ + + if( _.primitive.is( src ) ) + return false; + if( !_.class.methodIteratorOf( src ) ) + return false; + + if( _.argumentsArray.like( src ) ) + return true; + if( _.bufferTyped.is( src ) ) + return true; + + return false; +} + +// + +function isCompact( src ) +{ + if( _.argumentsArray.like( src ) ) + return true; + if( _.bufferTyped.is( src ) ) + return true; + + return false; +} + +// + +function isUnfolded( src ) +{ + if( Object.prototype.toString.call( src ) === '[object Arguments]' ) + return true; + if( Array.isArray( src ) ) + return true + if( _.bufferTyped.is( src ) ) + return true; + + return false; +} + +// + +function isUnfoldedSmartOrder( src ) +{ + if( Array.isArray( src ) ) + return true + if( _.bufferTyped.is( src ) ) + return true; + // if( !arguments[ Symbol.iterator ] ) + // return false; + if( Object.prototype.toString.call( src ) === '[object Arguments]' ) + return true; + + return false; +} + +// + +function isUnfoldedSmarter_functor() +{ + + const TypedArray = Object.getPrototypeOf( Int8Array ); + //const iteratorSymbol = Symbol.iterator; + + if( _global_.BufferNode ) + return isUnfoldedSmarterNjs; + return isUnfoldedSmarterBrowser; + + function isUnfoldedSmarterNjs( src ) + { + if( Array.isArray( src ) ) + return true + + if( src instanceof TypedArray ) + { + if( src instanceof BufferNode ) + return false; + return true; + } + + // if( arguments[ iteratorSymbol ] === undefined ) + // return false; + if( Object.prototype.toString.call( src ) === '[object Arguments]' ) + return true; + + return false; + } + + function isUnfoldedSmarterBrowser( src ) + { + if( Array.isArray( src ) ) + return true + + if( src instanceof TypedArray ) + return true; + + // if( arguments[ iteratorSymbol ] === undefined ) + // return false; + if( Object.prototype.toString.call( src ) === '[object Arguments]' ) + return true; + + return false; + } + +} + +const isUnfoldedSmarter = isUnfoldedSmarter_functor(); + +// function is( src ) +// { +// +// if( _.primitive.is( src ) ) +// return false; +// if( _.argumentsArray.like( src ) ) +// return true; +// if( _.bufferTypedIs( src ) ) +// return true; +// +// return false; +// } + +// + +function isEmpty( src ) +{ + if( !_.long.is( src ) ) + return false; + return src.length === 0; +} + +// + +function isPopulated( src ) +{ + if( !_.long.is( src ) ) + return false; + return src.length > 0; +} + +// + +function like( src ) /* qqq : cover */ +{ + if( _.primitive.is( src ) ) + return false; + return _.long.is( src ); +} + +// + +function isResizable( src ) +{ + if( _.array.is( src ) ) + return true; + return false; + // return this.is( src ); +} + +// + +function IsResizable() +{ + return this.default.IsResizable(); +} + +// -- +// maker +// -- + +function _makeEmpty( src ) +{ + if( arguments.length === 1 ) + { + if( _.argumentsArray.is( src ) ) + return _.argumentsArray._makeEmpty( 0 ); + else if( _.unroll.is( src ) ) + return _.unroll._makeEmpty(); + if( _.routine.is( src ) ) + { + let result = new src( 0 ); + _.assert( _.long.is( result ) ); + return result; + } + if( this.is( src ) ) + return new src.constructor(); + } + + return this.tools.long.default._makeEmpty(); +} + +// + +function makeEmpty( src ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 ); + if( arguments.length === 1 ) + { + _.assert( _.countable.is( src ) || _.routine.is( src ) ); + // _.assert( this.like( src ) || _.routine.is( src ) ); /* Dmytro : for compatibility with ContainerAdapters source instance should be a Vector, not simple Long */ + return this._makeEmpty( src ); + } + + return this._makeEmpty(); +} + +// + +function _makeUndefined( src, length ) +{ + if( arguments.length === 2 ) + { + if( !_.number.is( length ) ) + { + if( _.number.is( length.length ) ) + length = length.length; + else + length = [ ... length ].length; + } + + if( src === null ) + return this.tools.long.default._makeUndefined( length ); + if( _.argumentsArray.is( src ) ) + return _.argumentsArray._makeUndefined( src, length ); + if( _.unroll.is( src ) ) + return _.unroll._makeUndefined( src, length ); + if( _.routine.is( src ) ) + { + let result = new src( length ); + _.assert( _.long.is( result ) ); + return result; + } + return new src.constructor( length ); + } + else if( arguments.length === 1 ) + { + let constructor; + if( this.like( src ) ) + { + if( _.argumentsArray.is( src ) ) + return _.argumentsArray._makeUndefined( src ); + if( _.unroll.is( src ) ) + return _.unroll._makeUndefined( src ); + constructor = src.constructor; + length = src.length; + } + else + { + return this.tools.long.default._makeUndefined( src ); + } + return new constructor( length ); + } + + return this.tools.long.default._makeUndefined(); +} + +// + +function makeUndefined( src, length ) +{ + // _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + _.assert( 0 <= arguments.length && arguments.length <= 2 ); + if( arguments.length === 2 ) + { + _.assert( src === null || _.long.is( src ) || _.routine.is( src ) ); + _.assert( _.number.is( length ) || _.countable.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( src === null || _.number.is( src ) || this.like( src ) || _.countable.is( src ) || _.routine.is( src ) ); + } + return this._makeUndefined( ... arguments ); +} + +// + +function _makeZeroed( src, length ) +{ + if( arguments.length === 2 ) + { + if( !_.number.is( length ) ) + { + if( _.number.is( length.length ) ) + length = length.length; + else + length = [ ... length ].length; + } + + if( src === null ) + return this.tools.long.default._makeZeroed( length ); + if( _.argumentsArray.is( src ) ) + return _.argumentsArray._makeZeroed( src, length ); + if( _.unroll.is( src ) ) + return _.unroll._makeZeroed( src, length ); + if( _.routine.is( src ) ) + { + let result = fill( new src( length ) ); + _.assert( _.long.is( result ) ); + return result; + } + return fill( new src.constructor( length ) ); + } + else if( arguments.length === 1 ) + { + let constructor; + if( this.like( src ) ) + { + if( _.argumentsArray.is( src ) ) + return _.argumentsArray._makeZeroed( src ); + if( _.unroll.is( src ) ) + return _.unroll._makeZeroed( src ); + constructor = src.constructor; + length = src.length; + } + else + { + return this.tools.long.default._makeZeroed( src ); + } + return fill( new constructor( length ) ); + } + + return this.tools.long.default._make(); + + /* */ + + function fill( dst ) + { + let l = dst.length; + for( let i = 0 ; i < l ; i++ ) + dst[ i ] = 0; + return dst; + } +} + +// + +function makeZeroed( src, length ) +{ + // _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + _.assert( 0 <= arguments.length && arguments.length <= 2 ); + if( arguments.length === 2 ) + { + _.assert( src === null || _.long.is( src ) || _.routine.is( src ) ); + _.assert( _.number.is( length ) || _.countable.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( src === null || _.number.is( src ) || this.like( src ) || _.countable.is( src ) || _.routine.is( src ) ); + } + return this._makeZeroed( ... arguments ); +} + +// + +function _makeFilling( type, value, length ) +{ + if( arguments.length === 2 ) + { + value = arguments[ 0 ]; + length = arguments[ 1 ]; + + if( this.like( length ) ) + type = length; + else + type = null; + } + + if( !_.number.is( length ) ) + // if( _.long.is( length ) ) + if( length.length ) + length = length.length; + else if( _.countable.is( length ) ) + length = [ ... length ].length; + + let result = this._make( type, length ); + for( let i = 0 ; i < length ; i++ ) + result[ i ] = value; + + return result; +} + +// + +function makeFilling( type, value, length ) +{ + if( arguments.length === 2 ) + { + _.assert( _.number.is( value ) || _.countable.is( value ) ); + _.assert( type !== undefined ); + } + else if( arguments.length === 3 ) + { + _.assert( value !== undefined ); + _.assert( _.number.is( length ) || _.countable.is( length ) ); + _.assert( type === null || this.like( type ) || _.routine.is( type ) ); + } + else + { + _.assert( 0, 'Expects 2 or 3 arguments' ); + } + + return this._makeFilling( ... arguments ); +} + +// + +function _make( src, length ) +{ + if( arguments.length === 2 ) + { + let data = length; + if( _.number.is( length ) ) + { + data = src; + } + else + { + if( _.number.is( length.length ) ) + { + length = length.length; + } + else + { + data = [ ... length ]; + length = data.length; + } + } + if( _.argumentsArray.is( src ) ) + return fill( _.argumentsArray._make( length ), data ); + if( _.unroll.is( src ) ) + return fill( _.unroll._make( length ), data ); + if( src === null ) + return fill( this.tools.long.default._make( length ), data ); + let result; + if( _.routine.is( src ) ) + result = fill( new src( length ), data ) + else if( src.constructor ) + result = fill( new src.constructor( length ), data ); + _.assert( _.long.is( result ), 'Not clear how to make such long' ); + return result; + } + else if( src !== undefined && src !== null ) + { + if( _.number.is( src ) ) + return this.tools.long.default._make( src ); + if( _.unroll.is( src ) ) + return _.unroll._make( src ); + if( _.argumentsArray.is( src ) ) + return _.argumentsArray._make( src ); + if( src.constructor === Array ) + return [ ... src ]; + if( _.buffer.typedIs( src ) ) + return new src.constructor( src ); + if( _.countable.is( src ) ) + return this.tools.long.default._make( src ); + if( _.routine.is( src ) ) + { + let result = new src(); + _.assert( this.is( result ), 'Expects long as returned instance' ); + return result; + } + } + + return this.tools.long.default.make(); + + /* */ + + function fill( dst, data ) + { + if( data === null || data === undefined ) + return dst; + let l = Math.min( length, data.length ); + for( let i = 0 ; i < l ; i++ ) + dst[ i ] = data[ i ]; + return dst; + } +} + +// + +function make( src, length ) +{ + _.assert( arguments.length <= 2 ); + if( arguments.length === 2 ) + { + _.assert( src === null || _.long.is( src ) || _.routine.is( src ) ); + _.assert( _.number.is( length ) || _.countable.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( src === null || _.number.is( src ) || _.long.is( src ) || _.countable.is( src ) || _.routine.is( src ) ); + } + return this._make( ... arguments ); +} + +// + +function _cloneShallow( src ) +{ + if( _.argumentsArray.is( src ) ) + return _.argumentsArray.make( src ); + if( _.unroll.is( src ) ) + return _.unroll.make( src ); + // if( _.number.is( src ) ) /* Dmytro : wrong branch, public interface forbids numbers as argument */ + // return this.tools.long.default.make( src ); + if( src.constructor === Array ) + return [ ... src ]; + else + return new src.constructor( src ); +} + +// + +function cloneShallow( src ) +{ + _.assert( this.like( src ) ); + _.assert( arguments.length === 1 ); + return this._cloneShallow( src ); +} + +// + +function from( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + if( this.is( src ) ) + return src; + if( src === null ) + return this.make( null ); + return this.make( null, src ); +} + +// -- +// long sequential search +// -- + +function leftIndex( /* arr, ins, evaluator1, evaluator2 */ ) +{ + let arr = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let fromIndex = 0; + + if( _.number.is( arguments[ 2 ] ) ) + { + fromIndex = arguments[ 2 ]; + evaluator1 = arguments[ 3 ]; + evaluator2 = arguments[ 4 ]; + } + + _.assert( 2 <= arguments.length && arguments.length <= 5, 'Expects 2-5 arguments: source array, element, and optional evaluator / equalizer' ); + _.assert( _.longLike( arr ), 'Expect a Long' ); + _.assert( _.number.is( fromIndex ) ); + _.assert( !evaluator1 || evaluator1.length === 1 || evaluator1.length === 2 || evaluator1.length === 3 ); + _.assert( !evaluator1 || _.routine.is( evaluator1 ) ); + _.assert( !evaluator2 || evaluator2.length === 1 ); + _.assert( !evaluator2 || _.routine.is( evaluator2 ) ); + + if( !evaluator1 ) + { + _.assert( !evaluator2 ); + return Array.prototype.indexOf.call( arr, ins, fromIndex ); + } + else if( evaluator1.length === 1 ) /* equalizer */ + { + + if( evaluator2 ) + ins = evaluator2( ins ); + else + ins = evaluator1( ins ); + + if( arr.findIndex && fromIndex === 0 ) + { + return arr.findIndex( ( val ) => evaluator1( val ) === ins ); + } + else + { + for( let a = fromIndex; a < arr.length ; a++ ) + { + if( evaluator1( arr[ a ] ) === ins ) + return a; + } + } + + } + else /* evaluator */ + { + _.assert( !evaluator2 ); + for( let a = fromIndex ; a < arr.length ; a++ ) + { + if( evaluator1( arr[ a ], ins ) ) + return a; + } + } + + return -1; +} + +// + +function rightIndex( /* arr, ins, evaluator1, evaluator2 */ ) +{ + let arr = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let fromIndex = arr.length-1; + + if( _.number.is( arguments[ 2 ] ) ) + { + fromIndex = arguments[ 2 ]; + evaluator1 = arguments[ 3 ]; + evaluator2 = arguments[ 4 ]; + } + + _.assert( 2 <= arguments.length && arguments.length <= 5, 'Expects 2-5 arguments: source array, element, and optional evaluator / equalizer' ); + _.assert( _.number.is( fromIndex ) ); + _.assert( !evaluator1 || evaluator1.length === 1 || evaluator1.length === 2 || evaluator1.length === 3 ); + _.assert( !evaluator1 || _.routine.is( evaluator1 ) ); + _.assert( !evaluator2 || evaluator2.length === 1 ); + _.assert( !evaluator2 || _.routine.is( evaluator2 ) ); + + if( !evaluator1 ) + { + _.assert( !evaluator2 ); + return Array.prototype.lastIndexOf.call( arr, ins, fromIndex ); + } + else if( evaluator1.length === 1 ) /* equalizer */ + { + + if( evaluator2 ) + ins = evaluator2( ins ); + else + ins = evaluator1( ins ); + + for( let a = fromIndex ; a >= 0 ; a-- ) + { + if( evaluator1( arr[ a ] ) === ins ) + return a; + } + + } + else /* evaluator */ + { + _.assert( !evaluator2 ); + for( let a = fromIndex ; a >= 0 ; a-- ) + { + if( evaluator1( arr[ a ], ins ) ) + return a; + } + } + + return -1; +} + +// + +/** + * The routine longLeft() returns a new object containing the properties, (index, element), + * corresponding to a found value {-ins-} from a Long {-arr-}. + * If element is not founded, then routine return new object with property (index), which value is -1. + * + * @param { Long } arr - A Long to check. + * @param { * } ins - An element to locate in the {-arr-}. + * @param { Number } fromIndex - An index from which routine starts search left to right. + * If {-fromIndex-} not defined, then routine starts search from the first index. + * @param { Function } evaluator1 - It's a callback. If the routine has two parameters, + * it is used as an equalizer, and if it has only one, then routine is used as the evaluator. + * @param { Function } onEvaluate2 - The second part of evaluator. Accepts the {-ins-} to search. + * + * @example + * _.longLeft( [ 1, 2, false, 'str', 2, 5 ], 2 ); + * // returns { index : 1, element : 2 } + * + * @example + * _.longLeft( [ 1, 2, false, 'str', 2, 5 ], [ 2 ] ); + * // returns { index : -1 } + * + * @example + * _.longLeft( [ 1, 2, false, 'str', 2, 5 ], 2, 3 ); + * // returns { index : 4, element : 2 } + * + * @example + * _.longLeft( [ 1, 2, false, 'str', 2, 5 ], [ 2 ], ( val ) => val[ 0 ] ); + * // returns { index : -1 } + * + * @example + * _.longLeft( [ 1, [ 2 ], false, 'str', 2, 5 ], [ 2 ], ( val ) => val[ 0 ] ); + * // returns { index : 1, element : [ 2 ] } + * + * @example + * _.longLeft( [ 1, [ 2 ], false, 'str', 2, 5 ], [ 2 ], ( val ) => val - 3, ( ins ) => ins[ 0 ] ); + * // returns { index : 5, element : 5 } + * + * @example + * _.longLeft( [ 1, [ 2 ], false, 'str', 2, 5 ], [ 2 ], 3, ( val ) => val + 1, ( ins ) => ins[ 0 ] ); + * // returns { index : 5, element : 5 } + * + * @example + * _.longLeft( [ 1, 2, false, 'str', 2, 5 ], 2, ( val, ins ) => val === ins ); + * // returns { index : 1, element : 2 } + * + * @returns { Object } Returns a new object containing the properties, (index, element), + * corresponding to the found value {-ins-} from the array {-arr-}. + * Otherwise, it returns the object with property (index), which value is -1. + * @function longLeft + * @throws { Error } If arguments.length is less then two or more then five. + * @throws { Error } If {-fromIndex-} is not a number. + * @throws { Error } If {-onEvaluate1-} is not a routine. + * @throws { Error } If {-onEvaluate1-} is undefines and onEvaluate2 provided. + * @throws { Error } If {-onEvaluate1-} is evaluator and accepts less or more then one parameter. + * @throws { Error } If {-onEvaluate1-} is equalizer and onEvaluate2 provided. + * @throws { Error } If {-onEvaluate2-} is not a routine. + * @throws { Error } If {-onEvaluate2-} accepts less or more then one parameter. + * @namespace Tools + */ + +function left( /* arr, ins, fromIndex, evaluator1, evaluator2 */ ) +{ + let arr = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let fromIndex = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + let result = Object.create( null ); + let i = _.longLeftIndex( arr, ins, fromIndex, evaluator1, evaluator2 ); + + _.assert( 2 <= arguments.length && arguments.length <= 5 ); + + result.index = i; + + if( i >= 0 ) + result.element = arr[ i ]; + + return result; +} + +// + +/** + * The routine longRight() returns a new object containing the properties, (index, element), + * corresponding to a found value {-ins-} from a Long {-arr-}. + * If element is not founded, then routine return new object with property (index), which value is -1. + * + * @param { Long } arr - A Long to check. + * @param { * } ins - An element to locate in the {-arr-}. + * @param { Number } fromIndex - An index from which routine starts search right to left. + * If {-fromIndex-} not defined, then routine starts search from the last index. + * @param { Function } evaluator1 - It's a callback. If the routine has two parameters, + * it is used as an equalizer, and if it has only one, then routine is used as the evaluator. + * @param { Function } onEvaluate2 - The second part of evaluator. Accepts the {-ins-} to search. + * + * @example + * _.longRight( [ 1, 2, false, 'str', 2, 5 ], 2 ); + * // returns { index : 4, element : 2 } + * + * @example + * _.longRight( [ 1, 2, false, 'str', 2, 5 ], [ 2 ] ); + * // returns { index : -1 } + * + * @example + * _.longRight( [ 1, 2, false, 'str', 2, 5 ], 2, 3 ); + * // returns { index : 1, element : 2 } + * + * @example + * _.longRight( [ 1, 2, false, 'str', 2, 5 ], [ 2 ], ( val ) => val[ 0 ] ); + * // returns { index : -1 } + * + * @example + * _.longRight( [ 1, [ 2 ], false, 'str', 2, 5 ], [ 2 ], ( val ) => val[ 0 ] ); + * // returns { index : 1, element : [ 2 ] } + * + * @example + * _.longRight( [ 1, [ 2 ], false, 'str', 2, 5 ], [ 2 ], ( val ) => val - 3, ( ins ) => ins[ 0 ] ); + * // returns { index : 5, element : 5 } + * + * @example + * _.longRight( [ 1, [ 2 ], false, 'str', 2, 5 ], [ 2 ], 4, ( val ) => val - 3, ( ins ) => ins[ 0 ] ); + * // returns { index : -1 } + * + * @example + * _.longRight( [ 1, 2, false, 'str', 2, 5 ], 2, ( val, ins ) => val === ins ); + * // returns { index : 4, element : 2 } + * + * @returns { Object } Returns a new object containing the properties, (index, element), + * corresponding to the found value {-ins-} from the array {-arr-}. + * Otherwise, it returns the object with property (index), which value is -1. + * @function longRight + * @throws { Error } If arguments.length is less then two or more then five. + * @throws { Error } If {-fromIndex-} is not a number. + * @throws { Error } If {-onEvaluate1-} is not a routine. + * @throws { Error } If {-onEvaluate1-} is undefines and onEvaluate2 provided. + * @throws { Error } If {-onEvaluate1-} is evaluator and accepts less or more then one parameter. + * @throws { Error } If {-onEvaluate1-} is equalizer and onEvaluate2 provided. + * @throws { Error } If {-onEvaluate2-} is not a routine. + * @throws { Error } If {-onEvaluate2-} accepts less or more then one parameter. + * @namespace Tools + */ + +function right( /* arr, ins, fromIndex, evaluator1, evaluator2 */ ) +{ + let arr = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let fromIndex = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + let result = Object.create( null ); + let i = _.longRightIndex( arr, ins, fromIndex, evaluator1, evaluator2 ); + + _.assert( 2 <= arguments.length && arguments.length <= 5 ); + + result.index = i; + + if( i >= 0 ) + result.element = arr[ i ]; + + return result; +} + +// + +/** + * The routine longLeftDefined() returns a new object containing the properties, (index, element), + * of first left element in a Long {-arr-}, which value is not equal to undefined. + * If element is not founded, then routine return new object with property (index), which value is -1. + * + * @param { Long } arr - A Long to check. + * + * @example + * _.longLeftDefined( [ undefined, undefined, undefined, undefined, undefined ] ); + * // returns { index : -1 } + * + * @example + * _.longLeftDefined( [ 1, undefined, 2, false, 'str', 2, undefined, 5 ] ); + * // returns { index : 0, element : 1 } + * + * @example + * _.longLeftDefined( [ undefined, undefined, 2, false, 'str', 2 ] ); + * // returns { index : 2, element : 2 } + * + * @returns { Object } Returns a new object containing the properties, (index, element), + * of first left element in a Long {-arr-}, which value is not equal to undefined. + * Otherwise, it returns the object with property (index), which value is -1. + * @function longRight + * @throws { Error } If arguments.length is less then or more then one. + * @namespace Tools + */ + +function leftDefined( arr ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + return _.longLeft( arr, true, function( val ){ return val !== undefined; } ); +} + +// + +/** + * The routine longRightDefined() returns a new object containing the properties, (index, element), + * of first right element in a Long {-arr-}, which value is not equal to undefined. + * If element is not founded, then routine return new object with property (index), which value is -1. + * + * @param { Long } arr - A Long to check. + * + * @example + * _.longRightDefined( [ undefined, undefined, undefined, undefined, undefined ] ); + * // returns { index : -1 } + * + * @example + * _.longRightDefined( [ 1, 2, false, 'str', 2, undefined, 5 ] ); + * // returns { index : 6, element : 5 } + * + * @example + * _.longRightDefined( [ 1, 2, false, 'str', 2, undefined, undefined ] ); + * // returns { index : 4, element : 2 } + * + * @returns { Object } Returns a new object containing the properties, (index, element), + * of first right element in a Long {-arr-}, which value is not equal to undefined. + * Otherwise, it returns the object with property (index) which, value is -1. + * @function longRight + * @throws { Error } If arguments.length is less then or more then one. + * @namespace Tools + */ + +function rightDefined( arr ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + return _.longRight( arr, true, function( val ){ return val !== undefined; } ); +} + +// -- +// meta +// -- + +// function _namespaceRegister( namespace ) +// { +// let aggregatorNamespace = this; +// if( !aggregatorNamespace ) +// aggregatorNamespace = _.long; +// +// if( Config.debug ) +// verify(); +// +// aggregatorNamespace.namespaces[ namespace.NamespaceName ] = namespace; +// +// _.assert( !!namespace.IsResizable ); +// _.assert( namespace.IsLong === undefined || namespace.IsLong === true ); +// namespace.IsLong = true; +// +// namespace.asDefault = aggregatorNamespace._asDefaultGenerate( namespace ); +// +// /* */ +// +// function verify() +// { +// _.assert( !!namespace.NamespaceName ); +// _.assert( aggregatorNamespace.namespaces[ namespace.Name ] === undefined ); +// _.assert( _[ namespace.NamespaceName ] === namespace ); +// _.assert( _select( _global_, namespace.NamespaceQname ) === namespace ); +// } +// +// /* */ +// +// function _select( src, selector ) +// { +// selector = selector.split( '/' ); +// while( selector.length && !!src ) +// { +// src = src[ selector[ 0 ] ]; +// selector.splice( 0, 1 ) +// } +// return src; +// } +// +// /* */ +// +// } +// +// // +// +// function _asDefaultGenerate( namespace ) +// { +// let aggregatorNamespace = this; +// +// _.assert( !!namespace ); +// _.assert( !!namespace.TypeName ); +// +// let result = aggregatorNamespace.toolsNamespacesByType[ namespace.TypeName ]; +// if( result ) +// return result; +// +// result = aggregatorNamespace.toolsNamespacesByType[ namespace.TypeName ] = Object.create( _ ); +// +// aggregatorNamespace.toolsNamespacesByName[ namespace.NamespaceName ] = result; +// +// /* xxx : introduce map _.namespaces */ +// for( let name in aggregatorNamespace.namespaces ) +// { +// let namespace = aggregatorNamespace.namespaces[ name ]; +// result[ namespace.TypeName ] = Object.create( namespace ); +// result[ namespace.TypeName ].tools = result; +// } +// +// result[ aggregatorNamespace.NamespaceName ] = Object.create( aggregatorNamespace ); +// result[ aggregatorNamespace.NamespaceName ].tools = result; +// result[ aggregatorNamespace.NamespaceName ].default = namespace; +// +// return result; +// } + +function _namespaceRegister( namespace ) +{ + let aggregatorNamespace = this; + if( !aggregatorNamespace ) + aggregatorNamespace = _.long; + + if( Config.debug ) + verify(); + + // if( namespace.NamespaceName === 'u32x' ) + // debugger; + + namespace.NamespaceNames.forEach( ( name ) => + { + _.assert( aggregatorNamespace.namespaces[ name ] === undefined ); + aggregatorNamespace.namespaces[ name ] = namespace; + }); + + _.assert( !!namespace.IsResizable ); + _.assert( namespace.IsLong === undefined || namespace.IsLong === true ); + namespace.IsLong = true; + + namespace.asDefault = aggregatorNamespace._asDefaultGenerate( namespace ); + + /* */ + + function verify() + { + _.assert( !!namespace.NamespaceName ); + _.assert( aggregatorNamespace.namespaces[ namespace.Name ] === undefined ); + _.assert( _[ namespace.NamespaceName ] === namespace ); + _.assert( _select( _global_, namespace.NamespaceQname ) === namespace ); + } + + /* */ + + function _select( src, selector ) + { + selector = selector.split( '/' ); + while( selector.length && !!src ) + { + src = src[ selector[ 0 ] ]; + selector.splice( 0, 1 ) + } + return src; + } + + /* */ + +} + +// + +function _asDefaultGenerate( namespace ) +{ + let aggregatorNamespace = this; + + _.assert( !!namespace ); + _.assert( !!namespace.TypeName ); + + let result = aggregatorNamespace.toolsNamespacesByType[ namespace.TypeName ]; + if( result ) + return result; + + result = aggregatorNamespace.toolsNamespacesByType[ namespace.TypeName ] = Object.create( _ ); + namespace.TypeNames.forEach( ( name ) => + { + _.assert + ( + aggregatorNamespace.toolsNamespacesByType[ name ] === undefined + || aggregatorNamespace.toolsNamespacesByType[ name ] === result + ); + aggregatorNamespace.toolsNamespacesByType[ name ] = result; + }); + + /* xxx : introduce map _.namespaces */ + for( let name in aggregatorNamespace.namespaces ) + { + let namespace2 = aggregatorNamespace.namespaces[ name ]; + let namespace3 = result[ namespace2.TypeName ] = Object.create( namespace2 ); + namespace3.tools = result; + namespace3.TypeNames.forEach( ( name ) => + { + result[ name ] = namespace3; + }); + } + + let namespace2 = result[ aggregatorNamespace.NamespaceName ] = Object.create( aggregatorNamespace ); + namespace2.tools = result; + namespace2.default = namespace; + aggregatorNamespace.NamespaceNames.forEach( ( name ) => + { + result[ name ] = namespace2; + }); + + return result; +} + +// + +/* qqq : optimize */ +function namespaceOf( src ) +{ + + if( _.unroll.is( src ) ) + return _.unroll; + if( _.array.is( src ) ) + return _.array; + if( _.argumentsArray.is( src ) ) + return _.argumentsArray; + + let result = _.bufferTyped.namespaceOf( src ); + if( result ) + return result; + + if( _.long.is( src ) ) + return _.long; + + // if( _.vector.is( src ) ) + // return _.vector; + // if( _.countable.is( src ) ) + // return _.countable; + + return null; +} + +// + +function namespaceWithDefaultOf( src ) +{ + if( src === null ) + debugger; + if( src === null ) + return this.default; + return this.namespaceOf( src ); +} + +// + +function _functor_functor( methodName, typer, which ) +{ + _.assert( !!( methodName ) ); + if( !typer ) + typer = 'namespaceOf'; + if( !which ) + which = 0; + if( which === 0 ) + return end( _functor0 ); + if( which === 1 ) + return end( _functor1 ); + _.assert( 0 ); + + function _functor0( container ) + { + _.assert( arguments.length === 1 ); + _.assert( _.routine.is( this[ typer ] ), () => `No routine::${typer} in the namesapce::${this.NamespaceName}` ); + const namespace = this[ typer ]( container ); + _.assert( _.routine.is( namespace[ methodName ] ), `No routine::${methodName} in the namesapce::${namespace.NamespaceName}` ); + return namespace[ methodName ].bind( namespace, container ); + } + + function _functor1( container ) + { + _.assert( arguments.length === 1 ); + _.assert( _.routine.is( this[ typer ] ), () => `No routine::${typer} in the namesapce::${this.NamespaceName}` ); + const namespace = this[ typer ]( container ); + _.assert( _.routine.is( namespace[ methodName ] ), `No routine::${methodName} in the namesapce::${namespace.NamespaceName}` ); + const routine0 = namespace[ methodName ]; + return routine1.bind( namespace ); + function routine1( arg1, ... args ) + { + return routine0.call( this, arg1, container, ... args ); + } + } + + function end( result ) + { + result.functor = new Function( `return _.long._functor_functor( '${methodName}', '${typer}', ${which} )` ); + return result; + } + +} + +// -- +// long extension +// -- + +let LongExtension = +{ + + // + + NamespaceName : 'long', + NamespaceNames : [ 'long' ], + NamespaceQname : 'wTools/long', + MoreGeneralNamespaceName : 'long', + MostGeneralNamespaceName : 'countable', + TypeName : 'Long', + TypeNames : [ 'Long' ], + InstanceConstructor : null, + IsLong : true, + tools : _, + + // dichotomy + + is, + isOld, /* xxx : remove later */ + isCompact, + isUnfolded, + isUnfoldedSmartOrder, + isUnfoldedSmarter, + isEmpty, + isPopulated, + like, + isResizable, + IsResizable, + + // maker + + _makeEmpty, + makeEmpty, /* qqq : for junior : cover */ + _makeUndefined, + makeUndefined, /* qqq : for junior : cover */ + _makeZeroed, + makeZeroed, /* qqq : for junior : cover */ + _makeFilling, + makeFilling, + _make, + make, /* qqq : for junior : cover */ + _cloneShallow, + cloneShallow, /* qqq : for junior : cover */ + from, /* qqq : for junior : cover */ + + // long sequential search + + leftIndex, + rightIndex, + + left, + right, + + leftDefined, + rightDefined, + + // meta + + _namespaceRegister, + _asDefaultGenerate, + + // meta + + namespaceOf, + namespaceWithDefaultOf, + _functor_functor, + +} + +// + +Object.assign( _.long, LongExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + // dichotomy + + longIs : is.bind( _.long ), + longIsEmpty : isEmpty.bind( _.long ), + longIsPopulated : isPopulated.bind( _.long ), + longLike : like.bind( _.long ), + + // maker + + longMakeEmpty : makeEmpty.bind( _.long ), + longMakeUndefined : makeUndefined.bind( _.long ), + longMakeZeroed : makeZeroed.bind( _.long ), + longMakeFilling : makeFilling.bind( _.long ), + longMake : make.bind( _.long ), + longCloneShallow : cloneShallow.bind( _.long ), + longFrom : from.bind( _.long ), + + // long sequential search + + longLeftIndex : leftIndex, + longRightIndex : rightIndex, + + longLeft : left, + longRight : right, + + longLeftDefined : leftDefined, + longRightDefined : rightDefined, + +} + +Object.assign( _, ToolsExtension ); + +// + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/2Long.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, _2Long_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file _2Long_s */ })(); + +/* */ /* begin of file _2Props_s */ ( function _2Props_s() { function _2Props_s_naked() { ( function _l1_2Props_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.props = _.props || Object.create( null ); +const prototypeSymbol = Symbol.for( 'prototype' ); +const constructorSymbol = Symbol.for( 'constructor' ); + +// -- +// dichotomy +// -- + +function is( src ) +{ + if( src === null ) + return false; + if( src === undefined ) + return false; + return true; +} + +// + +function like( src ) +{ + return _.props.is( src ); +} + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return true; +} + +// -- +// maker +// -- + +function _makeEmpty( src ) +{ + if( _.map.is( src ) ) + return _.map._makeEmpty( src ); + if( _.aux.is( src ) ) + return _.aux._makeEmpty( src ); + if( _.object.isBasic( src ) ) + return _.object._makeEmpty( src ); + + _.assert( 0, `Not clear how to make ${ _.strType( src ) }` ); +} + +// + +function makeEmpty( src ) +{ + _.assert( arguments.length === 1 ); + return this._makeEmpty( ... arguments ); +} + +// + +function _makeUndefined( src, length ) +{ + if( _.map.is( src ) ) + return _.map._makeUndefined( src ); + if( _.aux.is( src ) ) + return _.aux._makeUndefined( src ); + if( _.object.isBasic( src ) ) + return _.object._makeUndefined( src ); + + _.assert( 0 ); + + return new src.constructor(); +} + +// + +function makeUndefined( src, length ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + return this._makeUndefined( ... arguments ); +} + +// + +function _make( src ) +{ + if( _.map.is( src ) ) + return _.map._make( src ); + if( _.aux.is( src ) ) + return _.aux._make( src ); + if( _.object.isBasic( src ) ) + return _.object._make( src ); + + _.assert( 0 ); + + let method = _.class.methodCloneShallowOf( src ); + if( method ) + return method.call( src ); + return new src.constructor( src ); +} + +// + +function make( src, length ) +{ + _.assert( this.like( src ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + return this._make( ... arguments ); +} + +// + +function _cloneShallow( src ) +{ + if( _.map.is( src ) ) + return _.map._cloneShallow( src ); + if( _.aux.is( src ) ) + return _.aux._cloneShallow( src ); + if( _.object.isBasic( src ) ) + return _.object._cloneShallow( src ); + + let method = _.class.methodCloneShallowOf( src ); + if( method ) + return method.call( src ); + return new src.constructor( src ); + + // _.assert( 0, `Not clear how to clone ${ _.strType( src ) }` ); +} + +// + +function cloneShallow( src ) +{ + _.assert( this.like( src ) ); + _.assert( arguments.length === 1 ); + return this._cloneShallow( src ); +} + +// + +function from( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + if( this.is( src ) ) + return src; + return this.make( src ); +} + +// -- +// amender +// -- + +// // +// +// function supplementStructureless( dstMap, srcMap ) +// { +// if( dstMap === null && arguments.length === 2 ) +// return Object.assign( Object.create( null ), srcMap ); +// +// if( dstMap === null ) +// dstMap = Object.create( null ); +// +// for( let a = 1 ; a < arguments.length ; a++ ) +// { +// srcMap = arguments[ a ]; +// for( let s in srcMap ) +// { +// if( dstMap[ s ] !== undefined ) +// continue; +// +// if( Config.debug ) +// if( _.object.like( srcMap[ s ] ) || _.argumentsArray.like( srcMap[ s ] ) ) +// if( !_.regexpIs( srcMap[ s ] ) && !_.date.is( srcMap[ s ] ) ) +// throw Error( `Source map should have only primitive elements, but ${ s } is ${ srcMap[ s ] }` ); +// +// dstMap[ s ] = srcMap[ s ]; +// } +// } +// +// return dstMap; +// } + +// + +function _extendWithHashmap( dstMap, src ) +{ + for( let [ key, val ] of src ) + dstMap[ key ] = val; + return dstMap; +} + +// + +function _extendWithSet( dstMap, src ) +{ + for( let key of src ) + dstMap[ key ] = key; + return dstMap; +} + +// + +function _extendWithCountable( dstMap, src ) +{ + for( let e of src ) + { + _.assert( e.length === 2 ); + dstMap[ e[ 0 ] ] = e[ 1 ]; + } + return dstMap; +} + +// + +function _extendWithProps( dstMap, src ) +{ + for( let k in src ) + dstMap[ k ] = src[ k ]; + return dstMap; +} + +// + +function _extendUniversal( dstMap, srcMap ) +{ + + _.assert( !_.primitive.is( srcMap ), 'Expects non-primitive' ); + + let srcProto = Object.getPrototypeOf( srcMap ); + if( srcProto === null || srcProto === Object.prototype ) + Object.assign( dstMap, srcMap ); + else if( _.hashMap.like( srcMap ) ) + this._extendWithHashmap( dstMap, srcMap ); /* qqq : cover */ + else if( _.set.like( srcMap ) ) + this._extendWithSet( dstMap, srcMap ); /* qqq : cover */ + else if( _.long.like( srcMap ) ) + this._extendWithCountable( dstMap, srcMap ); /* qqq : cover */ + else + this._extendWithProps( dstMap, srcMap ); /* qqq : cover */ + + return dstMap; +} + +// + +function extendUniversal( dstMap, srcMap ) +{ + + if( dstMap === null ) + dstMap = Object.create( null ); + + if( arguments.length === 2 ) + { + let srcProto = Object.getPrototypeOf( srcMap ); + if( srcProto === null || srcProto === Object.prototype ) + return Object.assign( dstMap, srcMap ); + } + + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + _.assert( this.like( dstMap ), () => `Expects dstMap::${this.NamespaceName} as the first argument` ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + let srcMap = arguments[ a ]; + _.assert( !_.primitive.is( srcMap ), 'Expects non-primitive' ); + + let srcProto = Object.getPrototypeOf( srcMap ); + if( srcProto === null || srcProto === Object.prototype ) + Object.assign( dstMap, srcMap ); + else + this._extendUniversal( dstMap, srcMap ); + + } + + return dstMap; +} + +// + +/** + * The extend() is used to copy the values of all properties + * from one or more source objects to a target object. + * + * It takes first object (dstMap) + * creates variable (result) and assign first object. + * Checks if arguments equal two or more and if (result) is an object. + * If true, + * it extends (result) from the next objects. + * + * @param{ objectLike } dstMap - The target object. + * @param{ ...objectLike } arguments[] - The source object(s). + * + * @example + * _.map.extend( { a : 7, b : 13 }, { c : 3, d : 33 }, { e : 77 } ); + * // returns { a : 7, b : 13, c : 3, d : 33, e : 77 } + * + * @returns { objectLike } It will return the target object. + * @function extend + * @throws { Error } Will throw an error if ( arguments.length < 2 ), + * if the (dstMap) is not an Object. + * @namespace Tools/props + */ + +function extend( dstMap, srcMap ) +{ + + if( dstMap === null ) + dstMap = Object.create( null ); + + if( arguments.length === 2 ) + { + let srcProto = Object.getPrototypeOf( srcMap ); + if( srcProto === null || srcProto === Object.prototype ) + return Object.assign( dstMap, srcMap ); + } + + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + _.assert( this.like( dstMap ), () => `Expects dstMap::${this.NamespaceName} as the first argument` ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + let srcMap = arguments[ a ]; + + _.assert( !_.primitive.is( srcMap ), 'Expects non-primitive' ); + + let srcProto = Object.getPrototypeOf( srcMap ); + if( srcProto === null || srcProto === Object.prototype ) + Object.assign( dstMap, srcMap ); + else + this._extendWithProps( dstMap, srcMap ); + + } + + return dstMap; +} + +// + +function _supplementWithHashmap( dstMap, src ) +{ + for( let [ key, val ] of src ) + if( !( key in dstMap ) ) + dstMap[ key ] = val; + return dstMap; +} + +// + +function _supplementWithSet( dstMap, src ) +{ + for( let key of src ) + if( !( key in dstMap ) ) + dstMap[ key ] = key; + return dstMap; +} + +// + +function _supplementWithCountable( dstMap, src ) +{ + for( let e of src ) + { + _.assert( e.length === 2 ); + if( !( e[ 0 ] in dstMap ) ) + dstMap[ e[ 0 ] ] = e[ 1 ]; + } + return dstMap; +} + +// + +function _supplementWithProps( dstMap, src ) +{ + for( let k in src ) + if( !( k in dstMap ) ) + dstMap[ k ] = src[ k ]; + return dstMap; +} + +// + +function _supplementUniversal( dstMap, srcMap ) +{ + + _.assert( !_.primitive.is( srcMap ), 'Expects non-primitive' ); + + let srcProto = Object.getPrototypeOf( srcMap ); + if( srcProto === null || srcProto === Object.prototype ) + Object.assign( dstMap, srcMap ); + else if( _.hashMap.like( srcMap ) ) + this._supplementWithHashmap( dstMap, srcMap ); /* qqq : cover */ + else if( _.set.like( srcMap ) ) + this._supplementWithSet( dstMap, srcMap ); /* qqq : cover */ + else if( _.long.like( srcMap ) ) + this._supplementWithCountable( dstMap, srcMap ); /* qqq : cover */ + else + this._supplementWithProps( dstMap, srcMap ); /* qqq : cover */ + + return dstMap; +} + +// + +function supplementUniversal( dstMap, srcMap ) +{ + if( dstMap === null && arguments.length === 2 ) + return Object.assign( Object.create( null ), srcMap ); + + if( dstMap === null ) + dstMap = Object.create( null ); + + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + _.assert( this.like( dstMap ), () => `Expects dstMap::${this.NamespaceName} as the first argument` ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + srcMap = arguments[ a ]; + this._supplementWithProps( dstMap, srcMap ); + } + + return dstMap +} + +// + +/** + * The supplement() supplement destination map by source maps. + * Pairs of destination map are not overwritten by pairs of source maps if any overlap. + * Routine rewrite pairs of destination map which has key === undefined. + * + * @param { ...objectLike } arguments[] - The source object(s). + * + * @example + * _.map.supplement( { a : 1, b : 2 }, { a : 1, c : 3 } ); + * // returns { a : 1, b : 2, c : 3 } + * + * @returns { objectLike } Returns an object with unique [ key, value ]. + * @function supplement + * @namespace Tools/props + */ + +function supplement( dstMap, srcMap ) +{ + if( dstMap === null && arguments.length === 2 ) + return Object.assign( Object.create( null ), srcMap ); + if( dstMap === null ) + dstMap = Object.create( null ); + + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + _.assert( this.like( dstMap ), () => `Expects dstMap::${this.NamespaceName} as the first argument` ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + srcMap = arguments[ a ]; + this._supplementWithProps( dstMap, srcMap ); + } + + return dstMap +} + +// -- +// properties +// -- + +function _keys( o ) +{ + let result = []; + + _.routine.options( _keys, o ); + + let srcMap = o.srcMap; + let selectFilter = o.selectFilter; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( this.like( srcMap ) ); + _.assert( selectFilter === null || _.routine.is( selectFilter ) ); + + /* */ + + if( o.onlyEnumerable ) + { + let result1 = []; + + if( o.onlyOwn ) + { + for( let k in srcMap ) + if( Object.hasOwnProperty.call( srcMap, k ) ) + result1.push( k ); + } + else + { + for( let k in srcMap ) + result1.push( k ); + } + + filter( srcMap, result1 ); + + } + else + { + + if( o.onlyOwn ) + { + filter( srcMap, Object.getOwnPropertyNames( srcMap ) ); + } + else + { + let proto = srcMap; + result = []; + do + { + filter( proto, Object.getOwnPropertyNames( proto ) ); + proto = Object.getPrototypeOf( proto ); + } + while( proto ); + } + + } + + return result; + + /* */ + + function filter( srcMap, keys ) + { + + if( !selectFilter ) + { + /* qqq : for junior : rewrite without arrayAppend and without duplicating array */ + arrayAppendArrayOnce( result, keys ); + } + else for( let k = 0 ; k < keys.length ; k++ ) + { + let e = selectFilter( srcMap, keys[ k ] ); + if( e !== undefined ) + arrayAppendOnce( result, e ); + /* qqq : for junior : rewrite without arrayAppend and without duplicating array */ + } + + } + + /* */ + + function arrayAppendOnce( dst, element ) + { + let i = dst.indexOf( element ); + if( i === -1 ) + dst.push( element ); + return dst; + } + + /* */ + + function arrayAppendArrayOnce( dst, src ) + { + src.forEach( ( element ) => + { + let i = dst.indexOf( element ); + if( i === -1 ) + dst.push( element ); + }); + return dst; + } + + /* */ + +} + +_keys.defaults = +{ + srcMap : null, + onlyOwn : 0, + onlyEnumerable : 1, + selectFilter : null, +} + +// + +/** + * This routine returns an array of a given objects onlyEnumerable properties, + * in the same order as that provided by a for...in loop. + * Accept single object. Each element of result array is unique. + * Unlike standard [Object.keys]{@https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys} + * which accept object only props.keys accept any object-like entity. + * + * @see {@link wTools.props.onlyOwnKeys} - Similar routine taking into account own elements only. + * @see {@link wTools.props.vals} - Similar routine returning values. + * + * @example + * _.props.keys({ a : 7, b : 13 }); + * // returns [ "a", "b" ] + * + * @example + * let o = { onlyOwn : 1, onlyEnumerable : 0 }; + * _.props.keys.call( o, { a : 1 } ); + * // returns [ "a" ] + * + * @param { objectLike } srcMap - object of interest to extract keys. + * @param { objectLike } o - routine options can be provided through routine`s context. + * @param { boolean } [ o.onlyOwn = false ] - count only object`s own properties. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * @return { array } Returns an array with unique string elements. + * corresponding to the onlyEnumerable properties found directly upon object or empty array + * if nothing found. + * @function keys + * @throws { Exception } Throw an exception if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools/props + */ + +function keys( srcMap, o ) +{ + let result; + + // _.assert( this === _.object ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( keys, o || null ); + // _.assert( !_.primitive.is( srcMap ) ); + + o.srcMap = srcMap; + + result = this._keys( o ); + + return result; +} + +keys.defaults = +{ + onlyOwn : 0, + onlyEnumerable : 1, +} + +// + +/** + * The props.onlyOwnKeys() returns an array of a given object`s own enumerable properties, + * in the same order as that provided by a for...in loop. Each element of result array is unique. + * + * @param { objectLike } srcMap - The object whose properties keys are to be returned. + * @param { objectLike } o - routine options can be provided through routine`s context. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * + * @example + * _.props.onlyOwnKeys({ a : 7, b : 13 }); + * // returns [ "a", "b" ] + * + * @example + * let o = { onlyEnumerable : 0 }; + * _.props.onlyOwnKeys.call( o, { a : 1 } ); + * // returns [ "a" ] + + * + * @return { array } Returns an array whose elements are strings + * corresponding to the own onlyEnumerable properties found directly upon object or empty + * array if nothing found. + * @function onlyOwnKeys + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools/props +*/ + +function onlyOwnKeys( srcMap, o ) +{ + let result; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( onlyOwnKeys, o || null ); + _.assert( this.like( srcMap ) ); + + o.srcMap = srcMap; + o.onlyOwn = 1; + + result = this._keys( o ); + + if( !o.onlyEnumerable ) + debugger; + + return result; +} + +onlyOwnKeys.defaults = +{ + onlyEnumerable : 1, +} + +// + +function onlyEnumerableKeys( srcMap, o ) +{ + let result; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( onlyEnumerableKeys, o || null ); + _.assert( this.like( srcMap ) ); + + o.srcMap = srcMap; + o.onlyEnumerable = 1; + + result = this._keys( o ); + + return result; +} + +onlyEnumerableKeys.defaults = +{ + onlyOwn : 0, +} + +// + +/** + * The props.allKeys() returns all properties of provided object as array, + * in the same order as that provided by a for...in loop. Each element of result array is unique. + * + * @param { objectLike } srcMap - The object whose properties keys are to be returned. + * + * @example + * let x = { a : 1 }; + * let y = { b : 2 }; + * Object.setPrototypeOf( x, y ); + * _.props.allKeys( x ); + * // returns [ "a", "b", "__defineGetter__", ... "isPrototypeOf" ] + * + * @return { array } Returns an array whose elements are strings + * corresponding to the all properties found on the object. + * @function allKeys + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @namespace Tools/props +*/ + +function allKeys( srcMap, o ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( allKeys, o || null ); + + o.srcMap = srcMap; + + let result = this._keys( o ); + + return result; +} + +/* qqq : write test routine for each option */ +/* qqq : do the same for similar routines */ +/* qqq : adjust similar routine if they handle options no like routine allKeys */ +allKeys.defaults = +{ + onlyOwn : 0, + onlyEnumerable : 0, +} + +// + +function _vals( o ) +{ + + _.routine.options( _vals, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( o.selectFilter === null || _.routine.is( o.selectFilter ) ); + _.assert( o.selectFilter === null ); + + let result = this._keys( o ); + + for( let k = 0 ; k < result.length ; k++ ) + { + result[ k ] = o.srcMap[ result[ k ] ]; + } + + return result; +} + +_vals.defaults = +{ + srcMap : null, + onlyOwn : 0, + onlyEnumerable : 1, + selectFilter : null, +} + +// + +/** + * The props.vals() routine returns an array of a given object's + * onlyEnumerable property values, in the same order as that provided by a for...in loop. + * + * It takes an object {-srcMap-} creates an empty array, + * checks if {-srcMap-} is an object. + * If true, it returns an array of values, + * otherwise it returns an empty array. + * + * @param { objectLike } srcMap - The object whose property values are to be returned. + * @param { objectLike } o - routine options can be provided through routine`s context. + * @param { boolean } [ o.onlyOwn = false ] - count only object`s own properties. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * + * @example + * _.props.vals( { a : 7, b : 13 } ); + * // returns [ "7", "13" ] + * + * @example + * let o = { onlyOwn : 1 }; + * let a = { a : 7 }; + * let b = { b : 13 }; + * Object.setPrototypeOf( a, b ); + * _.props.vals.call( o, a ) + * // returns [ 7 ] + * + * @returns { array } Returns an array whose elements are strings. + * corresponding to the onlyEnumerable property values found directly upon object. + * @function vals + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools/props + */ + +function vals( srcMap, o ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( vals, o || null ); + o.srcMap = srcMap; + + let result = this._vals( o ); + + return result; +} + +vals.defaults = +{ + onlyOwn : 0, + onlyEnumerable : 1, +} + +// + +/** + * The props.onlyOwnVals() routine returns an array of a given object's + * own onlyEnumerable property values, + * in the same order as that provided by a for...in loop. + * + * It takes an object {-srcMap-} creates an empty array, + * checks if {-srcMap-} is an object. + * If true, it returns an array of values, + * otherwise it returns an empty array. + * + * @param { objectLike } srcMap - The object whose property values are to be returned. + * @param { objectLike } o - routine options can be provided through routine`s context. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * + * @example + * _.props.onlyOwnVals( { a : 7, b : 13 } ); + * // returns [ "7", "13" ] + * + * @example + * let o = { onlyEnumerable : 0 }; + * let a = { a : 7 }; + * Object.defineProperty( a, 'x', { onlyEnumerable : 0, value : 1 } ) + * _.props.onlyOwnVals.call( o, a ) + * // returns [ 7, 1 ] + * + * @returns { array } Returns an array whose elements are strings. + * corresponding to the onlyEnumerable property values found directly upon object. + * @function onlyOwnVals + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools/props + */ + +function onlyOwnVals( srcMap, o ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( onlyOwnVals, o || null ); + + o.srcMap = srcMap; + o.onlyOwn = 1; + + let result = this._vals( o ); + + return result; +} + +onlyOwnVals.defaults = +{ + onlyEnumerable : 1, +} + +// + +function onlyEnumerableVals( srcMap, o ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( onlyEnumerableVals, o || null ); + + o.srcMap = srcMap; + o.onlyEnumerable = 1; + + let result = this._vals( o ); + + return result; +} + +onlyEnumerableVals.defaults = +{ + onlyOwn : 0, +} + +// + +/** + * The props.allVals() returns values of all properties of provided object as array, + * in the same order as that provided by a for...in loop. + * + * It takes an object {-srcMap-} creates an empty array, + * checks if {-srcMap-} is an object. + * If true, it returns an array of values, + * otherwise it returns an empty array. + * + * @param { objectLike } srcMap - The object whose property values are to be returned. + * + * @example + * _.props.allVals( { a : 7, b : 13 } ); + * // returns [ "7", "13", function __defineGetter__(), ... function prototype.isPrototypeFor() ] + * + * @returns { array } Returns an array whose elements are strings. + * corresponding to the onlyEnumerable property values found directly upon object. + * @function allVals + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @namespace Tools/props + */ + +function allVals( srcMap, o ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( allVals, o || null ); + + o.srcMap = srcMap; + o.onlyOwn = 0; + o.onlyEnumerable = 0; + + let result = this._vals( o ); + + debugger; + return result; +} + +allVals.defaults = +{ +} + +// + +function _pairs( o ) +{ + + _.routine.options( _pairs, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( o.selectFilter === null || _.routine.is( o.selectFilter ) ); + _.assert( this.like( o.srcMap ) ); + + let selectFilter = o.selectFilter; + + if( o.selectFilter ) + debugger; + + if( !o.selectFilter ) + o.selectFilter = function selectFilter( srcMap, k ) + { + return [ k, srcMap[ k ] ]; + } + + let result = this._keys( o ); + + return result; +} + +_pairs.defaults = +{ + srcMap : null, + onlyOwn : 0, + onlyEnumerable : 1, + selectFilter : null, +} + +// + +/** + * The map.pairs() converts an object into a list of unique [ key, value ] pairs. + * + * It takes an object {-srcMap-} creates an empty array, + * checks if {-srcMap-} is an object. + * If true, it returns a list of [ key, value ] pairs if they exist, + * otherwise it returns an empty array. + * + * @param { objectLike } srcMap - Object to get a list of [ key, value ] pairs. + * @param { objectLike } o - routine options can be provided through routine`s context. + * @param { boolean } [ o.onlyOwn = false ] - count only object`s own properties. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * + * @example + * _.map.pairs( { a : 7, b : 13 } ); + * // returns [ [ "a", 7 ], [ "b", 13 ] ] + * + * @example + * let a = { a : 1 }; + * let b = { b : 2 }; + * Object.setPrototypeOf( a, b ); + * _.map.pairs.call( { onlyOwn : 1 }, a ); + * // returns [ [ "a", 1 ] ] + * + * @returns { array } A list of [ key, value ] pairs. + * @function pairs + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools/props + */ + +function pairs( srcMap, o ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( pairs, o || null ); + + o.srcMap = srcMap; + + let result = this._pairs( o ); + + return result; +} + +pairs.defaults = +{ + onlyOwn : 0, + onlyEnumerable : 1, +} + +// + +/** + * The props.pairs() converts an object's own properties into a list of [ key, value ] pairs. + * + * + * It takes an object {-srcMap-} creates an empty array, + * checks if {-srcMap-} is an object. + * If true, it returns a list of [ key, value ] pairs of object`s own properties if they exist, + * otherwise it returns an empty array. + * + * @param { objectLike } srcMap - Object to get a list of [ key, value ] pairs. + * @param { objectLike } o - routine options can be provided through routine`s context. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * + * @example + * _.props.pairs( { a : 7, b : 13 } ); + * // returns [ [ "a", 7 ], [ "b", 13 ] ] + * + * @example + * let a = { a : 1 }; + * let b = { b : 2 }; + * Object.setPrototypeOf( a, b ); + * _.props.pairs( a ); + * // returns [ [ "a", 1 ] ] + * + * @example + * let a = { a : 1 }; + * _.props.pairs.call( { onlyEnumerable : 0 }, a ); + * + * @returns { array } A list of [ key, value ] pairs. + * @function onlyOwnPairs + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools/props + */ + +function onlyOwnPairs( srcMap, o ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( onlyOwnPairs, o || null ); + + o.srcMap = srcMap; + o.onlyOwn = 1; + + let result = this._pairs( o ); + + debugger; + return result; +} + +onlyOwnPairs.defaults = +{ + onlyEnumerable : 1, +} + +// + +function onlyEnumerablePairs( srcMap, o ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( onlyEnumerablePairs, o || null ); + + o.srcMap = srcMap; + o.onlyEnumerable = 1; + + let result = this._pairs( o ); + + debugger; + return result; +} + +onlyEnumerablePairs.defaults = +{ + onlyOwn : 0, +} + +// + +/** + * The props.allPairs() converts all properties of the object {-srcMap-} into a list of unique [ key, value ] pairs. + * + * It takes an object {-srcMap-} creates an empty array, + * checks if {-srcMap-} is an object. + * If true, it returns a list of [ key, value ] pairs that repesents all properties of provided object{-srcMap-}, + * otherwise it returns an empty array. + * + * @param { objectLike } srcMap - Object to get a list of [ key, value ] pairs. + * + * @example + * _.props.allPairs( { a : 7, b : 13 } ); + * // returns [ [ "a", 7 ], [ "b", 13 ], ... [ "isPrototypeOf", function prototype.isPrototypeFor() ] ] + * + * @example + * let a = { a : 1 }; + * let b = { b : 2 }; + * Object.setPrototypeOf( a, b ); + * _.props.allPairs( a ); + * // returns [ [ "a", 1 ], [ "b", 2 ], ... [ "isPrototypeOf", function prototype.isPrototypeFor() ] ] + * + * @returns { array } A list of [ key, value ] pairs. + * @function allPairs + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @namespace Tools/props + */ + +function allPairs( srcMap, o ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( allPairs, o || null ); + + o.srcMap = srcMap; + o.onlyOwn = 0; + o.onlyEnumerable = 0; + + let result = this._pairs( o ); + + return result; +} + +allPairs.defaults = +{ +} + +// -- +// +// -- + +function _ofAct( o ) +{ + let result = Object.create( null ); + + _.routine.options( _ofAct, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( this === _.props ); + _.assert( this.like( o.srcMap ) ); + + let keys = this._keys( o ); + + for( let k = 0 ; k < keys.length ; k++ ) + { + result[ keys[ k ] ] = o.srcMap[ keys[ k ] ]; + } + + return result; +} + +_ofAct.defaults = +{ + srcMap : null, + onlyOwn : 0, + onlyEnumerable : 1, + selectFilter : null, +} + +// + +/** + * Routine property.of() gets onlyEnumerable properties of the object{-srcMap-} and returns them as new map. + * + * It takes an object {-srcMap-} creates an empty map, + * checks if {-srcMap-} is an object. + * If true, it copies unique onlyEnumerable properties of the provided object to the new map using + * their original name/value and returns the result, + * otherwise it returns empty map. + * + * @param { objectLike } srcMap - Object to get a map of onlyEnumerable properties. + * @param { objectLike } o - routine options can be provided through routine`s context. + * @param { boolean } [ o.onlyOwn = false ] - count only object`s onlyOwn properties. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * + * @example + * _.props.of( { a : 7, b : 13 } ); + * // returns { a : 7, b : 13 } + * + * @example + * let a = { a : 1 }; + * let b = { b : 2 }; + * Object.setPrototypeOf( a, b ); + * _.props.of( a ); + * // returns { a : 1, b : 2 } + * + * @example + * let a = { a : 1 }; + * let b = { b : 2 }; + * Object.setPrototypeOf( a, b ); + * _.props.of.conlyExplicit( { onlyOwn : 1 }, a ) + * // returns { a : 1 } + * + * @returns { object } A new map with unique onlyEnumerable properties from source{-srcMap-}. + * @function of + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools + */ + +function _of( srcMap, o ) +{ + _.assert( this === _.props ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( _of, o || null ); + + o.srcMap = srcMap; + + let result = _.props._ofAct( o ); + return result; +} + +_of.defaults = +{ + onlyOwn : 0, + onlyEnumerable : 1, +} + +// + +/** + * The onlyOwn() gets the object's {-srcMap-} onlyOwn onlyEnumerable properties and returns them as new map. + * + * It takes an object {-srcMap-} creates an empty map, + * checks if {-srcMap-} is an object. + * If true, it copies object's onlyOwn onlyEnumerable properties to the new map using + * their original name/value and returns the result, + * otherwise it returns empty map. + * + * @param { objectLike } srcMap - Source to get a map of object`s onlyOwn onlyEnumerable properties. + * @param { objectLike } o - routine options can be provided through routine`s context. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * + * @example + * _.props.onlyOwn( { a : 7, b : 13 } ); + * // returns { a : 7, b : 13 } + * + * @example + * let a = { a : 1 }; + * let b = { b : 2 }; + * Object.setPrototypeOf( a, b ); + * _.props.onlyOwn( a ); + * // returns { a : 1 } + * + * @example + * let a = { a : 1 }; + * Object.defineProperty( a, 'b', { onlyEnumerable : 0, value : 2 } ); + * _.props.onlyOwn.conlyExplicit( { onlyEnumerable : 0 }, a ) + * // returns { a : 1, b : 2 } + * + * @returns { object } A new map with source {-srcMap-} onlyOwn onlyEnumerable properties. + * @function onlyOwn + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools + */ + +function onlyOwn( srcMap, o ) +{ + + _.assert( this === _.props ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( onlyOwn, o || null ); + + o.srcMap = srcMap; + o.onlyOwn = 1; + + let result = _.props._ofAct( o ); + return result; +} + +onlyOwn.defaults = +{ + onlyEnumerable : 1, +} + +// + +/** + * The onlyExplicit() gets onlyExplicit properties from provided object {-srcMap-} and returns them as new map. + * + * It takes an object {-srcMap-} creates an empty map, + * checks if {-srcMap-} is an object. + * If true, it copies onlyExplicit unique object's properties to the new map using + * their original name/value and returns the result, + * otherwise it returns empty map. + * + * @param { objectLike } srcMap - Source to get a map of onlyExplicit object`s properties. + * + * @example + * _.props.onlyExplicit( { a : 7, b : 13 } ); + * // returns { a : 7, b : 13, __defineGetter__ : function...} + * + * @example + * let a = { a : 1 }; + * let b = { b : 2 }; + * Object.setPrototypeOf( a, b ); + * _.props.onlyExplicit( a ); + * // returns { a : 1, b : 2, __defineGetter__ : function...} + * + * @returns { object } A new map with onlyExplicit unique properties from source {-srcMap-}. + * @function onlyExplicit + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools + */ + +function onlyExplicit( srcMap, o ) +{ + + _.assert( this === _.props ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( onlyExplicit, o || null ); + + o.srcMap = srcMap; + let result = _.props._ofAct( o ); + + return result; +} + +onlyExplicit.defaults = +{ + onlyOwn : 0, + onlyEnumerable : 0, +} + +// + +/** + * The routines() gets onlyEnumerable properties that contains routines as value from the object {-srcMap-} and returns them as new map. + * + * It takes an object {-srcMap-} creates an empty map, + * checks if {-srcMap-} is an object. + * If true, it copies unique onlyEnumerable properties that holds routines from source {-srcMap-} to the new map using + * original name/value of the property and returns the result, otherwise it returns empty map. + * + * @param { objectLike } srcMap - Source to get a map of object`s properties. + * @param { objectLike } o - routine options, can be provided through routine`s context. + * @param { boolean } [ o.onlyOwn = false ] - count only object`s onlyOwn properties. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * + * @example + * _.props.routines( { a : 7, b : 13, f : function(){} } ); + * // returns { f : function(){} } + * + * @example + * let a = { a : 1 }; + * let b = { b : 2, f : function(){} }; + * Object.setPrototypeOf( a, b ); + * _.props.routines( a ) + * // returns { f : function(){} } + * + * @example + * let a = { a : 1 }; + * let b = { b : 2, f : function(){} }; + * Object.setPrototypeOf( a, b ); + * _.props.routines.conlyExplicit( { onlyOwn : 1 }, a ) + * // returns {} + * + * @returns { object } A new map with unique onlyEnumerable routine properties from source {-srcMap-}. + * @function routines + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools + */ + + +function routines( srcMap, o ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( this === _.props ); + o = _.routine.options( routines, o || null ); + + o.srcMap = srcMap; + o.selectFilter = function selectRoutine( srcMap, k ) + { + debugger; + if( _.routine.is( srcMap[ k ] ) ) + return k; + debugger; + } + + debugger; + let result = _.props._ofAct( o ); + return result; +} + +routines.defaults = +{ + onlyOwn : 0, + onlyEnumerable : 1, +} + +// + +/** + * The onlyOwnRoutines() gets object`s {-srcMap-} onlyOwn onlyEnumerable properties that contains routines as value and returns them as new map. + * + * It takes an object {-srcMap-} creates an empty map, + * checks if {-srcMap-} is an object. + * If true, it copies object`s {-srcMap-} onlyOwn unique onlyEnumerable properties that holds routines to the new map using + * original name/value of the property and returns the result, otherwise it returns empty map. + * + * @param { objectLike } srcMap - Source to get a map of object`s properties. + * @param { objectLike } o - routine options, can be provided through routine`s context. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * + * @example + * _.props.onlyOwnRoutines( { a : 7, b : 13, f : function(){} } ); + * // returns { f : function(){} } + * + * @example + * let a = { a : 1 }; + * let b = { b : 2, f : function(){} }; + * Object.setPrototypeOf( a, b ); + * _.props.onlyOwnRoutines( a ) + * // returns {} + * + * @example + * let a = { a : 1 }; + * Object.defineProperty( a, 'b', { onlyEnumerable : 0, value : function(){} } ); + * _.props.onlyOwnRoutines.conlyExplicit( { onlyEnumerable : 0 }, a ) + * // returns { b : function(){} } + * + * @returns { object } A new map with unique object`s onlyOwn onlyEnumerable routine properties from source {-srcMap-}. + * @function onlyOwnRoutines + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools + */ + +function onlyOwnRoutines( srcMap, o ) +{ + + _.assert( this === _.props ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( onlyOwnRoutines, o || null ); + + o.srcMap = srcMap; + o.onlyOwn = 1; + o.selectFilter = function selectRoutine( srcMap, k ) + { + debugger; + if( _.routine.is( srcMap[ k ] ) ) + return k; + debugger; + } + + debugger; + let result = _.props._ofAct( o ); + return result; +} + +onlyOwnRoutines.defaults = +{ + onlyEnumerable : 1, +} + +// + +/** + * The onlyExplicitRoutines() gets onlyExplicit properties of object {-srcMap-} that contains routines as value and returns them as new map. + * + * It takes an object {-srcMap-} creates an empty map, + * checks if {-srcMap-} is an object. + * If true, it copies onlyExplicit unique properties of source {-srcMap-} that holds routines to the new map using + * original name/value of the property and returns the result, otherwise it returns empty map. + * + * @param { objectLike } srcMap - Source to get a map of object`s properties. + * + * @example + * _.props.onlyExplicitRoutines( { a : 7, b : 13, f : function(){} } ); + * // returns { f : function, __defineGetter__ : function...} + * + * @example + * let a = { a : 1 }; + * let b = { b : 2, f : function(){} }; + * Object.setPrototypeOf( a, b ); + * _.props.onlyExplicitRoutines( a ) + * // returns { f : function, __defineGetter__ : function...} + * + * @returns { object } A new map with onlyExplicit unique object`s {-srcMap-} properties that are routines. + * @function onlyExplicitRoutines + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools + */ + +function onlyExplicitRoutines( srcMap, o ) +{ + + _.assert( this === _.props ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( onlyExplicitRoutines, o || null ); + + o.srcMap = srcMap; + o.onlyOwn = 0; + o.onlyEnumerable = 0; + o.selectFilter = function selectRoutine( srcMap, k ) + { + if( _.routine.is( srcMap[ k ] ) ) + return k; + } + + let result = _.props._ofAct( o ); + return result; +} + +onlyExplicitRoutines.defaults = +{ +} + +// + +/** + * The fields() gets onlyEnumerable fields( onlyExplicit properties except routines ) of the object {-srcMap-} and returns them as new map. + * + * It takes an object {-srcMap-} creates an empty map, + * checks if {-srcMap-} is an object. + * If true, it copies unique onlyEnumerable properties of the provided object {-srcMap-} that are not routines to the new map using + * their original name/value and returns the result, otherwise it returns empty map. + * + * @param { objectLike } srcMap - Object to get a map of onlyEnumerable properties. + * @param { objectLike } o - routine options can be provided through routine`s context. + * @param { boolean } [ o.onlyOwn = false ] - count only object`s onlyOwn properties. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * + * @example + * _.props.fields( { a : 7, b : 13, c : function(){} } ); + * // returns { a : 7, b : 13 } + * + * @example + * let a = { a : 1 }; + * let b = { b : 2, c : function(){} }; + * Object.setPrototypeOf( a, b ); + * _.props.fields( a ); + * // returns { a : 1, b : 2 } + * + * @example + * let a = { a : 1, x : function(){} }; + * let b = { b : 2 }; + * Object.setPrototypeOf( a, b ); + * _.props.fields.conlyExplicit( { onlyOwn : 1 }, a ) + * // returns { a : 1 } + * + * @returns { object } A new map with unique onlyEnumerable fields( onlyExplicit properties except routines ) from source {-srcMap-}. + * @function fields + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools + */ + +function fields( srcMap, o ) +{ + + _.assert( this === _.props ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( fields, o || null ); + + o.srcMap = srcMap; + o.selectFilter = function selectRoutine( srcMap, k ) + { + if( !_.routine.is( srcMap[ k ] ) ) + return k; + } + + let result = _.props._ofAct( o ); + return result; +} + +fields.defaults = +{ + onlyOwn : 0, + onlyEnumerable : 1, +} + +// + +/** + * The onlyOwnFields() gets object`s {-srcMap-} onlyOwn onlyEnumerable fields( onlyExplicit properties except routines ) and returns them as new map. + * + * It takes an object {-srcMap-} creates an empty map, + * checks if {-srcMap-} is an object. + * If true, it copies object`s onlyOwn onlyEnumerable properties that are not routines to the new map using + * their original name/value and returns the result, otherwise it returns empty map. + * + * @param { objectLike } srcMap - Object to get a map of onlyEnumerable properties. + * @param { objectLike } o - routine options can be provided through routine`s context. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * + * @example + * _.props.onlyOwnFields( { a : 7, b : 13, c : function(){} } ); + * // returns { a : 7, b : 13 } + * + * @example + * let a = { a : 1 }; + * let b = { b : 2, c : function(){} }; + * Object.setPrototypeOf( a, b ); + * _.props.onlyOwnFields( a ); + * // returns { a : 1 } + * + * @example + * let a = { a : 1, x : function(){} }; + * Object.defineProperty( a, 'b', { onlyEnumerable : 0, value : 2 } ) + * _.props.fields.conlyExplicit( { onlyEnumerable : 0 }, a ) + * // returns { a : 1, b : 2 } + * + * @returns { object } A new map with object`s {-srcMap-} onlyOwn onlyEnumerable fields( onlyExplicit properties except routines ). + * @function onlyOwnFields + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools + */ + +function onlyOwnFields( srcMap, o ) +{ + + _.assert( this === _.props ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( onlyOwnFields, o || null ); + + o.srcMap = srcMap; + o.onlyOwn = 1; + o.selectFilter = function selectRoutine( srcMap, k ) + { + if( !_.routine.is( srcMap[ k ] ) ) + return k; + } + + let result = _.props._ofAct( o ); + return result; +} + +onlyOwnFields.defaults = +{ + onlyEnumerable : 1, +} + +// + +/** + * The onlyExplicitFields() gets onlyExplicit object`s {-srcMap-} fields( properties except routines ) and returns them as new map. + * + * It takes an object {-srcMap-} creates an empty map, + * checks if {-srcMap-} is an object. + * If true, it copies onlyExplicit object`s properties that are not routines to the new map using + * their original name/value and returns the result, otherwise it returns empty map. + * + * @param { objectLike } srcMap - Object to get a map of onlyExplicit properties. + * + * @example + * _.props.onlyExplicitFields( { a : 7, b : 13, c : function(){} } ); + * // returns { a : 7, b : 13, __proto__ : Object } + * + * @example + * let a = { a : 1 }; + * let b = { b : 2, c : function(){} }; + * Object.setPrototypeOf( a, b ); + * _.props.onlyExplicitFields( a ); + * // returns { a : 1, b : 2, __proto__ : Object } + * + * @example + * let a = { a : 1, x : function(){} }; + * Object.defineProperty( a, 'b', { onlyEnumerable : 0, value : 2 } ) + * _.props.onlyExplicitFields( a ); + * // returns { a : 1, b : 2, __proto__ : Object } + * + * @returns { object } A new map with onlyExplicit fields( properties except routines ) from source {-srcMap-}. + * @function onlyExplicitFields + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools + */ + +function onlyExplicitFields( srcMap, o ) +{ + + _.assert( this === _.props ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( onlyExplicitFields, o || null ); + + o.srcMap = srcMap; + o.onlyOwn = 0; + o.onlyEnumerable = 0; + o.selectFilter = function selectRoutine( srcMap, k ) + { + if( !_.routine.is( srcMap[ k ] ) ) + return k; + } + + if( _.routine.is( srcMap ) ) + o.selectFilter = function selectRoutine( srcMap, k ) + { + if( _.longHas( [ 'arguments', 'conlyExpliciter' ], k ) ) + return; + if( !_.routine.is( srcMap[ k ] ) ) + return k; + } + + let result = _.props._ofAct( o ); + return result; +} + +onlyExplicitFields.defaults = +{ +} + +// + +function own( src, key ) +{ + // if( src === null ) + // return false; + // if( src === undefined ) + // return false; + if( _.primitive.is( src ) ) + return false; + return Object.hasOwnProperty.call( src, key ); +} + +// + +function has( src, key ) +{ + if( _.primitive.is( src ) ) + return false; + if( !Reflect.has( src, key ) ) + return false; + return true; +} + +// + +function ownEnumerable( src, key ) +{ + if( _.primitive.is( src ) ) + return false; + + let descriptor = Object.getOwnPropertyDescriptor( src, key ); + + if( !descriptor ) + return false; + + debugger; + + return !!descriptor.enumerable +} + +// + +function hasEnumerable( src, key ) +{ + if( _.primitive.is( src ) ) + return false; + + let found = _.props.descriptorOf( src, key ); + + debugger; + + if( !found.descriptor ) + return false; + + return !!found.descriptor.enumerable +} + +// + +function descriptorActiveOf( object, name ) +{ + let result = Object.create( null ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( !!object, 'No object' ); + + do + { + let descriptor = Object.getOwnPropertyDescriptor( object, name ); + if( descriptor && !( 'value' in descriptor ) ) + { + result.descriptor = descriptor; + result.object = object; + return result; + } + object = Object.getPrototypeOf( object ); + } + while( object ); + + return result; +} + +// + +function descriptorOf( object, name ) +{ + let result = Object.create( null ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + do + { + let descriptor = Object.getOwnPropertyDescriptor( object, name ); + if( descriptor ) + { + result.descriptor = descriptor; + result.object = object; + return result; + } + object = Object.getPrototypeOf( object ); + } + while( object ); + + return result; +} + +// + +function descriptorOwnOf( object, name ) +{ + return Object.getOwnPropertyDescriptor( object, name ); +} + +// -- +// meta +// -- + +/* qqq : optimize */ +function namespaceOf( src ) +{ + + if( _.map.is( src ) ) + return _.map; + if( _.aux.is( src ) ) + return _.aux; + if( _.object.is( src ) ) + return _.object; + if( _.props.is( src ) ) + return _.props; + + return null; +} + +// -- +// props extension +// -- + +let PropsExtension = +{ + + // + + NamespaceName : 'props', + NamespaceNames : [ 'props' ], + NamespaceQname : 'wTools/props', + MoreGeneralNamespaceName : 'props', + MostGeneralNamespaceName : 'props', + TypeName : 'Props', + TypeNames : [ 'Props', 'Properties' ], + // SecondTypeName : 'Properties', + InstanceConstructor : null, + tools : _, + + // dichotomy + + is, + like, + IsResizable, + + // maker + + _makeEmpty, + makeEmpty, /* qqq : for junior : cover */ + _makeUndefined, + makeUndefined, /* qqq : for junior : cover */ + _make, + make, /* qqq : for junior : cover */ + _cloneShallow, + cloneShallow, /* qqq : for junior : cover */ + from, + + // amender + + _extendWithHashmap, + _extendWithSet, + _extendWithCountable, + _extendWithProps, + _extendUniversal, + extendUniversal, + extend, + + _supplementWithHashmap, + _supplementWithSet, + _supplementWithCountable, + _supplementWithProps, + _supplementUniversal, + supplementUniversal, + supplement, + + // properties + + _keys, + keys, /* qqq : for junior : cover */ + onlyOwnKeys, /* qqq : for junior : cover */ + onlyEnumerableKeys, /* qqq : for junior : implement and cover properly */ + allKeys, /* qqq : for junior : cover */ + + _vals, + vals, /* qqq : for junior : cover */ + onlyOwnVals, /* qqq : for junior : cover */ + onlyEnumerableVals, /* qqq : for junior : implement and cover properly */ + allVals, /* qqq : for junior : cover */ + + _pairs, /* qqq : for junior : cover */ + pairs, /* qqq : for junior : cover */ + onlyOwnPairs, /* qqq : for junior : cover */ + onlyEnumerablePairs, /* qqq : for junior : implement and cover properly */ + allPairs, /* qqq : for junior : cover */ + + _ofAct, + of : _of, + onlyOwn, + onlyExplicit, + + routines, + onlyOwnRoutines, + onlyExplicitRoutines, + + fields, + onlyOwnFields, + onlyExplicitFields, + + own, /* qqq : cover please */ + has, /* qqq : cover please */ + ownEnumerable, /* qqq : cover please */ + hasEnumerable, /* qqq : cover please */ + + // propertyDescriptorActiveGet, + // propertyDescriptorGet, + descriptorActiveOf, /* qqq : cover please */ + descriptorOf, /* qqq : cover please */ + descriptorOwnOf, + + // meta + + namespaceOf, + namespaceWithDefaultOf : _.long.namespaceWithDefaultOf, + _functor_functor : _.long._functor_functor, + +} + +// + +Object.assign( _.props, PropsExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + // dichotomy + + propsIs : is.bind( _.props ), + propsLike : like.bind( _.props ), + + // maker + + propsMakeEmpty : makeEmpty.bind( _.props ), + propsMakeUndefined : makeUndefined.bind( _.props ), + propsMake : make.bind( _.props ), + propsCloneShallow : cloneShallow.bind( _.props ), + propsFrom : from.bind( _.props ), + + // amender + + propsExtend : extend.bind( _.props ), + propsSupplement : supplement.bind( _.props ), + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/2Props.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, _2Props_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file _2Props_s */ })(); + +/* */ /* begin of file _3Blank_s */ ( function _3Blank_s() { function _3Blank_s_naked() { ( function _l1_3Blank_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.blank = _.blank || Object.create( null ); + +// -- +// blank +// -- + +function is( src ) +{ + return true; +} + +// + +function like( src ) +{ + return this.is( src ); +} + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return false; +} + +// -- +// maker +// -- + +function _makeEmpty( src ) +{ + return src; +} + +// + +function makeEmpty( src ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 ); + return src; +} + +// + +function _makeUndefined( src ) +{ + return src; +} + +// + +function makeUndefined( src, length ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + return src; +} + +// + +function _make( src ) +{ + return src; +} + +// + +function make( src ) +{ + _.assert( this.like( src ) ); + _.assert( arguments.length === 1 ); + return this._make( src ); +} + +// + +function _cloneShallow( src ) +{ + return src; +} + +// -- +// meta +// -- + +/* qqq : optimize */ +function namespaceOf( src ) +{ + return this; +} + +// + +function namespaceWithDefaultOf( src ) +{ + return this; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + + // dichotomy + + blankIs : is.bind( _.blank ), + blankLike : like.bind( _.blank ), + +} + +Object.assign( _, ToolsExtension ); + +// + +let BlankExtension = +{ + + // + + NamespaceName : 'blank', + NamespaceNames : [ 'blank' ], + NamespaceQname : 'wTools/blank', + MoreGeneralNamespaceName : 'blank', + MostGeneralNamespaceName : 'blank', + TypeName : 'Blank', + TypeNames : [ 'Blank' ], + // SecondTypeName : 'Blank', + InstanceConstructor : null, + tools : _, + + // dichotomy + + is, + like, + IsResizable, + + // maker + + _makeEmpty, + makeEmpty, /* qqq : for junior : cover */ + _makeUndefined, + makeUndefined, /* qqq : for junior : cover */ + _make, + make, /* qqq : for junior : cover */ + _cloneShallow, + cloneShallow : _.props.cloneShallow, /* qqq : for junior : cover */ + from : _.props.from, /* qqq : for junior : cover */ + + // meta + + namespaceOf, + namespaceWithDefaultOf, + _functor_functor : _.props._functor_functor, + +} + +Object.assign( _.blank, BlankExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/3Blank.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, _3Blank_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file _3Blank_s */ })(); + +/* */ /* begin of file _5ArgumentsArray_s */ ( function _5ArgumentsArray_s() { function _5ArgumentsArray_s_naked() { ( function _l1_5ArgumentsArray_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.argumentsArray = _.argumentsArray || Object.create( null ); + +// -- +// dichotomy +// -- + +function is( src ) +{ + return Object.prototype.toString.call( src ) === '[object Arguments]'; +} + +// + +function isOld( src ) +{ + return Object.prototype.toString.call( src ) === '[object Arguments]'; +} + +// + +function isIterator( src ) +{ + if( !src || !src[ Symbol.iterator ] ) + return false; + return Object.prototype.toString.call( src ) === '[object Arguments]'; +} + +// + +/* qqq : for Rahul : bad : useless variant */ +// function isUsingFunctor_functor( src ) +// { +// let argumentObject = '[object Arguments]'; +// return isUsingFunctor; +// +// function isUsingFunctor( src ) +// { +// return Object.prototype.toString.call( src ) === argumentObject; +// } +// } +// +// let isUsingFunctor = isUsingFunctor_functor(); + +// + +function like( src ) +{ + if( Array.isArray( src ) ) + return true; + if( Object.prototype.toString.call( src ) === '[object Arguments]' ) + return true; + return false; +} + +// + +function likeOld( src ) +{ + if( _.array.is( src ) ) + return true; + if( _.argumentsArray.is( src ) ) + return true; + return false; +} + +// + +function likeUnfolded( src ) +{ + if( Array.isArray( src ) ) + return true; + if( Object.prototype.toString.call( src ) === '[object Arguments]' ) + return true; + return false; +} + +// + +/* qqq : for Rahul : bad : misleading name, this is not functor! */ +// function likeUsingIsFunctor( src ) +// { +// if( _.argumentsArray.isUsingFunctor( src ) ) +// return true; +// if( _.array.is( src ) ) +// return true; +// return false; +// } + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return false; +} + +// -- +// maker +// -- + +function _makeAct() +{ + return arguments; +} + +// + +function _make( src, length ) +{ + if( arguments.length === 2 ) + { + let data = length; + if( _.number.is( length ) ) + data = src; + if( _.countable.is( length ) ) + length = length.length; + + const dst = _.argumentsArray._makeAct.apply( _, _.number.is( length ) ? Array( length ) : [ ... length ] ); + return fill( dst, data ); + } + else if( arguments.length === 1 ) + { + if( _.numberIs( src ) ) + return _.argumentsArray._makeAct.apply( _, Array( src ) ); + if( _.countable.is( src ) ) + return _.argumentsArray._makeAct.apply( _, [ ... src ] ); + } + return _.argumentsArray._makeAct.apply( _, [] ); + + /* */ + + function fill( dst, data ) + { + if( data === null || data === undefined ) + return dst; + let l = Math.min( length, data.length ); + for( let i = 0 ; i < l ; i++ ) + dst[ i ] = data[ i ]; + return dst; + } + +} + +// + +function make( src, length ) +{ + // if( !( arguments.length === 0 || src === null || _.countable.is( src ) || _.numberIs( src ) ) ) + // debugger; + _.assert( arguments.length === 0 || src === null || _.countable.is( src ) || _.numberIs( src ) ); + _.assert( length === undefined || !_.number.is( src ) || !_.number.is( length ) ); + _.assert( arguments.length < 2 || _.number.is( length ) || _.countable.is( length ) ); + _.assert( arguments.length <= 2 ); + return this._make( ... arguments ); +} + +// + +function _makeEmpty() +{ + return this._make( 0 ); +} + +// + +function makeEmpty( src ) +{ + _.assert( arguments.length === 0 || src === null || this.like( src ) || _.countable.is( src ) ); + _.assert( arguments.length <= 1 ); + return this._makeEmpty( src ); +} + +// + +function _makeUndefined( src, length ) +{ + if( arguments.length === 0 ) + return this._make( 0 ); + + if( length === undefined ) + length = src; + if( length && !_.number.is( length ) ) + { + if( length.length ) + length = length.length; + else + length = [ ... length ].length; + } + return this._make( length ); +} + +// + +function makeUndefined( src, length ) +{ + _.assert( 0 <= arguments.length && arguments.length <= 2 ); + if( arguments.length === 2 ) + { + _.assert( src === null || _.long.is( src ) || _.routineIs( src ) ); + _.assert( _.numberIs( length ) || _.countable.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( src === null || _.numberIs( src ) || _.countable.is( src ) || _.routineIs( src ) ); + } + return this._makeUndefined( ... arguments ); +} + +// + +function _makeZeroed( src, length ) +{ + return this._makeFilling.call( this, 0, ... arguments ); +} + +// + +function makeZeroed( src, length ) +{ + _.assert( 0 <= arguments.length && arguments.length <= 2 ); + if( arguments.length === 2 ) + { + _.assert( src === null || _.long.is( src ) || _.routine.is( src ) ); + _.assert( _.number.is( length ) || _.countable.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( src === null || _.numberIs( src ) || _.long.is( src ) || _.countable.is( src ) || _.routine.is( src ) ); + } + return this._makeZeroed( ... arguments ); +} + +// + +function _makeFilling( type, value, length ) +{ + if( arguments.length === 2 ) + { + value = arguments[ 0 ]; + length = arguments[ 1 ]; + } + + if( !_.number.is( length ) ) + // if( _.long.is( length ) ) + if( length.length ) + length = length.length; + else if( _.countable.is( length ) ) + length = [ ... length ].length; + + let result = this._make( length ); + for( let i = 0 ; i < length ; i++ ) + result[ i ] = value; + + return result; +} + +// + +function makeFilling( type, value, length ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( arguments.length === 2 ) + { + _.assert( _.number.is( value ) || _.countable.is( value ) ); + _.assert( type !== undefined ); + } + else + { + _.assert( value !== undefined ); + _.assert( _.number.is( length ) || _.countable.is( length ) ); + _.assert( type === null || _.routine.is( type ) || _.long.is( type ) ); + } + + return this._makeFilling( ... arguments ); +} + +// + +function _cloneShallow( src ) +{ + return this._makeAct( ... src ); +} + +// + +function cloneShallow( src ) +{ + _.assert( this.is( src ) ); + _.assert( arguments.length === 1 ); + return this._cloneShallow( src ); +} + +// + +function from( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + if( this.is( src ) ) + return src; + return this.make( src ); +} + +// -- +// extension +// -- + +var ToolsExtension = +{ + + // dichotomy + + argumentsArrayIs : is.bind( _.argumentsArray ), + argumentsArrayLike : like.bind( _.argumentsArray ), + + // maker + + argumentsArrayMakeEmpty : makeEmpty.bind( _.argumentsArray ), + argumentsArrayMakeUndefined : makeUndefined.bind( _.argumentsArray ), + argumentsArrayMake : make.bind( _.argumentsArray ), + argumentsArrayCloneShallow : cloneShallow.bind( _.argumentsArray ), + argumentsArrayFrom : from.bind( _.argumentsArray ), + +} + +// + +Object.assign( _, ToolsExtension ); + +// + +var ArgumentsArrayExtension = +{ + + // + + NamespaceName : 'argumentsArray', + NamespaceNames : [ 'argumentsArray' ], + NamespaceQname : 'wTools/argumentsArray', + MoreGeneralNamespaceName : 'long', + MostGeneralNamespaceName : 'countable', + TypeName : 'ArgumentsArray', + TypeNames : [ 'ArgumentsArray', 'Arguments' ], + // SecondTypeName : 'Arguments', + InstanceConstructor : null, + tools : _, + + // dichotomy + + is, /* qqq : cover */ + isOld, + isIterator, + // isUsingFunctor, + like, /* qqq : cover */ + likeOld, + likeUnfolded, + // likeUsingIsFunctor, + IsResizable, + + // maker + + _makeAct, + _make, + make, /* qqq : for junior : cover */ + _makeEmpty, + makeEmpty, /* qqq : for junior : cover */ + _makeUndefined, + makeUndefined, /* qqq : for junior : cover */ + _makeZeroed, + makeZeroed, /* qqq : for junior : cover */ + _makeFilling, + makeFilling, + _cloneShallow, + cloneShallow, /* qqq : for junior : cover */ + from, /* qqq : for junior : cover */ + + // meta + + namespaceOf : _.blank.namespaceOf, + namespaceWithDefaultOf : _.blank.namespaceWithDefaultOf, + _functor_functor : _.blank._functor_functor, + +} + +Object.assign( _.argumentsArray, ArgumentsArrayExtension ); +_.long._namespaceRegister( _.argumentsArray ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/5ArgumentsArray.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, _5ArgumentsArray_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file _5ArgumentsArray_s */ })(); + +/* */ /* begin of file _5BufferTyped_s */ ( function _5BufferTyped_s() { function _5BufferTyped_s_naked() { ( function _l1_5BufferTyped_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.buffer = _.buffer || Object.create( null ); +_.bufferTyped = _.bufferTyped || Object.create( null ); +_.bufferTyped.namespaces = _.bufferTyped.namespaces || Object.create( null ); + +// -- +// implementation +// -- + +function is( src ) +{ + if( !( src instanceof Object.getPrototypeOf( Int8Array ) ) ) + return false; + if( _.buffer.nodeIs( src ) ) + return false; + return true; +} + +// + +function isSlow( src ) +{ + let type = Object.prototype.toString.call( src ); + if( !/\wArray/.test( type ) ) + return false; + if( type === '[object SharedArrayBuffer]' ) + return false; + if( _.buffer.nodeIs( src ) ) + return false; + return true; +} + +// + +// /*qqq: Same as is. Should We Keep it? +function isUsingGetPrototype( src ) +{ + if( !( src instanceof Object.getPrototypeOf( Int8Array ) ) ) + return false; + if( _.buffer.nodeIs( src ) ) + return false; + return true; +} + +// + +function isUsingGetPrototypeWithFunctor_functor() +{ + let TypedArray = Object.getPrototypeOf( Int8Array ); + return isUsingGetPrototypeWithFunctor; + function isUsingGetPrototypeWithFunctor( src ) + { + if( !( src instanceof TypedArray ) ) + return false; + if( _.buffer.nodeIs( src ) ) + return false; + return true; + } +} + +let isUsingGetPrototypeWithFunctor = isUsingGetPrototypeWithFunctor_functor(); + +// + +function isUsingExistenceOfField_functor() +{ + let TypedArray = Object.getPrototypeOf( Int8Array ); + return isUsingExistenceOfField; + function isUsingExistenceOfField( src ) + { + if( !src ) + return false; + if( !( src.buffer ) ) + return false; + if( !( src instanceof TypedArray ) ) + return false; + if( _.buffer.nodeIs( src ) ) + return false; + return true; + } +} + +let isUsingExistenceOfField = isUsingExistenceOfField_functor(); + +// + +function alternateSet_functor() +{ + let typedArraysSet = new Set(); + typedArraysSet.add( '[object BigUint64Array]' ); + typedArraysSet.add( '[object Uint32Array]' ); + typedArraysSet.add( '[object Uint16Array]' ); + typedArraysSet.add( '[object Uint8Array]' ); + typedArraysSet.add( '[object Uint8ClampedArray]' ); + typedArraysSet.add( '[object BigInt64Array]' ); + typedArraysSet.add( '[object Int32Array]' ); + typedArraysSet.add( '[object Int16Array]' ); + typedArraysSet.add( '[object Int8Array]' ); + typedArraysSet.add( '[object Float64Array]' ); + typedArraysSet.add( '[object Float32Array]' ); + return alternateSet; + + function alternateSet( src ) + { + if( !( typedArraysSet.has( Object.prototype.toString.call( src ) ) ) ) + return false; + if( _.buffer.nodeIs( src ) ) + return false; + return true; + } +} + +let isUsingSet = alternateSet_functor(); + +// + +function isUsingHashMap_functor() +{ + let typedArraysMap = new Map(); + typedArraysMap.set( '[object BigUint64Array]', '[object BigUint64Array]' ); + typedArraysMap.set( '[object Uint32Array]', '[object Uint32Array]' ); + typedArraysMap.set( '[object Uint16Array]', '[object Uint16Array]' ); + typedArraysMap.set( '[object Uint8Array]', '[object Uint8Array]' ); + typedArraysMap.set( '[object Uint8ClampedArray]', '[object Uint8ClampedArray]' ); + typedArraysMap.set( '[object BigInt64Array]', '[object BigInt64Array]' ); + typedArraysMap.set( '[object Int32Array]', '[object Int32Array]' ); + typedArraysMap.set( '[object Int16Array]', '[object Int16Array]' ); + typedArraysMap.set( '[object Int8Array]', '[object Int8Array]' ); + typedArraysMap.set( '[object Float64Array]', '[object Float64Array]' ); + typedArraysMap.set( '[object Float32Array]', '[object Float32Array]' ); + return isUsingHashMap; + + function isUsingHashMap( src ) + { + if( !( typedArraysMap.has( Object.prototype.toString.call( src ) ) ) ) + return false; + if( _.buffer.nodeIs( src ) ) + return false; + return true; + } +} + +let isUsingHashMap = isUsingHashMap_functor(); + +// + +function isUsingMap_functor() +{ + let typedArraysMap = Object.create( null ); + typedArraysMap[ '[object BigUint64Array]' ] = '[object BigUint64Array]'; + typedArraysMap[ '[object Uint32Array]' ] = '[object Uint32Array]'; + typedArraysMap[ '[object Uint16Array]' ] = '[object Uint16Array]'; + typedArraysMap[ '[object Uint8Array]' ] = '[object Uint8Array]'; + typedArraysMap[ '[object Uint8ClampedArray]' ] = '[object Uint8ClampedArray]'; + typedArraysMap[ '[object BigInt64Array]' ] = '[object BigInt64Array]'; + typedArraysMap[ '[object Int32Array]' ] = '[object Int32Array]'; + typedArraysMap[ '[object Int16Array]' ] = '[object Int16Array]'; + typedArraysMap[ '[object Int8Array]' ] = '[object Int8Array]'; + typedArraysMap[ '[object Float64Array]' ] = '[object Float64Array]'; + typedArraysMap[ '[object Float32Array]' ] = '[object Float32Array]'; + return isUsingMap; + + function isUsingMap( src ) + { + if( !typedArraysMap[ Object.prototype.toString.call( src ) ] ) + return false; + if( _.buffer.nodeIs( src ) ) + return false; + return true; + } +} + +let isUsingMap = isUsingMap_functor(); + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return false; +} + +// + +function _make( src, length ) +{ + if( arguments.length === 2 ) + { + let data = length; + if( _.number.is( length ) ) + { + data = src; + } + else if( length.length ) + // else if( _.long.is( length ) ) + { + length = length.length; + } + if( _.countable.is( length ) ) + { + data = [ ... length ]; + length = data.length; + } + + + if( this.like( src ) ) + return fill( new src.constructor( length ), data ); + return fill( this.tools.bufferTyped.default.make( length ), data ); + } + else if( arguments.length === 1 ) + { + if( this.like( src ) ) + return new src.constructor( src ); + return this.tools.bufferTyped.default.make( src ); + } + return this.tools.bufferTyped.default.make( 0 ); + + /* */ + + function fill( dst, data ) + { + if( data === null || data === undefined ) + return dst; + let l = Math.min( length, data.length ); + for( let i = 0 ; i < l ; i++ ) + dst[ i ] = data[ i ]; + return dst; + } +} + +// + +function _makeEmpty( src ) +{ + if( arguments.length === 1 ) + { + if( _.routine.is( src ) ) + { + let result = new src( 0 ); + _.assert( this.like( result ) ); + return result; + } + if( this.like( src ) ) + return new src.constructor(); + } + return this.tools.bufferTyped.default.make(); +} + +// + +function makeEmpty( src ) +{ + _.assert( arguments.length === 0 || this.like( src ) || _.countable.is( src ) || _.routine.is( src ) ); + _.assert( arguments.length <= 1 ); + // _.assert( arguments.length === 0 || arguments.length === 1 ); + // if( arguments.length === 1 ) + // _.assert( this.like( src ) || _.countable.is( src ) || _.routine.is( src ) ); + + return this._makeEmpty( ... arguments ); +} + +// + +function _makeUndefined( src, length ) +{ + if( arguments.length === 0 ) + return this.make( 0 ); + + if( length === undefined ) + length = src; + if( length && !_.number.is( length ) ) + { + if( length.length ) + length = length.length; + else + length = [ ... length ].length; + } + if( this.like( src ) ) + return new src.constructor( length ); + return this._make( length ); +} + +// + +function _makeFilling( type, value, length ) +{ + if( arguments.length === 2 ) + { + value = arguments[ 0 ]; + length = arguments[ 1 ]; + if( this.like( length ) ) + type = length; + else + type = null; + } + + if( !_.number.is( length ) ) + // if( _.long.is( length ) ) + if( length.length ) + length = length.length; + else if( _.countable.is( length ) ) + length = [ ... length ].length; + + let result = this._make( type, length ); + for( let i = 0 ; i < length ; i++ ) + result[ i ] = value; + + return result; +} + +// + +function _cloneShallow( src ) +{ + return src.slice( 0 ); + // if( _.buffer.rawIs( src ) ) + // return bufferRawCopy( src ); + // if( _.buffer.viewIs( src ) ) + // return new BufferView( bufferRawCopy( src ) ); + // if( _.buffer.typedIs( src ) ) + // return src.slice( 0 ); + // if( _.buffer.nodeIs( src ) ) + // return src.copy(); + // + // /* */ + // + // function bufferRawCopy( src ) + // { + // var dst = new BufferRaw( src.byteLength ); + // new U8x( dst ).set( new U8x( src ) ); + // return dst; + // } +} + +// -- +// meta +// -- + +function _namespaceRegister( namespace, defaultNamespaceName ) +{ + + namespace.NamespaceNames.forEach( ( name ) => + { + _.assert( _.bufferTyped.namespaces[ name ] === undefined ); + _.bufferTyped.namespaces[ name ] = namespace; + }); + + _.assert( namespace.IsTyped === undefined || namespace.IsTyped === true ); + namespace.IsTyped = true; + + return _.long._namespaceRegister( ... arguments ); +} + +// + +/* qqq : optimize */ +function namespaceOf( src ) +{ + + if( _.f32x.is( src ) ) + return _.f32x; + if( _.f64x.is( src ) ) + return _.f64x; + + if( _.i8x.is( src ) ) + return _.i8x; + if( _.i16x.is( src ) ) + return _.i16x; + if( _.i32x.is( src ) ) + return _.i32x; + + if( _.u8x.is( src ) ) + return _.u8x; + if( _.u8xClamped.is( src ) ) + return _.u8xClamped; + if( _.u16x.is( src ) ) + return _.u16x; + if( _.u32x.is( src ) ) + return _.u32x; + + return null; +} + +// -- +// declaration +// -- + +let BufferTypedExtension = +{ + + // + + NamespaceName : 'bufferTyped', + NamespaceNames : [ 'bufferTyped' ], + NamespaceQname : 'wTools/bufferTyped', + MoreGeneralNamespaceName : 'long', + MostGeneralNamespaceName : 'countable', + TypeName : 'BufferTyped', + TypeNames : [ 'BufferTyped' ], + // SecondTypeName : 'ArrayTyped', + InstanceConstructor : null, + tools : _, + + // dichotomy + + // typedIs : is, + is : is, + like : is, + IsResizable, + isSlow, /* xxx : remove later */ + isUsingGetPrototype, + isUsingGetPrototypeWithFunctor, + isUsingExistenceOfField, + isUsingSet, + isUsingHashMap, + isUsingMap, + + // maker + + _make, /* qqq : cover */ + make : _.long.make, + _makeEmpty, + makeEmpty, + _makeUndefined, /* qqq : implement */ + makeUndefined : _.argumentsArray.makeUndefined, + _makeZeroed : _makeUndefined, + makeZeroed : _.argumentsArray.makeZeroed, /* qqq : for junior : cover */ + _makeFilling, + makeFilling : _.argumentsArray.makeFilling, /* qqq : for junior : cover */ + _cloneShallow, + cloneShallow : _.argumentsArray.cloneShallow, /* qqq : for junior : cover */ + from : _.argumentsArray.from, /* qqq : for junior : cover */ + + // meta + + _namespaceRegister, + + namespaceOf, + namespaceWithDefaultOf : _.props.namespaceWithDefaultOf, + _functor_functor : _.props._functor_functor, + +} + +Object.assign( _.bufferTyped, BufferTypedExtension ); + +// + +let BufferExtension = +{ + + // dichotomy + + typedIs : is.bind( _.buffer ), + +} + +Object.assign( _.buffer, BufferExtension ); + +// + +let ToolsExtension = +{ + + // dichotomy + + bufferTypedIs : is.bind( _.buffer ), + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/5BufferTyped.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, _5BufferTyped_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file _5BufferTyped_s */ })(); + +/* */ /* begin of file Array_s */ ( function Array_s() { function Array_s_naked() { ( function _l1_Array_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.array = _.array || Object.create( null ); +_.countable = _.countable || Object.create( null ); +_.vector = _.vector || Object.create( null ); + +_.assert( !!_.argumentsArray.make, 'Expects routine _.argumentsArray.make' ); + +// -- +// array +// -- + +/** + * The is() routine determines whether the passed value is an Array. + * + * If the {-srcMap-} is an Array, true is returned, + * otherwise false is. + * + * @param { * } src - The object to be checked. + * + * @example + * _.array.is( [ 1, 2 ] ); + * // returns true + * + * @example + * _.array.is( 10 ); + * // returns false + * + * @returns { boolean } Returns true if {-srcMap-} is an Array. + * @function is + * @namespace Tools + */ + +function is( src ) +{ + return Array.isArray( src ); + // return Object.prototype.toString.call( src ) === '[object Array]'; +} + +// + +function isEmpty( src ) +{ + if( !_.array.is( src ) ) + return false; + return src.length === 0; +} + +// + +function isPopulated( src ) +{ + if( !_.array.is( src ) ) + return false; + return src.length > 0; +} + +// + +function likeResizable( src ) +{ + return _.array.is( src ); +} + +// + +function like( src ) /* qqq : cover */ +{ + return this.is( src ); +} + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return true; +} + +// -- +// maker +// -- + +function _make( src, length ) +{ + if( arguments.length === 2 ) + { + let data = length; + if( _.number.is( length ) ) + { + data = src; + } + else if( length.length ) + { + length = length.length; + } + if( _.countable.is( length ) ) + { + data = [ ... length ]; + length = data.length; + } + + return fill( new Array( length ), data ); + } + else if( arguments.length === 1 ) + { + if( _.number.is( src ) ) + return new Array( src ); + if( _.countable.is( src ) ) + return [ ... src ]; + } + return []; + + /* */ + + function fill( dst, data ) + { + if( data === null || data === undefined ) + return dst; + let l = Math.min( length, data.length ); + for( let i = 0 ; i < l ; i++ ) + dst[ i ] = data[ i ]; + return dst; + } + +} + +// + +function _cloneShallow( srcArray ) +{ + return srcArray.slice(); +} + +// + +/** + * The as() routine copies passed argument to the array. + * + * @param { * } src - The source value. + * + * @example + * _.array.as( false ); + * // returns [ false ] + * + * @example + * _.array.as( { a : 1, b : 2 } ); + * // returns [ { a : 1, b : 2 } ] + * + * @returns { Array } - If passed null or undefined than return the empty array. If passed an array then return it. + * Otherwise return an array which contains the element from argument. + * @function as + * @namespace Tools/array + */ + +function as( src ) +{ + _.assert( arguments.length === 1 ); + _.assert( src !== undefined ); + + //src === undefined check below conflicts with above assert + // if( src === null || src === undefined ) + if( src === null ) + return []; + else if( _.array.is( src ) ) + return src; + else if( _.countable.like( src ) ) + return [ ... src ]; + else + return [ src ]; + +} + +// // +// +// function asTest( src ) +// { +// _.assert( arguments.length === 1 ); +// _.assert( src !== undefined ); +// +// if( src === null ) +// return []; +// if( src[ Symbol.iterator ] && !_.str.is( src ) ) +// return [ ... src ]; +// +// return [ src ]; +// } + +// + +function asShallow( src ) +{ + _.assert( arguments.length === 1 ); + _.assert( src !== undefined ); + + if( src === null ) + return []; + else if( _.longLike( src ) ) + return _.array.slice( src ); + else + return [ src ]; + +} + +// -- +// array extension +// -- + +let ArrayExtension = +{ + + // fields + + NamespaceName : 'array', + NamespaceNames : [ 'array' ], + NamespaceQname : 'wTools/array', + MoreGeneralNamespaceName : 'long', + MostGeneralNamespaceName : 'countable', + TypeName : 'Array', + TypeNames : [ 'Array' ], + // SecondTypeName : 'Array', + InstanceConstructor : Array, + tools : _, + + // dichotomy + + is, + isEmpty, + isPopulated, + likeResizable, + like, + IsResizable, + + // maker + + _makeEmpty : _.argumentsArray._makeEmpty, + makeEmpty : _.argumentsArray.makeEmpty, /* qqq : for junior : cover */ + _makeUndefined : _.argumentsArray._makeUndefined, + makeUndefined : _.argumentsArray.makeUndefined, /* qqq : for junior : cover */ + _makeZeroed : _.argumentsArray._makeZeroed, + makeZeroed : _.argumentsArray.makeZeroed, /* qqq : for junior : cover */ + _makeFilling : _.argumentsArray._makeFilling, + makeFilling : _.argumentsArray.makeFilling, + _make, + make : _.argumentsArray.make, /* qqq : for junior : cover */ + _cloneShallow, + cloneShallow : _.argumentsArray.cloneShallow, /* qqq : for junior : cover */ + from : _.argumentsArray.from, /* qqq : for junior : cover */ + as, + // asTest, + asShallow, + + // meta + + namespaceOf : _.blank.namespaceOf, + namespaceWithDefaultOf : _.blank.namespaceWithDefaultOf, + _functor_functor : _.blank._functor_functor, + +} + +// + +Object.assign( _.array, ArrayExtension ); + +_.long._namespaceRegister( _.array ); +_.assert( _.long.default === undefined ); +_.long.default = _.array; + +_.assert( _.countable.default === undefined ); +_.countable.default = _.array; + +_.assert( _.vector.default === undefined ); +_.vector.default = _.array; + +// -- +// tools extension +// -- + +/* qqq : for junior : duplicate routines on all levels */ +let ToolsExtension = +{ + + // dichotomy + + arrayIs : is.bind( _.array ), + arrayIsEmpty : isEmpty.bind( _.array ), + arrayIsPopulated : isPopulated.bind( _.array ), + arrayLikeResizable : likeResizable.bind( _.array ), + arrayLike : like.bind( _.array ), + + // maker + + arrayMakeEmpty : _.argumentsArray.makeEmpty.bind( _.array ), + // arrayMakeEmpty : makeEmpty.bind( _.array ), + arrayMakeUndefined : _.argumentsArray.makeUndefined.bind( _.array ), + arrayMake : _.argumentsArray.make.bind( _.array ), + arrayCloneShallow : _.argumentsArray.cloneShallow.bind( _.array ), + arrayFrom : _.argumentsArray.from.bind( _.array ), + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Array.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Array_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Array_s */ })(); + +/* */ /* begin of file ArraySet_s */ ( function ArraySet_s() { function ArraySet_s_naked() { ( function _l1_ArraySet_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.arraySet = _.arraySet || Object.create( null ); + +// -- +// array set +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +// + +let Extension = +{ + +} + +Object.assign( _.arraySet, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/ArraySet.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ArraySet_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ArraySet_s */ })(); + +/* */ /* begin of file Auxiliary_s */ ( function Auxiliary_s() { function Auxiliary_s_naked() { ( function _l1_Auxiliary_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.aux = _.aux || Object.create( null ); + +_.assert( !!_.props.keys, 'Expects routine _.props.keys' ); +_.assert( !!_.props._extendWithHashmap, 'Expects routine _.props._extendWithHashmap' ); + +// -- +// dichotomy +// -- + +function is( src ) +{ + + if( !src ) + return false; + + let proto = Object.getPrototypeOf( src ); + + if( proto === null ) + return true; + + if( proto === Object.prototype ) + { + if( src[ Symbol.iterator ] ) + return Object.prototype.toString.call( src ) !== '[object Arguments]'; + return true; + } + + if( _.routineIs( proto[ Symbol.iterator ] ) ) + return false; + + if( !_.primitive.is( proto ) ) + if( !Reflect.has( proto, 'constructor' ) || proto.constructor === Object.prototype.constructor ) + return true; + + return false; +} + +// function is( src ) +// { +// +// if( !src ) +// return false; +// +// if( src[ Symbol.iterator ] ) +// return false; +// +// let proto = Object.getPrototypeOf( src ); +// +// if( proto === null ) +// return true; +// +// if( proto === Object.prototype ) +// return true; +// +// if( !_.primitive.is( proto ) ) +// if( !Reflect.has( proto, 'constructor' ) || proto.constructor === Object.prototype.constructor ) +// return true; +// +// return false; +// } + +// + +function like( src ) +{ + return _.aux.is( src ); +} +// + +function isPrototyped( src ) +{ + + if( !src ) + return false; + + let proto = Object.getPrototypeOf( src ); + + if( proto === null ) + return false; + + if( proto === Object.prototype ) + return false; + + if( _.routineIs( proto[ Symbol.iterator ] ) ) + return false; + + if( !_.primitive.is( proto ) ) + if( !Reflect.has( proto, 'constructor' ) || proto.constructor === Object.prototype.constructor ) + return true; + + return false; +} + +// + +function isPure( src ) +{ + + if( !src ) + return false; + + let proto = Object.getPrototypeOf( src ); + + if( proto === null ) + return true; + + if( proto.constructor === Object ) + return false; + + if( _.routineIs( proto[ Symbol.iterator ] ) ) + return false; + + if( !_.primitive.is( proto ) ) + if( !Reflect.has( proto, 'constructor' ) ) + return true; + + return false; +} + +// + +function isPolluted( src ) +{ + + if( !src ) + return false; + + let proto = Object.getPrototypeOf( src ); + + if( proto === null ) + return false; + + if( proto === Object.prototype ) + { + if( src[ Symbol.iterator ] ) + return Object.prototype.toString.call( src ) !== '[object Arguments]'; + return true; + } + + if( _.routineIs( proto[ Symbol.iterator ] ) ) + return false; + + if( proto.constructor === Object ) + return true; + + return false; +} + +// // +// +// function isPrototyped( src ) +// { +// +// if( !src ) +// return false; +// +// if( src[ Symbol.iterator ] ) +// return false; +// +// let proto = Object.getPrototypeOf( src ); +// +// if( proto === null ) +// return false; +// +// if( proto === Object.prototype ) +// return false; +// +// if( !_.primitive.is( proto ) ) +// if( !Reflect.has( proto, 'constructor' ) || proto.constructor === Object.prototype.constructor ) +// return true; +// +// return false; +// } +// +// // +// +// function isPure( src ) +// { +// +// if( !src ) +// return false; +// +// if( src[ Symbol.iterator ] ) +// return false; +// +// let proto = Object.getPrototypeOf( src ); +// +// if( proto === null ) +// return true; +// +// if( proto.constructor === Object ) +// return false; +// +// if( !_.primitive.is( proto ) ) +// if( !Reflect.has( proto, 'constructor' ) ) +// return true; +// +// return false; +// } +// +// // +// +// function isPolluted( src ) +// { +// +// if( !src ) +// return false; +// +// if( src[ Symbol.iterator ] ) +// return false; +// +// let proto = Object.getPrototypeOf( src ); +// +// if( proto === null ) +// return false; +// +// if( proto.constructor === Object ) +// return true; +// +// return false; +// } + +// + +function isEmpty( src ) +{ + if( !this.like( src ) ) + return false; + return this.keys( src ).length === 0; +} + +// + +function isPopulated( src ) +{ + if( !this.like( src ) ) + return false; + return this.keys( src ).length > 0; +} + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return true; +} + +// -- +// maker +// -- + +function _makeEmpty( src ) +{ + let result = Object.create( null ); + let src2 = _.prototype.of( src ); + while( src2 && src2 !== Object.prototype ) + { + result = Object.create( result ); + src2 = _.prototype.of( src2 ); + } + return result; +} + +// + +function makeEmpty( src ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 ); + if( arguments.length === 1 ) + _.assert( this.like( src ) ); + return this._makeEmpty( src ); +} + +// + +function _makeUndefined( src, length ) +{ + let result = Object.create( null ); + return result; +} + +// + +function makeUndefined( src, length ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + + if( arguments.length === 2 ) + { + _.assert( this.like( src ) ); + _.assert( _.number.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( _.number.is( src ) || this.like( src ) ); + } + + return this._makeUndefined( src ); +} + +// + +function _make( src ) +{ + if( src ) + { + if( this.like( src ) ) + return this._cloneShallow( src ); + else + return this.extendUniversal( Object.create( null ), src ); + } + return Object.create( null ); +} + +// + +function make( src, length ) +{ + _.assert( arguments.length === 0 || src === null || !_.primitive.is( src ) ); + _.assert( length === undefined || length === 0 ); + _.assert( arguments.length <= 2 ); + return this._make( ... arguments ); +} + +// + +function _cloneShallow( src ) +{ + let dst = Object.create( null ); + let prototypes = _.prototype.each( src ); + let c = 1; + + for( let i = 1, l = prototypes.length ; i < l ; i++ ) + { + let prototype = prototypes[ i ]; + if( prototype && prototype !== Object.prototype ) + { + dst = Object.create( dst ); + c += 1; + } + } + + let result = dst; + + while( c > 0 ) + { + copy( dst, src ); + dst = _.prototype.of( dst ); + src = _.prototype.of( src ); + c -= 1; + } + + return result; + + function copy( dst, src ) + { + let keys = _.props.onlyOwnKeys( src ); + for( let k = 0 ; k < keys.length ; k++ ) + dst[ keys[ k ] ] = src[ keys[ k ] ]; + } + +} + +// -- +// meta +// -- + +/* qqq : optimize */ +function namespaceOf( src ) +{ + + if( _.map.is( src ) ) + return _.map; + if( _.aux.is( src ) ) + return _.aux; + + return null; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + + // dichotomy + + auxIs : is.bind( _.aux ), + auxIsPure : isPure.bind( _.aux ), + auxIsPolluted : isPolluted.bind( _.aux ), + auxIsEmpty : isEmpty.bind( _.aux ), + auxIsPopulated : isPopulated.bind( _.aux ), + auxLike : like.bind( _.aux ), + + // maker + + auxMakeEmpty : makeEmpty.bind( _.aux ), + auxMakeUndefined : makeUndefined.bind( _.aux ), + auxMake : make.bind( _.aux ), + auxCloneShallow : _.props.cloneShallow.bind( _.aux ), + auxFrom : _.props.from.bind( _.aux ), + + // amender + + auxExtend : _.props.extend.bind( _.aux ), + auxSupplement : _.props.supplement.bind( _.aux ), + +} + +Object.assign( _, ToolsExtension ); + +// + +var AuxiliaryExtension = +{ + + // + + NamespaceName : 'aux', + NamespaceNames : [ 'aux' ], + NamespaceQname : 'wTools/aux', + MoreGeneralNamespaceName : 'props', + MostGeneralNamespaceName : 'props', + TypeName : 'Aux', + TypeNames : [ 'Aux', 'Auxiliary' ], + InstanceConstructor : null, + tools : _, + + // dichotomy + + is, + like, + isPrototyped, + isPure, + isPolluted, + + isEmpty, /* qqq : cover */ + isPopulated, /* qqq : cover */ + IsResizable, + + // maker + + _makeEmpty, + makeEmpty, /* qqq : for junior : cover */ + _makeUndefined, + makeUndefined, /* qqq : for junior : cover */ + _make, + make, /* qqq : for junior : cover */ + _cloneShallow, + cloneShallow : _.props.cloneShallow, /* qqq : for junior : cover */ + from : _.props.from, /* qqq : for junior : cover */ + + // properties + + _keys : _.props._keys, + keys : _.props.keys, /* qqq : for junior : cover */ + onlyOwnKeys : _.props.onlyOwnKeys, /* qqq : for junior : cover */ + onlyEnumerableKeys : _.props.onlyEnumerableKeys, /* qqq : for junior : implement and cover properly */ + allKeys : _.props.allKeys, /* qqq : for junior : cover */ + + _vals : _.props._vals, + vals : _.props.vals, /* qqq : for junior : cover */ + onlyOwnVals : _.props.onlyOwnVals, /* qqq : for junior : cover */ + onlyEnumerableVals : _.props.onlyEnumerableVals, /* qqq : for junior : implement and cover properly */ + allVals : _.props.allVals, /* qqq : for junior : cover */ + + _pairs : _.props._pairs, + pairs : _.props.pairs, /* qqq : for junior : cover */ + onlyOwnPairs : _.props.onlyOwnPairs, /* qqq : for junior : cover */ + onlyEnumerablePairs : _.props.onlyEnumerablePairs, /* qqq : for junior : implement and cover properly */ + allPairs : _.props.allPairs, /* qqq : for junior : cover */ + + // amender + + _extendWithHashmap : _.props._extendWithHashmap, + _extendWithSet : _.props._extendWithSet, + _extendWithCountable : _.props._extendWithCountable, + _extendWithProps : _.props._extendWithProps, + _extendUniversal : _.props._extendUniversal, + extendUniversal : _.props.extendUniversal, + extend : _.props.extend, + + _supplementWithHashmap : _.props._supplementWithHashmap, + _supplementWithSet : _.props._supplementWithSet, + _supplementWithCountable : _.props._supplementWithCountable, + _supplementWithProps : _.props._supplementWithProps, + _supplementUniversal : _.props._supplementUniversal, + supplementUniversal : _.props.supplementUniversal, + supplement : _.props.supplement, + + // meta + + namespaceOf, + namespaceWithDefaultOf : _.props.namespaceWithDefaultOf, + _functor_functor : _.props._functor_functor, + +} + +Object.assign( _.aux, AuxiliaryExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Auxiliary.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Auxiliary_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Auxiliary_s */ })(); + +/* */ /* begin of file BigInt_s */ ( function BigInt_s() { function BigInt_s_naked() { ( function _l1_BigInt_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.bigInt = _.bigInt || Object.create( null ); +_.bigInts = _.bigInt.s = _.bigInts || _.bigInt.s || Object.create( null ); + +// -- +// implementation +// -- + +function is( src ) +{ + let result = Object.prototype.toString.call( src ) === '[object BigInt]'; + return result; +} + +// + +function exportStringCodeShallow( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + _.assert( _.bigInt.is( src ) ); + + return `${String( src )}n`; +} + +// -- +// big int extension +// -- + +let BigIntExtension = +{ + + // + + is, + + // exporter + + exportString : exportStringCodeShallow, + exportStringCodeShallow, + exportStringDiagnosticShallow : exportStringCodeShallow, + +} + +Object.assign( _.bigInt, BigIntExtension ); + +// -- +// extension +// -- + +let ToolsExtension = +{ + + bigIntIs : is, + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/BigInt.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, BigInt_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file BigInt_s */ })(); + +/* */ /* begin of file Bool_s */ ( function Bool_s() { function Bool_s_naked() { ( function _l1_Bool_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.bool = _.bool || Object.create( null ); +_.bools = _.bool.s = _.bools || _.bool.s || Object.create( null ); + +// -- +// bool +// -- + +/** + * Returns true if entity ( src ) is a Boolean values - true and false. + * @function is + * @param { * } src - An entity to check. + * @namespace Tools + * + * @example + * var got = _.bool.is( '' ); + * console.log( got ) + * // log false + * + * @example + * var got = _.bool.is( 1 ); + * console.log( got ) + * // log false + * + * @example + * var got = _.bool.is( true ); + * console.log( got ) + * // log true + * + * @example + * var got = _.bool.is( false ); + * console.log( got ) + * // log true + * + */ + +function is( src ) +{ + return src === true || src === false; +} + +// + +/** + * Routine like() returns true if entity ( src ) is a Boolean values - true and false or Numbers 1 and 0. + * @function like + * @param { * } src - An entity to check. + * @namespace Tools + * + * @example + * var got = _.bool.like( false ); + * console.log( got ) + * // log true + * + * @example + * var got = _.bool.like( true ); + * console.log( got ) + * // log true + * + * @example + * var got = _.bool.like( 1 ); + * console.log( got ) + * // log true + * + * @example + * var got = _.bool.like( 0 ); + * console.log( got ) + * // log true + * + * @example + * var got = _.bool.like( '0' ); + * console.log( got ) + * // log false + * + */ + +function like( src ) +{ + return src === true || src === false || src === 0 || src === 1; + // let type = Object.prototype.toString.call( src ); + // return type === '[object Boolean]' || src === 0 || src === 1; +} + +// + +/** + * Returns true if entity ( src ) is Boolean value - false or Number - 0. + * @function likeFalse + * @param { * } src - An entity to check. + * @namespace Tools + * + * @example + * var got = _.bool.likeFalse( 0 ); + * console.log( got ) + * // log true + * + * @example + * var got = _.bool.likeFalse( 1 ); + * console.log( got ) + * // log false + * + * @example + * var got = _.bool.likeFalse( false ); + * console.log( got ) + * // log true + * + * @example + * var got = _.bool.likeFalse( true ); + * console.log( got ) + * // log false + * + */ + +function likeFalse( src ) +{ + if( !_.bool.like( src ) ) + return false; + return !src; +} + +// + +/** + * Returns true if entity ( src ) is Boolean value - true or Number - 1. + * @function likeTrue + * @param { * } src - An entity to check. + * @namespace Tools + * + * @example + * var got = _.bool.likeTrue( 0 ); + * console.log( got ) + * // log false + * + * @example + * var got = _.bool.likeTrue( 1 ); + * console.log( got ) + * // log true + * + * @example + * var got = _.bool.likeTrue( false ); + * console.log( got ) + * // log false + * + * @example + * var got = _.bool.likeTrue( true ); + * console.log( got ) + * // log true + * + */ + +function likeTrue( src ) +{ + if( !_.bool.like( src ) ) + return false; + return !!src; +} + +// -- +// bool extension +// -- + +let BoolExtension = +{ + + is, + like, + likeFalse, + likeTrue, + +} + +Object.assign( _.bool, BoolExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + boolIs : is, + boolLike : like, + boolLikeFalse : likeFalse, + boolLikeTrue : likeTrue, + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Bool.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Bool_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Bool_s */ })(); + +/* */ /* begin of file Buffer_s */ ( function Buffer_s() { function Buffer_s_naked() { ( function _l1_Buffer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.buffer = _.buffer || Object.create( null ); + +// -- +// implementation +// -- + +function anyIs( src ) +{ + if( src instanceof ArrayBuffer ) + return true; + if( _global.BufferRawShared && src instanceof SharedArrayBuffer ) + return true; + if( ArrayBuffer.isView( src ) ) + return true; + return false; +} + +// // +// +// function anyIsOld( src ) +// { +// if( !src ) +// return false; +// if( typeof src !== 'object' ) +// return false; +// //{ byteLength: 6 } will pass the below check +// if( !Reflect.has( src, 'byteLength' ) ) +// return false; +// // return src.byteLength >= 0; +// // return typedIs( src ) || viewIs( src ) || rawIs( src ) || nodeIs( src ); +// return true; +// } +// +// // +// +// function anyIsUsingInstanceOf( src ) +// { +// if( src instanceof ArrayBuffer ) +// return true; +// if( src instanceof SharedArrayBuffer ) +// return true; +// if( ArrayBuffer.isView( src ) ) +// return true; +// return false; +// } + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return false; +} + +// -- +// maker +// -- + +function _make_functor( onMake ) +{ + + return function _bufferMake( src, ins ) + { + let result; + + /* */ + + let length = ins; + + // if( _.longIs( length ) || _.bufferNodeIs( length ) ) + if( _.countable.is( length ) || _.bufferNodeIs( length ) ) + { + if( length.length ) + { + length = length.length; + } + else + { + ins = [ ... length ]; + length = ins.length; + } + } + else if( _.bufferRawIs( length ) || _.bufferViewIs( length ) ) + { + length = length.byteLength; + ins = _.bufferViewIs( ins ) ? new U8x( ins.buffer ) : new U8x( ins ); + } + else if( length === undefined || length === null ) + { + if( src === null ) /* Dmytro : Does module has default buffer type? */ + { + length = 0; + } + else if( _.longIs( src ) || _.bufferNodeIs( src ) ) + { + length = src.length; + ins = src; + // src = null; + } + else if( _.bufferRawIs( src ) ) + { + length = src.byteLength; + ins = new U8x( src ); + // src = null; + } + else if( _.bufferViewIs( src ) ) + { + length = src.byteLength; + ins = new U8x( src.buffer ); + // src = null; + } + else if( _.number.is( src ) ) + { + length = src; + src = null; + } + else if( _.routine.is( src ) ) + { + _.assert( 0, 'Unknown length of buffer' ); + } + else if( arguments.length === 0 ) + { + length = 0; + src = null; + } + else _.assert( 0 ); + } + else if( !_.number.is( length ) ) + { + _.assert( 0, 'Unknown length of buffer' ); + } + + if( !length ) + length = 0; + + /* */ + + if( _.number.is( ins ) ) + { + if( _.bufferRawIs( src ) ) + ins = new U8x( src ); + else if( _.bufferViewIs( src ) ) + ins = new U8x( src.buffer ) + else if( _.longIs( src ) || _.bufferNodeIs( src ) ) + ins = src; + else + ins = null; + } + + /* */ + + let minLength; + if( ins ) + minLength = Math.min( ins.length, length ); + else + minLength = 0; + + /* */ + + if( _.argumentsArray.is( src ) ) + src = _.routine.join( this.tools.bufferTyped.default, this.tools.bufferTyped.default.make ); + // src = _.routine.join( this.tools.long.default, this.tools.long.default.make ); + + if( src === null ) + src = _.routine.join( this.tools.bufferTyped.default, this.tools.bufferTyped.default.make ); + // src = _.routine.join( this.tools.long.default, this.tools.long.default.make ); + + _.assert( 0 <= arguments.length && arguments.length <= 2 ); + // _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.number.isFinite( length ) ); + _.assert( _.routine.is( src ) || _.longIs( src ) || _.bufferAnyIs( src ), 'unknown type of array', _.entity.strType( src ) ); + + result = onMake.call( this, src, ins, length, minLength ); + + _.assert( _.bufferAnyIs( result ) || _.longLike( result ) ); + + return result; + } +} + +// + +/** + * The routine make() returns a new buffer with the same type as source buffer {-src-}. New buffer fills by content of insertion buffer {-ins-}. If {-ins-} is + * a number, the buffer fills by {-src-} content. The length of resulted buffer is equal to {-ins-}. If {-ins-} is not defined, then routine makes default Long type, + * length of returned container defines from {-src-}. + * + * @param { BufferAny|Long|Function|Number|Null } src - Instance of any buffer, Long or constructor, defines type of returned buffer. If {-src-} is null, + * then routine returns instance of default Long. + * @param { Number|Long|Buffer|Null|Undefined } ins - Defines length and content of new buffer. If {-ins-} is null or undefined, then routine makes new container + * with default Long type and fills it by {-src-} content. + * + * Note. Default Long type defines by descriptor {-longDescriptor-}. If descriptor not provided directly, then it is Array descriptor. + * + * @example + * let got = _.make(); + * // returns [] + * + * @example + * let got = _.make( null ); + * // returns [] + * + * @example + * let got = _.make( null, null ); + * // returns [] + * + * @example + * let got = _.make( 3 ); + * // returns [ undefined, undefined, undefined ] + * + * @example + * let got = _.make( 3, null ); + * // returns [ undefined, undefined, undefined ] + * + * @example + * let got = _.make( new U8x( [ 1, 2, 3 ] ) ); + * // returns [ 1, 2, 3 ]; + * _.bufferTypedIs( got ); + * // log false + * + * @example + * let got = _.make( new I16x( [ 1, 2, 3 ] ), null ); + * // returns [ 1, 2, 3 ]; + * _.bufferTypedIs( got ); + * // log false + * + * @example + * _.make( new BufferRaw( 4 ), 6 ); + * // returns ArrayBuffer { [Uint8Contents]: <00 00 00 00 00 00>, byteLength: 6 } + * + * @example + * _.make( new BufferRaw( 4 ), [ 1, 2, 3 ] ); + * // returns ArrayBuffer { [Uint8Contents]: <01 02 03>, byteLength: 3 } + * + * @example + * _.make( F64x, [ 1, 2, 3 ] ); + * // returns Float64Array [ 1, 2, 3 ] + * + * @returns { BufferAny|Long } Returns a buffer with source buffer {-src-} type filled by insertion container {-ins-} content. + * If {-ins-} is not defined, then routine makes default Long type container and fills it by {-src-} content. + * @function make + * @throws { Error } If arguments.length is more than two. + * @throws { Error } If {-src-} is not a Long, not a buffer, not a Number, not a constructor, not null. + * @throws { Error } If {-src-} is constructor and second argument {-src-} is not provided. + * @throws { Error } If {-src-} is constructor that returns not a Long, not a buffer value. + * @throws { Error } If {-ins-} is not a number, not a Long, not a buffer, not null, not undefined. + * @throws { Error } If {-ins-} or src.length has a not finite value. + * @namespace Tools + */ + +function _make( src, length ) +{ + if( length === undefined ) + length = src; + let data = length; + + if( _.number.is( length ) ) + { + data = src; + } + else if( length ) + { + if( _.number.is( length.length ) ) + { + length = length.length; + } + else if( _.number.is( length.byteLength ) ) + { + length = length.byteLength; + } + else + { + data = [ ... length ]; + length = data.length; + } + } + + if( arguments.length === 2 ) + { + if( src === null ) + return fill( this.tools.bufferTyped.make( length ), data ); + if( _.buffer.rawIs( src ) ) + return fill( new BufferRaw( length ), data ); + if( _.buffer.viewIs( src ) ) + return new BufferView( fill( new BufferRaw( length ), data ) ); + if( _.buffer.typedIs( src ) ) + return fill( new src.constructor( length ), data ); + if( _.buffer.nodeIs( src ) ) + return fill( BufferNode.alloc( length ), data ); + if( _.long.is( src ) ) + return fill( this.tools.bufferTyped.make( length ), data ); + + let result; + if( _.routineIs( src ) ) + result = fill( new src( length ), data ) + _.assert( _.buffer.is( result ), 'Not clear how to make such buffer' ); + return result; + } + else if( arguments.length === 1 ) + { + if( src === null || _.number.is( src ) ) + return this.tools.bufferTyped.make( src ); + if( _.buffer.rawIs( src ) ) + return fill( new BufferRaw( length ), data ); + if( _.buffer.viewIs( src ) ) + return new BufferView( fill( new BufferRaw( length ), data ) ); + if( _.buffer.typedIs( src ) ) + return fill( new src.constructor( src ) ); + if( _.buffer.nodeIs( src ) ) + return fill( BufferNode.from( src ) ); + if( _.countable.is( src ) ) + return this.tools.bufferTyped.make( src ); + } + + return this.tools.bufferTyped.make(); + + /* */ + + function fill( dst, data ) + { + if( data === null || data === undefined ) + return dst; + + let dstTyped = dst; + if( _.bufferRawIs( dst ) ) + dstTyped = new U8x( dst ); + if( _.bufferViewIs( dst ) ) + dstTyped = new U8x( dst.buffer ); + + let dataTyped = data; + if( _.bufferRawIs( data ) ) + dataTyped = new U8x( data ); + if( _.bufferViewIs( data ) ) + dataTyped = new U8x( data.buffer ); + + let l = Math.min( length, dataTyped.length ); + for( let i = 0 ; i < l ; i++ ) + dstTyped[ i ] = dataTyped[ i ]; + + return dst; + } +} + +// + +function make( src, length ) +{ + _.assert( arguments.length <= 2 ); + if( arguments.length === 2 ) + { + _.assert( src === null || this.is( src ) || _.long.is( src ) || _.routineIs( src ) ); + _.assert( _.number.is( length ) || this.is( length ) || _.countable.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( src === null || _.number.is( src ) || this.is( src ) || _.long.is( src ) || _.routineIs( src ) ); + } + return this._make( ... arguments ); +} + +// let make = _make_functor( function( /* src, ins, length, minLength */ ) +// { +// let src = arguments[ 0 ]; +// let ins = arguments[ 1 ]; +// let length = arguments[ 2 ]; +// let minLength = arguments[ 3 ]; +// +// /* */ +// +// let resultTyped; +// /* qqq : for Dmytro : bad solution! */ +// if( _.routine.is( src ) ) +// { +// if( src.name === 'make' || src.name === 'bound make' ) +// resultTyped = src( length ); +// else +// resultTyped = new src( length ); +// } +// else if( _.bufferNodeIs( src ) ) +// resultTyped = BufferNode.alloc( length ); +// else if( _.bufferViewIs( src ) ) +// resultTyped = new BufferView( new BufferRaw( length ) ); +// else if( _.unrollIs( src ) ) +// resultTyped = _.unroll.make( length ); +// else +// resultTyped = new src.constructor( length ); +// +// let result = resultTyped; +// if( _.bufferRawIs( result ) ) +// resultTyped = new U8x( result ); +// if( _.bufferViewIs( result ) ) +// resultTyped = new U8x( result.buffer ); +// +// for( let i = 0 ; i < minLength ; i++ ) +// resultTyped[ i ] = ins[ i ]; +// +// return result; +// }); + +// + +function _makeEmpty( src ) +{ + if( arguments.length === 1 ) + { + if( _.routineIs( src ) ) + { + let result = new src( 0 ); + _.assert( this.like( result ) ); + return result; + } + if( this.like( src ) ) + { + if( _.buffer.viewIs( src ) ) + return new src.constructor( new BufferRaw() ); + else if( _.buffer.nodeIs( src ) ) + return BufferNode.alloc( 0 ); + else + return new src.constructor(); + } + } + return this.tools.bufferTyped.default.make(); +} + +// + +function makeEmpty( src ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 ); + if( arguments.length === 1 ) + _.assert( this.like( src ) || _.countable.is( src ) || _.routineIs( src ) ); + + return this._makeEmpty( ... arguments ); +} + +// + +/** + * The routine makeUndefined() returns a new buffer with the same type as source buffer {-src-}. The length of resulted buffer is equal to {-ins-}. + * If {-ins-} is not defined, then routine makes default Long type, length of returned container defines from {-src-}. + * + * @param { BufferAny|Long|Function|Number|Null } src - Instance of any buffer, Long or constructor, defines type of returned buffer. If {-src-} is null, + * then routine returns instance of default Long. + * @param { Number|Long|Buffer|Null|Undefined } ins - Defines length of new buffer. If {-ins-} is null or undefined, then routine makes new container + * with default Long type and length defined by {-src-}. + * + * Note. Default Long type defines by descriptor {-longDescriptor-}. If descriptor not provided directly, then it is Array descriptor. + * + * @example + * let got = _.makeUndefined(); + * // returns [] + * + * @example + * let got = _.makeUndefined( null ); + * // returns [] + * + * @example + * let got = _.makeUndefined( null, null ); + * // returns [] + * + * @example + * let got = _.makeUndefined( 3 ); + * // returns [ undefined, undefined, undefined ] + * + * @example + * let got = _.makeUndefined( 3, null ); + * // returns [ undefined, undefined, undefined ] + * + * @example + * let got = _.makeUndefined( new U8x( [ 1, 2, 3 ] ) ); + * // returns [ undefined, undefined, undefined ]; + * _.bufferTypedIs( got ); + * // log false + * + * @example + * let got = _.makeUndefined( new I16x( [ 1, 2, 3 ] ), null ); + * // returns [ undefined, undefined, undefined ]; + * _.bufferTypedIs( got ); + * // log false + * + * @example + * _.makeUndefined( new BufferRaw( 4 ), 6 ); + * // returns ArrayBuffer { [Uint8Contents]: <00 00 00 00 00 00>, byteLength: 6 } + * + * @example + * _.makeUndefined( new BufferRaw( 4 ), [ 1, 2, 3 ] ); + * // returns ArrayBuffer { [Uint8Contents]: <00 00 00>, byteLength: 3 } + * + * @example + * _.makeUndefined( F64x, [ 1, 2, 3 ] ); + * // returns Float64Array [ 0, 0, 0 ] + * + * @returns { BufferAny|Long } Returns a buffer with source buffer {-src-} type filled by insertion container {-ins-} content. + * If {-ins-} is not defined, then routine makes default Long type container and fills it by {-src-} content. + * @function makeUndefined + * @throws { Error } If arguments.length is more than two. + * @throws { Error } If {-src-} is not a Long, not a buffer, not a Number, not a constructor, not null. + * @throws { Error } If {-src-} is constructor and second argument {-src-} is not provided. + * @throws { Error } If {-src-} is constructor that returns not a Long, not a buffer value. + * @throws { Error } If {-ins-} is not a number, not a Long, not a buffer, not null, not undefined. + * @throws { Error } If {-ins-} or src.length has a not finite value. + * @namespace Tools + */ + +function _makeUndefined( src, length ) +{ + if( length === undefined ) + length = src; + + if( length && !_.number.is( length ) ) + { + if( _.number.is( length.length ) ) + length = length.length; + else if( _.number.is( length.byteLength ) ) + length = length.byteLength; + else + length = [ ... length ].length; + } + + if( src === null || _.number.is( src ) ) + return this.tools.bufferTyped.make( length ); + if( _.buffer.rawIs( src ) ) + return new BufferRaw( length ); + if( _.buffer.viewIs( src ) ) + return new BufferView( new BufferRaw( length ) ); + if( _.buffer.typedIs( src ) ) + return new src.constructor( length ); + if( _.buffer.nodeIs( src ) ) + return BufferNode.alloc( length ); + if( _.countable.is( src ) ) + return this.tools.bufferTyped.make( length ); + + if( _.routineIs( src ) ) + { + _.assert( arguments.length === 2 ); + let result = new src( length ); + _.assert( _.buffer.is( result ), 'Not clear how to make such buffer' ); + return result; + } + + return this.tools.bufferTyped.make(); +} + +// + +function makeUndefined( src, length ) +{ + _.assert( 0 <= arguments.length && arguments.length <= 2 ); + if( arguments.length === 2 ) + { + _.assert( src === null || this.like( src ) || _.long.is( src ) || _.routineIs( src ) ); + _.assert( _.number.is( length ) || this.like( length ) || _.countable.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( src === null || _.number.is( src ) || this.like( src ) || _.long.is( src ) || _.routineIs( src ) ); + } + return this._makeUndefined( ... arguments ); +} + +// let makeUndefined = _make_functor( function( /* src, ins, length, minLength */ ) +// { +// let src = arguments[ 0 ]; +// let ins = arguments[ 1 ]; +// let length = arguments[ 2 ]; +// let minLength = arguments[ 3 ]; +// +// /* */ +// +// let result; +// /* qqq : for Dmytro : bad solution! */ +// if( _.routine.is( src ) ) +// { +// if( src.name === 'make' || src.name === 'bound make' ) +// result = src( length ); +// else +// result = new src( length ); +// } +// else if( _.bufferNodeIs( src ) ) +// result = BufferNode.alloc( length ); +// else if( _.bufferViewIs( src ) ) +// result = new BufferView( new BufferRaw( length ) ); +// else if( _.unrollIs( src ) ) +// result = _.unroll.make( length ); +// else +// result = new src.constructor( length ); +// +// return result; +// }); + +// + +function _makeFilling( type, value, length ) +{ + if( arguments.length === 2 ) + { + type = null; + value = arguments[ 0 ]; + length = arguments[ 1 ]; + } + + if( !_.number.is( length ) ) + if( length.length ) + length = length.length; + else if( length.byteLength ) + length = length.byteLength; + else if( _.countable.is( length ) ) + length = [ ... length ].length; + + let result = this._make( type, length ); + let resultTyped = result; + if( !resultTyped.length ) + { + if( _.buffer.viewIs( resultTyped ) ) + resultTyped = new U8x( resultTyped.buffer ); + else + resultTyped = new U8x( resultTyped ); + } + for( let i = 0 ; i < length ; i++ ) + resultTyped[ i ] = value; + + return result; +} + +// + +function makeFilling( type, value, length ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( arguments.length === 2 ) + { + _.assert( _.number.is( value ) || _.countable.is( value ) || this.like( length ) ); + _.assert( type !== undefined ); + } + else + { + _.assert( value !== undefined ); + _.assert( _.number.is( length ) || _.countable.is( length ) || this.like( length ) ); + _.assert( type === null || _.long.is( type ) || this.like( type ) || _.routine.is( type ) ); + } + + return this._makeFilling( ... arguments ); +} + +// + +function _cloneShallow( src ) +{ + if( _.buffer.rawIs( src ) ) + return bufferRawCopy( src ); + if( _.buffer.viewIs( src ) ) + return new BufferView( bufferRawCopy( src ) ); + if( _.buffer.typedIs( src ) ) + return src.slice( 0 ); + if( _.buffer.nodeIs( src ) ) + return BufferNode.from( src ); + + /* */ + + function bufferRawCopy( src ) + { + const dst = new BufferRaw( src.byteLength ); + const buffer = src.buffer || src; + const offset = src.byteOffset || 0; + new U8x( dst ).set( new U8x( buffer, offset, src.byteLength ) ); + return dst; + } +} + +// + +function bufferFromArrayOfArray( array, options ) +{ + + if( _.object.isBasic( array ) ) + { + options = array; + array = options.buffer; + } + + options = options || Object.create( null ); + array = options.buffer = array || options.buffer; + + /* */ + + if( options.BufferType === undefined ) options.BufferType = F32x; + if( options.sameLength === undefined ) options.sameLength = 1; + if( !options.sameLength ) + throw _.err( '_.bufferFromArrayOfArray :', 'different length of arrays is not implemented' ); + + if( !array.length ) + return new options.BufferType(); + + let scalarsPerElement = _.number.is( array[ 0 ].length ) ? array[ 0 ].length : array[ 0 ].len; + + if( !_.number.is( scalarsPerElement ) ) + throw _.err( '_.bufferFromArrayOfArray :', 'cant find out element length' ); + + let length = array.length * scalarsPerElement; + let result = new options.BufferType( length ); + let i = 0; + + for( let a = 0 ; a < array.length ; a++ ) + { + let element = array[ a ]; + + for( let e = 0 ; e < scalarsPerElement ; e++ ) + { + result[ i ] = element[ e ]; + i += 1; + } + } + + return result; +} + +// + +/** + * The bufferRawFromTyped() routine returns a new BufferRaw from (buffer.byteOffset) to the end of an BufferRaw of a typed array (buffer) + * or returns the same BufferRaw of the (buffer), if (buffer.byteOffset) is not provided. + * + * @param { typedArray } buffer - Entity to check. + * + * @example + * let buffer1 = new BufferRaw( 10 ); + * let view1 = new I8x( buffer1 ); + * _.bufferRawFromTyped( view1 ); + * // returns [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] + * + * @example + * let buffer2 = new BufferRaw( 10 ); + * let view2 = new I8x( buffer2, 2 ); + * _.bufferRawFromTyped( view2 ); + * // returns [ 0, 0, 0, 0, 0, 0 ] + * + * @returns { BufferRaw } Returns a new or the same BufferRaw. + * If (buffer) is instance of '[object ArrayBuffer]', it returns buffer. + * @function bufferRawFromTyped + * @throws { Error } Will throw an Error if (arguments.length) is not equal to the 1. + * @throws { Error } Will throw an Error if (buffer) is not a typed array. + * @namespace Tools + */ + +function bufferRawFromTyped( buffer ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.bufferTypedIs( buffer ) || _.bufferRawIs( buffer ) ); + + if( _.bufferRawIs( buffer ) ) + return buffer; + + let result = buffer.buffer; + + if( buffer.byteOffset || buffer.byteLength !== result.byteLength ) + result = result.slice( buffer.byteOffset || 0, buffer.byteLength ); + + _.assert( _.bufferRawIs( result ) ); + + return result; +} + +// + +function bufferRawFrom( buffer ) +{ + let result; + + /* + aaa : should do not copying when possible! | + aaa Dmytro : not copying if it possible + zzz + */ + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( buffer instanceof BufferRaw ) + return buffer; + + if( _.bufferNodeIs( buffer ) || _.arrayIs( buffer ) ) + { + + // result = buffer.buffer; + result = new U8x( buffer ).buffer; + + } + else if( _.bufferTypedIs( buffer ) || _.bufferViewIs( buffer ) ) + { + + result = buffer.buffer; + if( buffer.byteOffset || buffer.byteLength !== result.byteLength ) + // Dmytro : works not correctly, offset + length = right bound of new bufferRaw + // result = result.slice( buffer.byteOffset || 0, buffer.byteLength ); + result = result.slice( buffer.byteOffset, buffer.byteOffset + buffer.byteLength ); + + } + else if( _.strIs( buffer ) ) + { + + if( _global_.BufferNode ) + { + result = _.bufferRawFrom( BufferNode.from( buffer, 'utf8' ) ); + } + else + { + result = _.encode.utf8ToBuffer( buffer ).buffer; + } + + } + else if( _global.File && buffer instanceof File ) + { + let fileReader = new FileReaderSync(); + result = fileReader.readAsArrayBuffer( buffer ); + _.assert( 0, 'not tested' ); + } + else _.assert( 0, () => 'Unknown type of source ' + _.entity.strType( buffer ) ); + + _.assert( _.bufferRawIs( result ) ); + + return result; +} + +// + +function bufferBytesFrom( buffer ) +{ + let result; + + // Dmytro : missed + if( _.bufferBytesIs( buffer ) ) + return buffer; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.bufferNodeIs( buffer ) ) + { + + _.assert( _.bufferRawIs( buffer.buffer ) ) + result = new U8x( buffer.buffer, buffer.byteOffset, buffer.byteLength ); + + } + else if( _.bufferRawIs( buffer ) ) + { + + result = new U8x( buffer, 0, buffer.byteLength ); + + } + else if( _.bufferTypedIs( buffer ) ) + { + + result = new U8x( buffer.buffer, buffer.byteOffset, buffer.byteLength ); + + } + else if( _.bufferViewIs( buffer ) ) + { + + result = new U8x( buffer.buffer, buffer.byteOffset, buffer.byteLength ); + + } + else + { + + return _.bufferBytesFrom( _.bufferRawFrom( buffer ) ); + + } + + _.assert( _.bufferBytesIs( result ) ); + + return result; +} + +// + +function bufferBytesFromNode( src ) /* Dmytro : what does this code do? */ +{ + _.assert( _.bufferNodeIs( src ) ); + let result = new U8x( buffer ); + return result; +} + +// + +function bufferNodeFrom( buffer ) +{ + if( _.bufferNodeIs( buffer ) ) + return buffer; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.bufferAnyIs( buffer ) || _.strIs( buffer ) || _.arrayIs( buffer ), 'Expects buffer, string of array, but got', _.entity.strType( buffer ) ); + + /* */ + + let result; + + if( buffer.length === 0 || buffer.byteLength === 0 ) + { + result = BufferNode.from([]); + } + else if( _.strIs( buffer ) ) + { + result = _.bufferNodeFrom( _.bufferRawFrom( buffer ) ); + } + else if( buffer.buffer ) + { + result = BufferNode.from( buffer.buffer, buffer.byteOffset, buffer.byteLength ); + } + else + { + result = BufferNode.from( buffer ); + } + + _.assert( _.bufferNodeIs( result ) ); + + return result; +} + +// -- +// meta +// -- + +/* qqq : optimize */ +function namespaceOf( src ) +{ + + if( _.bufferRaw.is( src ) ) + return _.bufferRaw; + if( _.bufferView.is( src ) ) + return _.bufferView; + if( _.bufferNode.is( src ) ) + return _.bufferNode; + + return _.bufferTyped.namespaceOf( src ); +} + +// -- +// declaration +// -- + +let BufferExtension = +{ + + // + + NamespaceName : 'buffer', + NamespaceNames : [ 'buffer' ], + NamespaceQname : 'wTools/buffer', + TypeName : 'Buffer', + TypeNames : [ 'Buffer', 'BufferAny' ], + // SecondTypeName : 'BufferAny', + InstanceConstructor : null, + tools : _, + + // dichotomy + + anyIs, + // anyIsOld, + // anyIsUsingInstanceOf, + is : anyIs, + like : anyIs, + IsResizable, + + // maker + + _make_functor, /* aaa : remove maybe */ /* Dmytro : implemented */ + _make, /* aaa : implement */ /* Dmytro : implemented */ + make, + _makeEmpty, + makeEmpty, + _makeUndefined, /* aaa : implement */ /* Dmytro : implemented */ + makeUndefined, + _makeZeroed : _makeUndefined, /* aaa : implement */ /* Dmytro : implemented */ + makeZeroed : makeUndefined, + _makeFilling, + makeFilling, + + _cloneShallow, + cloneShallow : _.argumentsArray.cloneShallow, /* qqq : for junior : cover */ + from : _.argumentsArray.from, /* qqq : for junior : cover */ + + // meta + + namespaceOf, + namespaceWithDefaultOf : _.props.namespaceWithDefaultOf, + _functor_functor : _.props._functor_functor, + +} + +Object.assign( _.buffer, BufferExtension ); + +// + +let ToolsExtension = +{ + + // dichotomy + + bufferAnyIs : anyIs.bind( _.buffer ), + bufferIs : anyIs.bind( _.buffer ), + + // maker + + /* qqq : attention is needed. ask */ + bufferMake : make.bind( _.buffer ), + bufferMakeEmpty : makeEmpty.bind( _.buffer ), + bufferMakeUndefined : makeUndefined.bind( _.buffer ), + bufferMakeZeroed : _.buffer.makeZeroed.bind( _.buffer ), + + bufferFromArrayOfArray, + bufferRawFromTyped, /* xxx : qqq : for Dmytro : move corresponding namespace and tests */ + bufferRawFrom, /* xxx : qqq : for Dmytro : move corresponding namespace and tests */ + bufferBytesFrom, /* xxx : qqq : for Dmytro : move corresponding namespace and tests */ + bufferBytesFromNode, /* xxx : qqq : for Dmytro : move corresponding namespace and tests */ + bufferNodeFrom, /* xxx : qqq : for Dmytro : move corresponding namespace and tests */ + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Buffer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Buffer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Buffer_s */ })(); + +/* */ /* begin of file BufferBytes_s */ ( function BufferBytes_s() { function BufferBytes_s_naked() { ( function _l1_BufferBytes_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.assert( _.bufferBytes === undefined ); +_.assert( _.u8x === undefined ); +_.bufferBytes = _.u8x = _.bufferBytes || _.u8x || Object.create( null ); + +// -- +// implementation +// -- + +function is( src ) +{ + if( _.buffer.nodeIs( src ) ) + return false; + return src instanceof U8x; +} + +// -- +// declaration +// -- + +let BufferBytesExtension = +{ + + // + + NamespaceName : 'u8x', + NamespaceNames : [ 'u8x', 'bufferBytes' ], + NamespaceQname : 'wTools/u8x', + TypeName : 'U8x', + TypeNames : [ 'U8x', 'Uint8Array', 'BufferBytes', ], + InstanceConstructor : U8x, + tools : _, + + // dichotomy + + // bytesIs, + is, + like : is, + + // maker + + // _make : _.buffer._make, /* qqq : cover */ + // make : _.buffer.make, + // _makeEmpty : _.buffer._makeEmpty, + // makeEmpty : _.buffer.makeEmpty, + // _makeUndefined : _.buffer._makeUndefined, /* qqq : implement */ + // makeUndefined : _.buffer.makeUndefined, + // _makeZeroed : _.buffer._makeZeroed, + // makeZeroed : _.buffer.makeZeroed, /* qqq : for junior : cover */ + // _cloneShallow : _.buffer._cloneShallow, + // cloneShallow : _.buffer.cloneShallow, /* qqq : for junior : cover */ + // from : _.buffer.from, /* qqq : for junior : cover */ + // qqq : implement + +} + +Object.assign( _.bufferBytes, BufferBytesExtension ); + +// + +let BufferExtension = +{ + + // dichotomy + + bytesIs : is.bind( _.bufferBytes ), + +} + +Object.assign( _.buffer, BufferExtension ); + +// + +let ToolsExtension = +{ + + // dichotomy + + bufferBytesIs : is.bind( _.bufferBytes ), + bufferBytesLike : is.bind( _.bufferBytes ), + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/BufferBytes.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, BufferBytes_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file BufferBytes_s */ })(); + +/* */ /* begin of file BufferNode_s */ ( function BufferNode_s() { function BufferNode_s_naked() { ( function _l1_BufferNode_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.bufferNode = _.bufferNode || Object.create( null ); + +// -- +// implementation +// -- + +/* qqq : for Rahul : write performance test and optimize */ +function nodeIs( src ) +{ + // if( typeof BufferNode !== 'undefined' ) + if( _global_.BufferNode ) + return src instanceof BufferNode; + return false; +} + +// -- +// declaration +// -- + +let BufferNodeExtension = +{ + + // + + NamespaceName : 'bufferNode', + NamespaceNames : [ 'bufferNode' ], + NamespaceQname : 'wTools/bufferNode', + TypeName : 'BufferNode', + TypeNames : [ 'BufferNode' ], + // SecondTypeName : 'ArrayNode', + InstanceConstructor : _global.BufferNode, + tools : _, + + // dichotomy + + nodeIs, + is : nodeIs, + like : nodeIs, + + // maker + + _make : _.buffer._make, /* qqq : cover */ + make : _.buffer.make, + _makeEmpty : _.buffer._makeEmpty, + makeEmpty : _.buffer.makeEmpty, + _makeUndefined : _.buffer._makeUndefined, /* qqq : implement */ + makeUndefined : _.buffer.makeUndefined, + // _makeZeroed : _.buffer._makeZeroed, + // makeZeroed : _.buffer.makeZeroed, /* qqq : for junior : cover */ + // _cloneShallow : _.buffer._cloneShallow, + // cloneShallow : _.buffer.cloneShallow, /* qqq : for junior : cover */ + // from : _.buffer.from, /* qqq : for junior : cover */ + // qqq : implement + +} + +Object.assign( _.bufferNode, BufferNodeExtension ); + +// + +let BufferExtension = +{ + + // dichotomy + + nodeIs : nodeIs.bind( _.buffer ), + +} + +Object.assign( _.buffer, BufferExtension ); + +// + +let ToolsExtension = +{ + + // dichotomy + + bufferNodeIs : nodeIs.bind( _.buffer ), + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/BufferNode.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, BufferNode_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file BufferNode_s */ })(); + +/* */ /* begin of file BufferRaw_s */ ( function BufferRaw_s() { function BufferRaw_s_naked() { ( function _l1_BufferRaw_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.bufferRaw = _.bufferRaw || Object.create( null ); + +// -- +// implementation +// -- + +function rawIs( src ) +{ + let type = Object.prototype.toString.call( src ); + // let result = type === '[object ArrayBuffer]'; + // return result; + if( type === '[object ArrayBuffer]' || type === '[object SharedArrayBuffer]' ) + return true; + return false; +} + +// -- +// declaration +// -- + +let BufferRawExtension = +{ + + // + + NamespaceName : 'bufferRaw', + NamespaceNames : [ 'bufferRaw' ], + NamespaceQname : 'wTools/bufferRaw', + TypeName : 'BufferRaw', + TypeNames : [ 'BufferRaw', 'ArrayBuffer' ], + // SecondTypeName : 'ArrayRaw', + InstanceConstructor : ArrayBuffer, + tools : _, + + // dichotomy + + rawIs, + is : rawIs, + like : rawIs, + + // maker + + _make : _.buffer._make, /* qqq : cover */ + make : _.buffer.make, + _makeEmpty : _.buffer._makeEmpty, + makeEmpty : _.buffer.makeEmpty, + _makeUndefined : _.buffer._makeUndefined, /* qqq : implement */ + makeUndefined : _.buffer.makeUndefined, + // _makeZeroed : _.buffer._makeZeroed, + // makeZeroed : _.buffer.makeZeroed, /* qqq : for junior : cover */ + // _cloneShallow : _.buffer._cloneShallow, + // cloneShallow : _.buffer.cloneShallow, /* qqq : for junior : cover */ + // from : _.buffer.from, /* qqq : for junior : cover */ + // qqq : implement + +} + +Object.assign( _.bufferRaw, BufferRawExtension ); + +// + +let BufferExtension = +{ + + // dichotomy + + rawIs : rawIs.bind( _.buffer ), + +} + +Object.assign( _.buffer, BufferExtension ); + +// + +let ToolsExtension = +{ + + // dichotomy + + bufferRawIs : rawIs.bind( _.buffer ), + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/BufferRaw.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, BufferRaw_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file BufferRaw_s */ })(); + +/* */ /* begin of file BuffersTyped_s */ ( function BuffersTyped_s() { function BuffersTyped_s_naked() { ( function _l1_BuffersTyped_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +function _functor( fo ) +{ + + _.assert( !!_.bufferTyped ); + _[ fo.name ] = _[ fo.name ] || Object.create( null ); + fo.names.forEach( ( name ) => + { + _[ name ] = _[ fo.name ]; + }); + + // -- + // dichotomy + // -- + + function is( src ) + { + return src instanceof this.InstanceConstructor; + } + + // + + function like( src ) /* qqq : cover */ + { + let type = Object.prototype.toString.call( src ); + if( !/\wArray/.test( type ) ) + return false; + if( type === '[object SharedArrayBuffer]' ) + return false; + if( _.bufferNodeIs( src ) ) + return false; + return true; + } + + // + + function IsResizable() + { + _.assert( arguments.length === 0 ); + return false; + } + + // -- + // maker + // -- + + function _makeEmpty( src ) + { + return new this.InstanceConstructor( 0 ); + } + + // + + // function makeEmpty( src ) + // { + // if( arguments.length === 1 ) + // _.assert( this.like( src ) ); + // else + // _.assert( arguments.length === 0 ); + // + // return this._makeEmpty( ... arguments ); + // + // // _.assert( arguments.length === 0 || arguments.length === 1 ); + // // if( arguments.length === 1 ) + // // { + // // _.assert( this.like( src ) ); + // // return []; + // // } + // // else + // // { + // // return []; + // // } + // } + + // + + function _makeUndefined( src, length ) + { + // if( arguments.length === 2 ) + // { + // if( _.long.is( length ) ) + // length = length.length; + // return new this.InstanceConstructor( length ); + // } + // else if( arguments.length === 1 ) + // { + // length = src; + // if( _.long.is( length ) ) + // length = length.length; + // if( length === null ) + // return new this.InstanceConstructor(); + // else + // return new this.InstanceConstructor( length ); + // } + + if( length === undefined ) + length = src; + if( length && !_.number.is( length ) ) + { + if( length.length ) + length = length.length; + else + length = [ ... length ].length; + } + return new this.InstanceConstructor( length ); + } + + // + + // function makeUndefined( src, length ) + // { + // _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + // if( arguments.length === 2 ) + // { + // _.assert( src === null || _.long.is( src ) ); + // _.assert( _.number.is( length ) || _.long.is( length ) ); + // } + // else if( arguments.length === 1 ) + // { + // _.assert( _.number.is( src ) || _.long.is( src ) || src === null ); + // } + // + // return this._makeUndefined( ... arguments ); + // + // // _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + // // if( arguments.length === 2 ) + // // { + // // _.assert( src === null || _.long.is( src ) ); + // // _.assert( _.number.is( length ) || _.long.is( length ) ); + // // return this._makeUndefined( src, length ); + // // } + // // else if( arguments.length === 1 ) + // // { + // // _.assert( _.number.is( src ) || _.long.is( src ) || src === null ); + // // return this._makeUndefined( src ); + // // } + // // else + // // { + // // return []; + // // } + // } + + // + + // function _makeZeroed( src, length ) + // { + // if( length === undefined ) + // length = src; + // if( this.like( length ) ) + // length = length.length; + // return new this.InstanceConstructor( length ); + // } + + // + + // function _makeFilling( type, value, length ) + // { + // if( arguments.length === 2 ) + // { + // value = arguments[ 0 ]; + // length = arguments[ 1 ]; + // if( _.longIs( length ) ) + // { + // if( _.argumentsArray.is( length ) ) + // type = length; + // else if( _.number.is( length ) ) + // type = null; + // else + // type = length; + // } + // else + // { + // type = null; + // } + // } + // + // if( _.longIs( length ) ) + // length = length.length; + // + // let result = this._make( type, length ); + // for( let i = 0 ; i < length ; i++ ) + // result[ i ] = value; + // + // return result; + // } + + // + + // function makeFilling( type, value, length ) + // { + // _.assert( arguments.length === 2 || arguments.length === 3 ); + // + // if( arguments.length === 2 ) + // { + // _.assert( _.number.is( value ) || _.countable.is( value ) ); + // _.assert( type !== undefined ); + // } + // else + // { + // _.assert( value !== undefined ); + // _.assert( _.number.is( length ) || _.countable.is( length ) ); + // _.assert( type === null || _.routine.is( type ) || _.longIs( type ) ); + // } + // + // return this._makeFilling( ... arguments ); + // } + + // + + function _make( src, length ) + { + if( arguments.length === 2 ) + { + let data = length; + if( _.number.is( length ) ) + { + data = src; + } + else if( length.length ) + { + length = length.length; + } + else if( _.countable.is( length ) ) + { + data = [ ... length ]; + length = data.length; + } + return fill( new this.InstanceConstructor( length ), data ); + } + else if( arguments.length === 1 ) + { + return new this.InstanceConstructor( src ); + } + return new this.InstanceConstructor( 0 ); + + /* */ + + function fill( dst, data ) + { + if( data === null || data === undefined ) + return dst; + let l = Math.min( length, data.length ); + for( let i = 0 ; i < l ; i++ ) + dst[ i ] = data[ i ]; + return dst; + } + + // if( _.numberIs( length ) ) + // return new this.InstanceConstructor( length ); + // if( _.numberIs( src ) ) + // return new this.InstanceConstructor( src ); + // if( src ) + // return new this.InstanceConstructor( src ); + // return new this.InstanceConstructor( 0 ); + } + + // + + // function make( src, length ) + // { + // _.assert( arguments.length === 0 || src === null || _.countable.is( src ) || _.numberIs( src ) ); + // _.assert( length === undefined || !_.number.is( src ) || !_.number.is( length ) ); + // // _.assert( arguments.length < 2 || _.number.is( length ) ); + // _.assert( arguments.length < 2 || _.number.is( length ) || _.countable.is( length ) ); + // _.assert( arguments.length <= 2 ); + // return this._make( ... arguments ); + // } + + // + + function _cloneShallow( srcArray ) + { + return srcArray.slice(); + } + + // + + function cloneShallow( srcArray ) + { + _.assert( this.like( srcArray ) ); + _.assert( arguments.length === 1 ); + return this._cloneShallow( srcArray ); + } + + // + + function from( src ) + { + _.assert( arguments.length === 1, 'Expects single argument' ); + if( this.is( src ) ) + return src; + return this.make( src ); + } + + // -- + // declare + // -- + + let ToolsExtension = + { + + /* xxx : binding will cause problem with changing default long type */ + + // dichotomy + + [ fo.name + 'Is' ] : is.bind( _[ fo.name ] ), + [ fo.name + 'Like' ] : like.bind( _[ fo.name ] ), + + // maker + + [ fo.name + 'MakeEmpty' ] : _.argumentsArray.makeEmpty.bind( _[ fo.name ] ), + // [ fo.name + 'MakeEmpty' ] : makeEmpty.bind( _[ fo.name ] ), + [ fo.name + 'MakeUndefined' ] : _.argumentsArray.makeUndefined.bind( _[ fo.name ] ), + // [ fo.name + 'MakeUndefined' ] : makeUndefined.bind( _[ fo.name ] ), + [ fo.name + 'Make' ] : _.argumentsArray.make.bind( _[ fo.name ] ), + // [ fo.name + 'Make' ] : make.bind( _[ fo.name ] ), + [ fo.name + 'CloneShallow' ] : cloneShallow.bind( _[ fo.name ] ), + [ fo.name + 'From' ] : from.bind( _[ fo.name ] ), + + } + + _.props.supplement( _, ToolsExtension ); + + // + + let BufferTypedExtension = + { + + // + + NamespaceName : fo.name, + NamespaceNames : fo.names, + NamespaceQname : `wTools/${fo.name}`, + MoreGeneralNamespaceName : 'bufferTyped', + MostGeneralNamespaceName : 'countable', + TypeName : fo.typeName, + TypeNames : fo.typeNames, + // TypeNames : [ fo.typeName, fo.secondTypeName ], + // SecondTypeName : fo.secondTypeName, + InstanceConstructor : fo.instanceConstructor, + IsTyped : true, + tools : _, + + // dichotomy + + is, + like, + IsResizable, + + // maker + + _makeEmpty, + makeEmpty : _.argumentsArray.makeEmpty, /* qqq : for junior : cover */ + _makeUndefined, + makeUndefined : _.argumentsArray.makeUndefined, /* qqq : for junior : cover */ + _makeZeroed : _makeUndefined, + makeZeroed : _.argumentsArray.makeUndefined, + // makeZeroed : makeUndefined, + _makeFilling : _.argumentsArray.makeFilling, + makeFilling : _.argumentsArray.makeFilling, + _make, + make : _.argumentsArray.make, /* qqq : for junior : cover */ + // make, /* qqq : for junior : cover */ + _cloneShallow, + cloneShallow, /* qqq : for junior : cover */ + from, /* qqq : for junior : cover */ + + // meta + + namespaceOf : _.blank.namespaceOf, + namespaceWithDefaultOf : _.blank.namespaceWithDefaultOf, + _functor_functor : _.blank._functor_functor, + + } + + // + + _.props.supplement( _[ fo.name ], BufferTypedExtension ); + _.bufferTyped._namespaceRegister( _[ fo.name ] ); + +} + +_functor({ name : 'u32x', names : [ 'u32x', 'ux' ], typeName : 'U32x', typeNames : [ 'U32x', 'Uint32Array', 'Ux' ], instanceConstructor : U32x }); +_functor({ name : 'u16x', names : [ 'u16x' ], typeName : 'U16x', typeNames : [ 'U16x', 'Uint16Array' ], instanceConstructor : U16x }); +_functor({ name : 'u8x', names : [ 'u8x' ], typeName : 'U8x', typeNames : [ 'U8x', 'Uint8Array' ], instanceConstructor : U8x }); +_functor({ name : 'u8xClamped', names : [ 'u8xClamped' ], typeName : 'U8xClamped', typeNames : [ 'U8xClamped', 'Uint8ClampedArray' ], instanceConstructor : U8xClamped }); + +_functor({ name : 'i32x', names : [ 'i32x', 'ix' ], typeName : 'I32x', typeNames : [ 'I32x', 'Int32Array', 'Ix' ], instanceConstructor : I32x }); +_functor({ name : 'i16x', names : [ 'i16x' ], typeName : 'I16x', typeNames : [ 'I16x', 'Int16Array' ], instanceConstructor : I16x }); +_functor({ name : 'i8x', names : [ 'i8x' ], typeName : 'I8x', typeNames : [ 'I8x', 'Int8Array' ], instanceConstructor : I8x }); + +_functor({ name : 'f64x', names : [ 'f64x' ], typeName : 'F64x', typeNames : [ 'F64x', 'Float64Array' ], instanceConstructor : F64x }); +_functor({ name : 'f32x', names : [ 'f32x', 'fx' ], typeName : 'F32x', typeNames : [ 'F32x', 'Float32Array', 'Fx' ], instanceConstructor : F32x }); + +_.assert( !!_.fx ); +_.assert( _.bufferTyped.default === undefined ); +_.bufferTyped.default = _.fx; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/BuffersTyped.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, BuffersTyped_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file BuffersTyped_s */ })(); + +/* */ /* begin of file BufferView_s */ ( function BufferView_s() { function BufferView_s_naked() { ( function _l1_BufferView_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.bufferView = _.bufferView || Object.create( null ); + +// -- +// implementation +// -- + +function viewIs( src ) +{ + let type = Object.prototype.toString.call( src ); + let result = type === '[object DataView]'; + return result; +} + +// -- +// declaration +// -- + +let BufferViewExtension = +{ + + // + + NamespaceName : 'bufferView', + NamespaceNames : [ 'bufferView' ], + NamespaceQname : 'wTools/bufferView', + TypeName : 'BufferView', + TypeNames : [ 'BufferView', 'DataView' ], + // SecondTypeName : 'DataView', + InstanceConstructor : DataView, + tools : _, + + // dichotomy + + viewIs, + is : viewIs, + like : viewIs, + + // maker + + _make : _.buffer._make, /* qqq : cover */ + make : _.buffer.make, + _makeEmpty : _.buffer._makeEmpty, + makeEmpty : _.buffer.makeEmpty, + _makeUndefined : _.buffer._makeUndefined, /* qqq : implement */ + makeUndefined : _.buffer.makeUndefined, + // _makeZeroed : _.buffer._makeZeroed, + // makeZeroed : _.buffer.makeZeroed, /* qqq : for junior : cover */ + // _cloneShallow : _.buffer._cloneShallow, + // cloneShallow : _.buffer.cloneShallow, /* qqq : for junior : cover */ + // from : _.buffer.from, /* qqq : for junior : cover */ + // qqq : implement + +} + +Object.assign( _.bufferView, BufferViewExtension ); + +// + +let BufferExtension = +{ + + // dichotomy + + viewIs : viewIs.bind( _.buffer ), + +} + +Object.assign( _.buffer, BufferExtension ); + +// + +let ToolsExtension = +{ + + // dichotomy + + bufferViewIs : viewIs.bind( _.buffer ), + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/BufferView.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, BufferView_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file BufferView_s */ })(); + +/* */ /* begin of file Class_s */ ( function Class_s() { function Class_s_naked() { ( function _l1_Class_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.class = _.class || Object.create( null ); + +// -- +// container +// -- + +function methodIteratorOf( src ) +{ + if( !src ) + return; + if( _.routine.like( src[ iteratorSymbol ] ) ) + return src[ iteratorSymbol ]; + return; +} + +// + +/* qqq : for junior : cover */ +function methodEqualOf( src ) +{ + if( !src ) + return; + if( _.routine.is( src[ equalAreSymbol ] ) ) + return src[ equalAreSymbol ]; + if( _.routine.is( src.equalAre ) ) + return src.equalAre; + return; +} + +// + +/* qqq : for junior : cover */ +function methodExportStringOf( src ) +{ + if( !src ) + return; + if( _.routine.is( src[ exportStringSymbol ] ) ) + return src[ exportStringSymbol ]; + if( _.routine.is( src.exportString ) ) + return src.exportString; + return; +} + +// + +function methodAscendOf( src ) +{ + if( !src ) + return; + if( _.routine.is( src[ ascendSymbol ] ) ) + return src[ ascendSymbol ]; + if( _.routine.is( src.ascend ) ) + return src.ascend; + return; +} + +// + +/* qqq : for junior : cover */ +function methodCloneShallowOf( src ) +{ + if( !src ) + return; + if( _.routine.is( src[ cloneShallowSymbol ] ) ) + return src[ cloneShallowSymbol ]; + if( _.routine.is( src.cloneShallow ) ) + return src.cloneShallow; + return +} + +// + +/* qqq : for junior : cover */ +function methodCloneDeepOf( src ) +{ + if( !src ) + return; + if( _.routine.is( src[ cloneDeepSymbol ] ) ) + return src[ cloneDeepSymbol ]; + if( _.routine.is( src.cloneDeep ) ) + return src.cloneDeep; + return +} + +// + +function methodElementWithKeySetOf( src ) +{ + if( !src ) + return; + if( _.routine.is( src[ elementWithKeySetSymbol ] ) ) + return src[ elementWithKeySetSymbol ]; + return; +} + +// + +function methodElementSetOf( src ) +{ + if( !src ) + return; + if( _.routine.is( src[ elementSetSymbol ] ) ) + return src[ elementSetSymbol ]; + if( _.routine.is( src.eSet ) ) + return src.eSet; + return; +} + +// + +function methodMakeEmptyOf( src ) +{ + if( _.routine.is( src.makeEmpty ) ) + return src.makeEmpty; + if( _.routine.is( src.MakeEmpty ) ) + return src.MakeEmpty; + return; +} + +// + +function methodMakeUndefinedOf( src ) +{ + if( _.routine.is( src.makeUndefined ) ) + return src.makeUndefined; + if( _.routine.is( src.MakeUndefined ) ) + return src.MakeUndefined; + return; +} + +// + +function declareBasic( o ) +{ + + for( let e in o ) + { + if( declareBasic.defaults[ e ] === undefined ) + { + throw Error( `Unknown option::${e}` ); + } + } + + for( let e in declareBasic.defaults ) + { + if( o[ e ] === undefined ) + o[ e ] = declareBasic.defaults[ e ]; + } + + _.assert( routineIs( o.constructor ) && o.constructor !== Object.constructor && o.constructor !== Object ); + _.assert( strDefined( o.constructor.name ) && o.constructor.name !== 'Object' ); + _.assert( arguments.length === 1 ); + _.assert( o.iterate === undefined ); + + o.exportString = o.exportString || exportString; + o.cloneShallow = o.cloneShallow || cloneShallow; + o.cloneDeep = o.cloneDeep || o.cloneShallow; + o.equalAre = o.equalAre || equalAre; + + // debugger; + // Object.setPrototypeOf( o.constructor.prototype, null ); + o.constructor.prototype = Object.create( o.prototype ); + if( o.iterator ) + o.constructor.prototype[ iteratorSymbol ] = o.iterator; + o.constructor.prototype[ exportPrimitiveSymbol ] = exportStringIgnoringArgs; + o.constructor.prototype[ exportStringNjsSymbol ] = exportStringIgnoringArgs; + o.constructor.prototype[ exportStringSymbol ] = o.exportString; + o.constructor.prototype[ cloneShallowSymbol ] = o.cloneShallow; /* xxx : reimplement? */ + o.constructor.prototype[ cloneDeepSymbol ] = o.cloneDeep; /* xxx : implement */ + o.constructor.prototype[ equalAreSymbol ] = o.equalAre; /* qqq : cover */ + o.constructor.prototype.constructor = o.constructor; + + Object.defineProperty( o.constructor.prototype, exportTypeNameGetterSymbol, + { + enumerable : false, + configurable : false, + get : TypeNameGet, + }); + + /* - */ + + function TypeNameGet() + { + return this.constructor.name; + } + + /* - */ + + function cloneShallow() + { + _.assert( !( this instanceof cloneShallow ) ); + return this; + } + + /* - */ + + function equalAre( it ) + { + let self = this; + _.assert( arguments.length === 1 ); + debugger; + if( it.src !== it.src2 ) + return it.stop( false ); + } + + /* - */ + + function exportString() + { + return `{- ${this.constructor.name} -}`; + } + + /* - */ + + function exportStringIgnoringArgs() + { + return this[ exportStringSymbol ](); + } + + /* - */ + + function strDefined( src ) + { + if( !src ) + return; + let result = Object.prototype.toString.call( src ) === '[object String]'; + return result; + } + + /* - */ + + function routineIs( src ) + { + let typeStr = Object.prototype.toString.call( src ); + return typeStr === '[object Function]' || typeStr === '[object AsyncFunction]'; + } + + /* - */ + +} + +declareBasic.defaults = +{ + constructor : null, + prototype : null, + parent : null, + exportString : null, + cloneShallow : null, + cloneDeep : null, + equalAre : null, + iterator : null, +} + +// -- +// tools extension +// -- + +let ToolsExtension = +{ +} + +// + +Object.assign( _, ToolsExtension ); + +// -- +// class extension +// -- + +const iteratorSymbol = Symbol.iterator; +const exportTypeNameGetterSymbol = Symbol.toStringTag; +const exportPrimitiveSymbol = Symbol.toPrimitive; +const exportStringNjsSymbol = Symbol.for( 'nodejs.util.inspect.custom' ); +const exportStringSymbol = Symbol.for( 'exportString' ); +const ascendSymbol = Symbol.for( 'ascend' ); +const equalAreSymbol = Symbol.for( 'equalAre' ); +const cloneShallowSymbol = Symbol.for( 'cloneShallow' ); +const cloneDeepSymbol = Symbol.for( 'cloneDeep' ); +const elementWithKeySetSymbol = Symbol.for( 'elementWithKeySet' ); +const elementSetSymbol = Symbol.for( 'elementSet' ); + +// + +let ClassExtension = +{ + + methodIteratorOf, + methodEqualOf, /* xxx : qqq : add other similar routines */ + methodExportStringOf, + methodAscendOf, + methodCloneShallowOf, + methodCloneDeepOf, + methodElementWithKeySetOf, + methodElementSetOf, + methodMakeEmptyOf, + methodMakeUndefinedOf, + + declareBasic, + + // fields + + tools : _, + iteratorSymbol, + exportTypeNameGetterSymbol, + exportPrimitiveSymbol, + exportStringNjsSymbol, + exportStringSymbol, + ascendSymbol, + equalAreSymbol, + cloneShallowSymbol, + cloneDeepSymbol, + elementSetSymbol, + +} + +// + +Object.assign( _.class, ClassExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Class.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Class_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Class_s */ })(); + +/* */ /* begin of file Constructible_s */ ( function Constructible_s() { function Constructible_s_naked() { ( function _l1_Constructible_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.constructible = _.constructible || Object.create( null ); + +// -- +// dichotomy +// -- + +function is( src ) /* xxx qqq : optimize */ +{ + if( _.primitive.is( src ) ) + return false; + + let proto = Object.getPrototypeOf( src ); + if( proto === null ) + return false; + + if( !Reflect.has( proto, 'constructor' ) ) + return false; + if( proto.constructor === Object ) + return false; + + if( _.aux.is( src ) ) /* xxx : remove? */ + return false; + if( _.vector.is( src ) ) + return false; + if( _.set.is( src ) ) + return false; + if( _.hashMap.is( src ) ) + return false; + + return true; +} + +// + +function like( src ) +{ + return _.constructibleIs( src ); +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + + // dichotomy + + constructibleIs : is, /* qqq : cover and move */ + constructibleLike : like, /* qqq : cover and move */ + +} + +// + +let Extension = +{ + + // dichotomy + + is, /* qqq : cover and move */ + like, /* qqq : cover and move */ + +} + +// + +Object.assign( _, ToolsExtension ); +Object.assign( _.constructible, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Constructible.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Constructible_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Constructible_s */ })(); + +/* */ /* begin of file Container_s */ ( function Container_s() { function Container_s_naked() { ( function _l1_Container_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const _functor_functor = _.props._functor_functor; + +// -- +// implementation +// -- + +/* xxx : adjust */ +/* qqq : cover is and like by test routine dichotomy */ +function is( src ) +{ + if( _.countable.like( src ) ) + return true; + if( _.aux.is( src ) ) + return true; + return false; +} + +// function is( src ) +// { +// if( _.longLike( src ) ) +// return true; +// if( _.aux.is( src ) ) +// return true; +// if( _.hashMap.like( src ) ) +// return true; +// if( _.set.like( src ) ) +// return true; +// return false; +// } + +// + +function like( src ) +{ + return _.container.is( src ); +} + +// -- +// maker +// -- + +function cloneShallow( container ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 1 ); + return cloneShallow.functor.call( this, container )(); +} + +cloneShallow.functor = _functor_functor( 'cloneShallow' ); + +// + +function make( container, ... args ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + return make.functor.call( this, container )( ... args ); +} + +make.functor = _functor_functor( 'make' ); + +// + +function makeEmpty( container ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 1 ); + return makeEmpty.functor.call( this, container )(); +} + +makeEmpty.functor = _functor_functor( 'makeEmpty' ); + +// + +function makeUndefined( container, ... args ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + return makeUndefined.functor.call( this, container )( ... args ); +} + +makeUndefined.functor = _functor_functor( 'makeUndefined' ); + +// -- +// meta +// -- + +function namespaceForIterating( src ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 1 ); + + if( _.primitive.is( src ) ) + return _.blank; + if( _.hashMap.like( src ) ) + return _.hashMap; + if( _.set.like( src ) ) + return _.set; + if( _.longIs( src ) ) + return _.long; + if( _.countableIs( src ) ) + return _.countable; + if( _.auxIs( src ) ) + return _.aux; + + return _.blank; +} + +// + +function namespaceForExporting( src ) +{ + if( _.primitive.is( src ) ) + return _.primitive; + if( _.date.is( src ) ) + return _.date; + if( _.regexp.is( src ) ) + return _.regexp; + if( _.set.like( src ) ) + return _.set; + if( _.hashMap.like( src ) ) + return _.hashMap; + if( _.routine.is( src ) ) + return _.routine; + if( _.buffer.like( src ) ) + return _.buffer; + if( _.long.like( src ) ) + return _.long; + if( _.vector.like( src ) ) + return _.vector; + if( _.countable.like( src ) ) + return _.countable; + if( _.aux.like( src ) ) + return _.aux; + if( _.object.like( src ) ) + return _.object; + + return null; +} + +// -- +// declare type +// -- + +class Container +{ + static[ Symbol.hasInstance ]( instance ) + { + return is( instance ); + } +} + +let Handler = +{ + construct( original, args ) + { + return Container.make( ... args ); + } +}; + +const Self = new Proxy( Container, Handler ); +Self.original = Container; + +// -- +// extend container +// -- + +let ContainerExtension = +{ + + NamespaceName : 'container', + NamespaceNames : [ 'container' ], + NamespaceQname : 'wTools/container', + TypeName : 'Container', + TypeNames : [ 'Container' ], + // SecondTypeName : 'Container', + InstanceConstructor : null, + tools : _, + + // dichotomy + + is, /* qqq : cover please */ + like, + + // maker + + cloneShallow, /* qqq : cover */ + make, /* qqq : cover */ + makeEmpty, /* qqq : cover */ + makeUndefined, /* qqq : cover */ + + // meta + + namespaceForIterating, + namespaceForExporting, + namespaceOf : namespaceForIterating, + namespaceWithDefaultOf : _.props.namespaceWithDefaultOf, + _functor_functor : _.props._functor_functor, + +} + +// + +_.container = Self; + +Object.assign( Self, ContainerExtension ); + +// -- +// extend tools +// -- + +let ToolsExtension = +{ + + containerIs : is.bind( _.container ), + containerLike : like.bind( _.container ), + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Container.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Container_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Container_s */ })(); + +/* */ /* begin of file ContainerAdapter_s */ ( function ContainerAdapter_s() { function ContainerAdapter_s_naked() { ( function _l1_ContainerAdapter_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// exporter +// -- + +// function is( src ) +// { +// if( !src ) +// return false; +// return src instanceof ContainerAdapterAbstract; +// } + +// + +function is( src ) +{ + // if( _.primitive.is( src ) ) + // return false; + if( !src ) + return false; + if( !_.containerAdapter.Abstract ) + return false; + return src instanceof _.containerAdapter.Abstract; +} + +// + +function like( src ) +{ + return this.is( src ); +} + +// + +function isContainer( src ) +{ + if( _.set.like( src ) ) + return true; + if( _.long.like( src ) ) + return true; + if( _.containerAdapter.is( src ) ) + return true; + return false; +} + +// + +// function adapterLike( src ) +function setLike( src ) +{ + if( !src ) + return false; + if( _.set.like( src ) ) + return true; + if( !_.containerAdapter || !_.containerAdapter.Set ) + return false; + if( src instanceof _.containerAdapter.Set ) + return true; + return false; +} + +// + +function longLike( src ) +{ + if( !src ) + return false; + if( _.long.like( src ) ) + return true; + if( !_.containerAdapter || !_.containerAdapter.Array ) + return false; + if( src instanceof _.containerAdapter.Array ) + return true; + return false; +} + +// -- +// +// -- + +class ContainerAdapterNamespace +{ + static[ Symbol.hasInstance ]( instance ) + { + return is( instance ); + } +} + +let Handler = +{ + construct( original, args ) + { + return ContainerAdapterNamespace.make( ... args ); + } +}; + +const Self = new Proxy( ContainerAdapterNamespace, Handler ); +Self.original = ContainerAdapterNamespace; +_.assert( _.containerAdapter === undefined ); +_.containerAdapter = Self; + +// -- +// container adapter extension +// -- + +let ContainerAdapterExtension = +{ + + is, + like, + isContainer, + setLike, + longLike, + +} + +Object.assign( _.containerAdapter, ContainerAdapterExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + is : is.bind( _.containerAdapter ), + like : like.bind( _.containerAdapter ), + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/ContainerAdapter.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ContainerAdapter_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ContainerAdapter_s */ })(); + +/* */ /* begin of file Countable_s */ ( function Countable_s() { function Countable_s_naked() { ( function _l1_Countable_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.countable = _.countable || Object.create( null ); + +// -- +// dichotomy +// -- + +/* qqq : for Junior : cover please */ +function is( src ) +{ + + if( _.arrayIs( src ) ) + return true; + + if( _.primitive.is( src ) ) + return false; + + // if( _.routine.like( _.class.methodIteratorOf( src ) ) ) + // if( !_.mapIs( src ) ) + if( _.class.methodIteratorOf( src ) !== undefined ) /* qqq : for Junior : cover please */ + return true; + + return false; +} + +// + +function like( src ) +{ + return _.countable.is( src ); +} + +// + +function isResizable( src ) +{ + if( _.array.is( src ) ) + return true; + return false; + // return this.is( src ); +} + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return this.default.IsResizable(); +} + +// -- +// maker +// -- + +function _makeEmpty( src ) +{ + if( arguments.length === 0 || src === null || _.long.is( src ) ) + return _.long._makeEmpty( ... arguments ); + return _.object.makeEmpty( ... arguments ); +} + +// + +/* qqq2 : for junior : cover please */ +function makeEmpty( src ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 ); + if( arguments.length === 1 ) + { + _.assert( this.like( src ) || _.routineIs( src ) ); + return this._makeEmpty( src ); + } + else + { + return this._makeEmpty(); + } +} + +// + +function _makeUndefined( src, length ) +{ + if( _.long.is( src ) ) + return _.long._makeUndefined( ... arguments ); + return _.object.makeUndefined( ... arguments ); +} + +// + +/* qqq2 : for junior : cover please */ +function makeUndefined( src, length ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + if( arguments.length === 2 ) + { + _.assert( src === null || _.long.is( src ) || _.routineIs( src ) ); + _.assert( _.numberIs( length ) || _.countable.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( src === null || _.numberIs( src ) || this.like( src ) || _.routineIs( src ) ); + } + return this._makeUndefined( ... arguments ); +} + +// + +function _makeZeroed( src, length ) +{ + if( _.long.is( src ) ) + return _.long._makeZeroed( ... arguments ); + return _.object.make( ... arguments ); +} + +// + +/* qqq2 : for junior : cover please */ +/* qqq : for junior : extend with test cases with countable in 2nd arg */ +function makeZeroed( src, length ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + if( arguments.length === 2 ) + { + _.assert( src === null || _.long.is( src ) || _.routineIs( src ) ); + _.assert( _.numberIs( length ) || _.countable.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( src === null || _.numberIs( src ) || this.like( src ) || _.routineIs( src ) ); + } + return this._makeZeroed( ... arguments ); +} + +// + +function _make( src, length ) +{ + if( _.long.is( src ) ) + return _.long._make( ... arguments ); + return _.object.make( ... arguments ); +} + +// + +/* qqq2 : for junior : full implementation and coverage are required */ +/* qqq : for junior : extend with test cases with countable in 2nd arg */ +function make( src, length ) +{ + _.assert( arguments.length <= 2 ); + if( arguments.length === 2 ) + { + _.assert( src === null || _.countable.is( src ) || _.routineIs( src ) ); + _.assert( _.numberIs( length ) || _.countable.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( src === null || _.numberIs( src ) || this.like( src ) || _.routineIs( src ) ); + } + return this._make( ... arguments ); +} + +// + +/* qqq2 : for junior : full implementation and coverage are required */ +function _cloneShallow( src ) +{ + if( _.long.is( src ) ) + return _.long._cloneShallow( src ); + return _.object.cloneShallow( src ); +} + +// + +function cloneShallow( srcArray ) +{ + _.assert( this.like( srcArray ) ); + _.assert( arguments.length === 1 ); + return this._cloneShallow( srcArray ); +} + +// + +function from( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + if( this.is( src ) ) + return src; + if( src === null ) + return this.make( null ); + return this.make( null, src ); +} + +// -- +// meta +// -- + +/* qqq : optimize */ +function namespaceOf( src ) +{ + if( !this.is( src ) ) + return null; + + let result = _.long.namespaceOf( src ); + if( result ) + return result; + + return this; +} + +// -- +// extension +// -- + +var ToolsExtension = +{ + + // dichotomy + + countableIs : is.bind( _.countable ), + countableLike : like.bind( _.countable ), + +} + +Object.assign( _, ToolsExtension ); + +// + +var CountableExtension = +{ + + // + + NamespaceName : 'countable', + NamespaceNames : [ 'countable' ], + NamespaceQname : 'wTools/countable', + MoreGeneralNamespaceName : 'countable', + MostGeneralNamespaceName : 'countable', + TypeName : 'Countable', + TypeNames : [ 'Countable' ], + // SecondTypeName : 'Countable', + InstanceConstructor : null, + tools : _, + + // dichotomy + + is, /* qqq : cover here and in the module::MathVector */ + like, /* qqq : cover here and in the module::MathVector */ + isResizable, + IsResizable, + + // maker + + _makeEmpty, + makeEmpty, /* qqq : for junior : cover */ + _makeUndefined, + makeUndefined, /* qqq : for junior : cover */ + _makeZeroed, + makeZeroed, /* qqq : for junior : cover */ + _make, + make, /* qqq : for junior : cover */ + _cloneShallow, + cloneShallow, /* qqq : for junior : cover */ + from, /* qqq : for junior : cover */ + + // meta + + namespaceOf, + namespaceWithDefaultOf : _.props.namespaceWithDefaultOf, + _functor_functor : _.props._functor_functor, + +} + +Object.assign( _.countable, CountableExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Countable.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Countable_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Countable_s */ })(); + +/* */ /* begin of file Ct_s */ ( function Ct_s() { function Ct_s_naked() { ( function _l1_Ct_s_() +{ + +'use strict'; + +// + +const _global = _global_; +const _ = _global_.wTools; +_.ct = _.ct || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// declare +// -- + +let Extension = +{ +} + +Object.assign( _.ct, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Ct.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Ct_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Ct_s */ })(); + +/* */ /* begin of file Date_s */ ( function Date_s() { function Date_s_naked() { ( function _l1_Date_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.date = _.date || Object.create( null ); + +// -- +// dichotomy +// -- + +function is( src ) +{ + return Object.prototype.toString.call( src ) === '[object Date]'; +} + +// + +function identicalShallow( src1, src2, o ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + + + if( !_.date.is( src1 ) ) + return false; + if( !_.date.is( src2 ) ) + return false; + + return _.date._identicalShallow( src1, src2 ); +} + +// + +function _identicalShallow( src1, src2 ) +{ + src1 = src1.getTime(); + src2 = src2.getTime(); + + return src1 === src2; +} + +// + +function exportStringDiagnosticShallow( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + _.assert( _.date.is( src ) ); + + return src.toISOString(); +} + +// + +function exportStringCodeShallow( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + _.assert( _.date.is( src ) ); + + return `new Date( '${src.toISOString()}' )`; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + dateIs : is, + datesAreIdentical : identicalShallow, +} + +// + +let Extension = +{ + is, + identicalShallow, + _identicalShallow, + areIdentical : identicalShallow, + equivalentShallow : identicalShallow, + + // exporter + + exportString : exportStringDiagnosticShallow, + // exportStringDiagnosticShallow : exportStringDiagnosticShallow, + exportStringCodeShallow, + exportStringDiagnosticShallow, + // exportStringDiagnostic : exportStringDiagnosticShallow, + // exportStringCode : exportStringCodeShallow +} + +// + +Object.assign( _, ToolsExtension ); +Object.assign( _.date, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Date.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Date_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Date_s */ })(); + +/* */ /* begin of file Entity_s */ ( function Entity_s() { function Entity_s_naked() { ( function _l1_Entity_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.entity = _.entity || Object.create( null ); + +// -- +// dichotomy +// -- + +function is( src ) +{ + return true; +} + +// + +function like( src ) +{ + return _.entity.is( src ); +} + +// -- +// exporter +// -- + +function strPrimitive( src ) +{ + let result = ''; + + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + + if( src === null || src === undefined ) + return; + + if( _.primitive.is( src ) ) + return String( src ); + + return; +} + +// + +/** + * Return primitive type of src. + * + * @example + * let str = _.entity.strTypeSecondary( 'testing' ); + * + * @param {*} src + * + * @return {string} + * string name of type src + * @function strTypeSecondary + * @namespace Tools + */ + +function strTypeSecondary( src ) +{ + + let name = Object.prototype.toString.call( src ); + let result = /\[(\w+) (\w+)\]/.exec( name ); + _.assert( !!result, 'unknown type', name ); + return result[ 2 ]; +} + +// + +/** + * Return type of src. + * + * @example + * let str = _.entity.strType( 'testing' ); + * + * @param {*} src + * + * @return {string} + * string name of type src + * @function strType + * @namespace Tools + */ + +/* qqq for junior : jsdoc */ +/* xxx : optimize later */ +/* xxx : move to namesapce type? */ +function strTypeWithTraits( src ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.aux.is( src ) ) + { + + if( _.mapIsPure( src ) ) + return end( 'Map.pure' ); + else if( _.mapIsPolluted( src ) ) + return end( 'Map.polluted' ); + else if( _.aux.isPure( src ) && _.aux.isPrototyped( src ) ) + return end( 'Aux.pure.prototyped' ); + else if( _.aux.isPolluted( src ) && _.aux.isPrototyped( src ) ) + return end( 'Aux.polluted.prototyped' ); + else _.assert( 0, 'undexpected' ); + + } + + if( _.primitive.is( src ) ) + return end( _.entity.strTypeSecondary( src ) ); + + let proto = Object.getPrototypeOf( src ); + if( proto && proto.constructor && proto.constructor !== Object && proto.constructor.name ) + return end( proto.constructor.name ); + + return end( _.entity.strTypeSecondary( src ) ); + + function end( result ) + { + let translated = _.entity.TranslatedTypeMap[ result ]; + if( translated ) + result = translated; + + if( !_.entity.StandardTypeSet.has( result ) ) + { + if( _.countableIs( src ) ) + result += '.countable'; + if( _.constructibleIs( src ) ) + result += '.constructible'; + } + + return result; + } + +} + +// + +/* qqq for junior : jsdoc */ +function strTypeWithoutTraits( src ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.aux.is( src ) ) + { + if( _.mapIs( src ) ) + return 'Map'; + else + return 'Aux'; + } + + if( _.primitive.is( src ) ) + return end( _.entity.strTypeSecondary( src ) ); + + let proto = Object.getPrototypeOf( src ); + if( proto && proto.constructor && proto.constructor !== Object && proto.constructor.name ) + return end( proto.constructor.name ); + + return end( _.entity.strTypeSecondary( src ) ); + + function end( result ) + { + let translated = _.entity.TranslatedTypeMap[ result ]; + if( translated ) + result = translated; + return result; + } + +} + +// -- +// meta +// -- + +function namespaceForIterating( src ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 1 ); + + if( src === undefined ) + return _.blank; + if( _.primitive.is( src ) ) + return _.itself; + if( _.hashMap.like( src ) ) + return _.hashMap; + if( _.set.like( src ) ) + return _.set; + if( _.long.is( src ) ) + return _.long; + if( _.buffer.like( src ) ) + return _.buffer; + if( _.countable.is( src ) ) + return _.object; + if( _.aux.is( src ) ) + return _.aux; + if( _.object.is( src ) ) + return _.object; + + return _.props; +} + +// -- +// entity extension +// -- + +let TranslatedTypeMap = +{ + + 'BigUint64Array' : 'U64x', + 'Uint32Array' : 'U32x', + 'Uint16Array' : 'U16x', + 'Uint8Array' : 'U8x', + 'Uint8ClampedArray' : 'U8xClamped', + + 'BigInt64Array' : 'I64x', + 'Int32Array' : 'I32x', + 'Int16Array' : 'I16x', + 'Int8Array' : 'I8x', + + 'Float64Array' : 'F64x', + 'Float32Array' : 'F32x', + + 'Buffer' : 'BufferNode', + 'ArrayBuffer' : 'BufferRaw', + 'SharedArrayBuffer' : 'BufferRawShared', + 'Map' : 'HashMap', + 'WeakMap' : 'HashMapWeak', + 'Function' : 'Routine', + 'Arguments' : 'ArgumentsArray', + +} + +let StandardTypeSet = new Set +([ + + 'U64x', + 'U32x', + 'U16x', + 'U8x', + 'U8xClamped', + 'I64x', + 'I32x', + 'I16x', + 'I8x', + 'F64x', + 'F32x', + + 'BufferNode', + 'BufferRaw', + 'BufferRawShared', + 'HashMap', + 'HashMapWeak', + + 'ArgumentsArray', + 'Array', + 'Set', + 'Routine', + 'Global', + +]); + +// + +let EntityExtension = +{ + + // fields + + NamespaceName : 'entity', + NamespaceNames : [ 'entity' ], + NamespaceQname : 'wTools/entity', + TypeName : 'Entity', + TypeNames : [ 'Entity' ], + // SecondTypeName : 'Entity', + InstanceConstructor : null, + tools : _, + TranslatedTypeMap, + StandardTypeSet, + + // dichotmoy + + is, + like, + + // maker + + // _cloneShallow : _.container._cloneShallow, /* xxx : implement? */ + cloneShallow : _.container.cloneShallow, /* qqq : cover */ + // _make : _.container._make, /* qqq : implement */ + make : _.container.make, /* xxx : implement? */ + // _makeEmpty : _.container._makeEmpty, /* qqq : implement */ + makeEmpty : _.container.makeEmpty, /* xxx : implement? */ + // _makeUndefined : _.container._makeUndefined, /* qqq : implement */ + makeUndefined : _.container.makeUndefined, /* xxx : implement? */ + + // exporter + + strPrimitive, + strTypeSecondary, + strType : strTypeWithTraits, + strTypeWithTraits, + strTypeWithoutTraits, + + // meta + + namespaceForIterating, + namespaceForExporting : _.container.namespaceForExporting, + namespaceOf : namespaceForIterating, + namespaceWithDefaultOf : _.props.namespaceWithDefaultOf, + _functor_functor : _.props._functor_functor, + +} + +// + +Object.assign( _.entity, EntityExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + entityIs : is.bind( _.entity ), + entityLike : like.bind( _.entity ), + + strType : strTypeWithTraits, + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Entity.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Entity_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Entity_s */ })(); + +/* */ /* begin of file Escape_s */ ( function Escape_s() { function Escape_s_naked() { ( function _l1_Escape_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.escape = _.escape || Object.create( null ); + +// -- +// implement +// -- + +// -- +// declare +// -- + +var Extension = +{ +} + +Object.assign( _.escape, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Escape.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Escape_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Escape_s */ })(); + +/* */ /* begin of file Event_s */ ( function Event_s() { function Event_s_naked() { ( function _l1_Event_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.event = _.event || Object.create( null ); + +// -- +// +// -- + + +// -- +// declare +// -- + +let Extension = +{ +}; + +Object.assign( _.event, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Event.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Event_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Event_s */ })(); + +/* */ /* begin of file Functional_s */ ( function Functional_s() { function Functional_s_naked() { ( function _l1_Functional_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// declaration +// -- + +let ToolsExtension = +{ +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Functional.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Functional_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Functional_s */ })(); + +/* */ /* begin of file Functor_s */ ( function Functor_s() { function Functor_s_naked() { ( function _l1_Functor_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.functor = _.functor || Object.create( null ); + +// -- +// implementation +// -- + +/* +qqq : for Dmytro : add support and coverage of Set. discuss +*/ + +function vectorize_head( routine, args ) +{ + let o = args[ 0 ]; + + if( args.length === 2 ) + o = { routine : args[ 0 ], select : args[ 1 ] } + else if( _.routine.is( o ) || _.strIs( o ) ) + o = { routine : args[ 0 ] } + + _.routine.options( routine, o ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.routine.is( o.routine ) || _.strIs( o.routine ) || _.strsAreAll( o.routine ), () => 'Expects routine {-o.routine-}, but got ' + o.routine ); + _.assert( args.length === 1 || args.length === 2 ); + _.assert( o.select >= 1 || _.strIs( o.select ) || _.argumentsArray.like( o.select ), () => 'Expects {-o.select-} as number >= 1, string or array, but got ' + o.select ); + + return o; +} + +function vectorize_body( o ) +{ + + _.routine.assertOptions( vectorize_body, arguments ); + + if( _.argumentsArray.like( o.routine ) && o.routine.length === 1 ) + o.routine = o.routine[ 0 ]; + + let routine = o.routine; + let propertyCondition = o.propertyCondition; + let bypassingFilteredOut = o.bypassingFilteredOut; + let bypassingEmpty = o.bypassingEmpty; + let vectorizingArray = o.vectorizingArray; + let vectorizingMapVals = o.vectorizingMapVals; + let vectorizingMapKeys = o.vectorizingMapKeys; + let vectorizingContainerAdapter = o.vectorizingContainerAdapter; + let unwrapingContainerAdapter = o.unwrapingContainerAdapter; + let head = null; + let select = o.select === null ? 1 : o.select; + let selectAll = o.select === Infinity; + let multiply = select > 1 ? multiplyReally : multiplyNo; + + routine = routineNormalize( routine ); + + _.assert( _.routine.is( routine ), () => 'Expects routine {-o.routine-}, but got ' + routine ); + + /* */ + + let resultRoutine = vectorizeArray; + + if( _.number.is( select ) ) + { + + if( !vectorizingArray && !vectorizingMapVals && !vectorizingMapKeys ) + resultRoutine = routine; + else if( propertyCondition ) + resultRoutine = vectorizeWithFilters; + else if( vectorizingMapKeys ) + { + + if( vectorizingMapVals ) + { + _.assert( select === 1, 'Only single argument is allowed if {-o.vectorizingMapKeys-} and {-o.vectorizingMapVals-} are enabled.' ); + resultRoutine = vectorizeMapWithKeysOrArray; + } + else + { + resultRoutine = vectorizeKeysOrArray; + } + + } + else if( !vectorizingArray || vectorizingMapVals ) + resultRoutine = vectorizeMapOrArray; + else if( multiply === multiplyNo ) + resultRoutine = vectorizeArray; + else + resultRoutine = vectorizeArrayMultiplying; + + } + else + { + _.assert( multiply === multiplyNo ); + if( routine.head ) + { + head = routine.head; + routine = routine.body; + } + if( propertyCondition ) + { + _.assert( 0, 'not implemented' ); + } + else if( vectorizingArray || !vectorizingMapVals ) + { + if( _.strIs( select ) ) + resultRoutine = vectorizeForOptionsMap; + else + resultRoutine = vectorizeForOptionsMapForKeys; + } + else _.assert( 0, 'not implemented' ); + } + + /* */ + + resultRoutine.vectorized = o; + + /* */ + + _.routine.extend( resultRoutine, routine ); + return resultRoutine; + + /* + vectorizeWithFilters : multiply + array/map vectorizing + filter + vectorizeArray : array vectorizing + vectorizeArrayMultiplying : multiply + array vectorizing + vectorizeMapOrArray : multiply + array/map vectorizing + */ + + /* - */ + + function routineNormalize( routine ) + { + + if( _.strIs( routine ) ) + { + return function methodCall() + { + _.assert( _.routine.is( this[ routine ] ), () => 'Context ' + _.entity.exportStringDiagnosticShallow( this ) + ' does not have routine ' + routine ); + return this[ routine ].apply( this, arguments ); + } + } + else if( _.argumentsArray.like( routine ) ) + { + _.assert( routine.length === 2 ); + return function methodCall() + { + let c = this[ routine[ 0 ] ]; + _.assert( _.routine.is( c[ routine[ 1 ] ] ), () => 'Context ' + _.entity.exportStringDiagnosticShallow( c ) + ' does not have routine ' + routine ); + return c[ routine[ 1 ] ].apply( c, arguments ); + } + } + + return routine; + } + + /* - */ + + function multiplyNo( args ) + { + return args; + } + + /* - */ + + function multiplyReally( args ) + { + let length, keys; + + args = [ ... args ]; + + if( selectAll ) + select = args.length; + + _.assert( args.length === select, () => 'Expects ' + select + ' arguments, but got ' + args.length ); + + for( let d = 0 ; d < select ; d++ ) + { + if( vectorizingArray && _.argumentsArray.like( args[ d ] ) ) + { + length = args[ d ].length; + break; + } + else if( vectorizingArray && _.set.like( args[ d ] ) ) + { + length = args[ d ].size; + break; + } + else if( vectorizingContainerAdapter && _.containerAdapter.is( args[ d ] ) ) + { + length = args[ d ].length; + break; + } + else if( vectorizingMapVals && _.aux.is( args[ d ] ) ) + { + keys = _.props.onlyOwnKeys( args[ d ] ); + break; + } + } + + if( length !== undefined ) + { + for( let d = 0 ; d < select ; d++ ) + { + if( vectorizingMapVals ) + _.assert( !_.mapIs( args[ d ] ), () => 'Arguments should have only arrays or only maps, but not both. Incorrect argument : ' + args[ d ] ); + else if( vectorizingMapKeys && _.mapIs( args[ d ] ) ) + continue; + args[ d ] = _.multiple( args[ d ], length ); + } + + } + else if( keys !== undefined ) + { + for( let d = 0 ; d < select ; d++ ) + if( _.mapIs( args[ d ] ) ) + { + _.assert( _.arraySet.identical( _.props.onlyOwnKeys( args[ d ] ), keys ), () => 'Maps should have same keys : ' + keys ); + } + else + { + if( vectorizingArray ) + _.assert( !_.argumentsArray.like( args[ d ] ), () => 'Arguments should have only arrays or only maps, but not both. Incorrect argument : ' + args[ d ] ); + let arg = Object.create( null ); + _.mapSetWithKeys( arg, keys, args[ d ] ); + args[ d ] = arg; + } + } + + return args; + } + + /* - */ + + function vectorizeArray() + { + if( bypassingEmpty && !arguments.length ) + return []; + + let args = arguments; + let src = args[ 0 ]; + + if( _.arrayIs( src ) ) /* Dmytro : arrayLike returns true for instances of containerAdapter */ + { + let args2 = [ ... args ]; + let result = _.long.makeEmpty( src ); + let append = _.long.appender( result ); + let each = _.long.eacher( src ); + each( ( e ) => + { + args2[ 0 ] = e; + append( routine.apply( this, args2 ) ); + }); + return result; + } + else if( _.set.like( src ) ) /* qqq : cover please */ + { + let args2 = [ ... args ]; + let result = new Set; + for( let e of src ) + { + args2[ 0 ] = e; + result.add( routine.apply( this, args2 ) ); + } + return result; + } + else if( vectorizingContainerAdapter && _.containerAdapter.is( src ) ) + { + let args2 = [ ... args ]; + let result = src.filter( ( e ) => + { + args2[ 0 ] = e; + return routine.apply( this, args2 ); + }); + if( unwrapingContainerAdapter ) + return result.original; + else + return result; + } + + return routine.apply( this, args ); + } + + /* - */ + + function vectorizeArrayMultiplying() + { + if( bypassingEmpty && !arguments.length ) + return []; + + let args = multiply( arguments ); + let src = args[ 0 ]; + + if( _.argumentsArray.like( src ) ) + { + + let args2 = [ ... args ]; + let result = _.long.makeEmpty( src ); + let append = _.long.appender( result ); + let each = _.long.eacher( src ); + each( ( e, r ) => + { + for( let m = 0 ; m < select ; m++ ) + args2[ m ] = args[ m ][ r ]; /* zzz qqq : use _.long.get */ + append( routine.apply( this, args2 ) ); + }); + return result; + } + + return routine.apply( this, args ); + } + + /* - */ + + function vectorizeForOptionsMap( srcMap ) + { + if( bypassingEmpty && !arguments.length ) + return []; + + let src = srcMap[ select ]; + let args = [ ... arguments ]; + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.argumentsArray.like( src ) ) + { + if( head ) + { + args = head( routine, args ); + _.assert( _.arrayLikeResizable( args ) ); + } + + let result = _.long.makeEmpty( src ); + let append = _.long.appender( result ); + let each = _.long.eacher( src ); + each( ( e ) => + { + args[ 0 ] = _.props.extend( null, srcMap ); + args[ 0 ][ select ] = e; + append( routine.apply( this, args ) ); + }); + return result; + + } + else if( _.set.like( src ) ) /* qqq : cover */ + { + if( head ) + { + args = head( routine, args ); + _.assert( _.arrayLikeResizable( args ) ); + } + let result = new Set; + for( let e of src ) + { + args[ 0 ] = _.props.extend( null, srcMap ); + args[ 0 ][ select ] = e; + result.add( routine.apply( this, args ) ); + } + return result; + } + else if( vectorizingContainerAdapter && _.containerAdapter.is( src ) ) /* qqq : cover */ + { + if( head ) + { + args = head( routine, args ); + _.assert( _.arrayLikeResizable( args ) ); + } + result = src.filter( ( e ) => + { + args[ 0 ] = _.props.extend( null, srcMap ); + args[ 0 ][ select ] = e; + return routine.apply( this, args ); + }); + if( unwrapingContainerAdapter ) + return result.original; + else + return result; + } + + return routine.apply( this, arguments ); + } + + /* - */ + + function vectorizeForOptionsMapForKeys() + { + let result = []; + + if( bypassingEmpty && !arguments.length ) + return result; + + for( let i = 0; i < o.select.length; i++ ) + { + select = o.select[ i ]; + result[ i ] = vectorizeForOptionsMap.apply( this, arguments ); + } + return result; + } + + /* - */ + + function vectorizeMapOrArray() + { + if( bypassingEmpty && !arguments.length ) + return []; + + let args = multiply( arguments ); + let src = args[ 0 ]; + + if( vectorizingArray && _.argumentsArray.like( src ) ) + { + + let args2 = [ ... args ]; + let result = _.long.makeEmpty( src ); + let append = _.long.appender( result ); + let each = _.long.eacher( src ); + each( ( e, r ) => + { + + for( let m = 0 ; m < select ; m++ ) + args2[ m ] = args[ m ][ r ]; /* qqq zzz : use _.long.get? */ + + append( routine.apply( this, args2 ) ); + }); + return result; + } + else if( vectorizingMapVals && _.mapIs( src ) ) + { + let args2 = [ ... args ]; + let result = Object.create( null ); + for( let r in src ) + { + for( let m = 0 ; m < select ; m++ ) + args2[ m ] = args[ m ][ r ]; + + result[ r ] = routine.apply( this, args2 ); + } + return result; + } + + return routine.apply( this, arguments ); + } + + /* - */ + + function vectorizeMapWithKeysOrArray() + { + if( bypassingEmpty && !arguments.length ) + return []; + + let args = multiply( arguments ); + let srcs = args[ 0 ]; + + _.assert( args.length === select, () => 'Expects ' + select + ' arguments but got : ' + args.length ); + + if( vectorizingMapKeys && vectorizingMapVals &&_.mapIs( srcs ) ) + { + let result = Object.create( null ); + for( let s in srcs ) + { + let val = routine.call( this, srcs[ s ] ); + let key = routine.call( this, s ); + result[ key ] = val; + } + return result; + } + else if( vectorizingArray && _.argumentsArray.like( srcs ) ) + { + let result = []; + for( let s = 0 ; s < srcs.length ; s++ ) + result[ s ] = routine.call( this, srcs[ s ] ); + return result; + } + + return routine.apply( this, arguments ); + } + + /* - */ + + function vectorizeWithFilters( src ) + { + + _.assert( 0, 'not tested' ); /* qqq : cover please */ + _.assert( arguments.length === 1, 'Expects single argument' ); + + let args = multiply( arguments ); + + if( vectorizingArray && _.argumentsArray.like( src ) ) + { + args = [ ... args ]; + throw _.err( 'not tested' ); /* cover please */ + + let result = _.long.makeEmpty( src ); + let append = _.long.appender( result ); + let each = _.long.eacher( src ); + each( ( e, r ) => + { + if( propertyCondition( e, r, src ) ) + { + args[ 0 ] = e; + append( routine.apply( this, args ) ); + } + else if( bypassingFilteredOut ) + { + append( e ); + } + + args2[ 0 ] = e; + append( routine.apply( this, args2 ) ); + }); + return result; + + } + else if( vectorizingMapVals && _.mapIs( src ) ) + { + args = [ ... args ]; + let result = Object.create( null ); + throw _.err( 'not tested' ); /* qqq : cover please */ + for( let r in src ) + { + if( propertyCondition( src[ r ], r, src ) ) + { + args[ 0 ] = src[ r ]; + result[ r ] = routine.apply( this, args ); + } + else if( bypassingFilteredOut ) + { + result[ r ] = src[ r ]; + } + } + return result; + } + + return routine.call( this, src ); + } + + /* - */ + + function vectorizeKeysOrArray() + { + if( bypassingEmpty && !arguments.length ) + return []; + + // let args = multiply( _.originalsFromAdaptersInplace( arguments ) ); + let args = multiply( arguments ); + let src = args[ 0 ]; + let args2, result, map, mapIndex, arr; + + _.assert( args.length === select, () => 'Expects ' + select + ' arguments but got : ' + args.length ); + + if( vectorizingMapKeys ) + { + for( let d = 0; d < select; d++ ) + { + if( vectorizingArray && _.argumentsArray.like( args[ d ] ) ) + arr = args[ d ]; + else if( _.mapIs( args[ d ] ) ) + { + _.assert( map === undefined, () => 'Arguments should have only single map. Incorrect argument : ' + args[ d ] ); + map = args[ d ]; + mapIndex = d; + } + } + } + + if( map ) + { + result = Object.create( null ); + args2 = [ ... args ]; + + if( vectorizingArray && _.argumentsArray.like( arr ) ) + { + for( let i = 0; i < arr.length; i++ ) + { + for( let m = 0 ; m < select ; m++ ) + args2[ m ] = args[ m ][ i ]; + + for( let k in map ) + { + args2[ mapIndex ] = k; + let key = routine.apply( this, args2 ); + result[ key ] = map[ k ]; + } + } + } + else + { + for( let k in map ) + { + args2[ mapIndex ] = k; + let key = routine.apply( this, args2 ); + result[ key ] = map[ k ]; + } + } + + return result; + } + else if( vectorizingArray && _.argumentsArray.like( src ) ) + { + + let args2 = [ ... args ]; + let result = _.long.makeEmpty( src ); + let append = _.long.appender( result ); + let each = _.long.eacher( src ); + each( ( e, r ) => + { + for( let m = 0 ; m < select ; m++ ) + args2[ m ] = args[ m ][ r ]; /* qqq zzz : use _.long.get */ + append( routine.apply( this, args2 ) ); + }); + return result; + + } + + return routine.apply( this, arguments ); + } + +} + +/* qqq : implement options combination vectorizingMapVals : 1, vectorizingMapKeys : 1, vectorizingArray : [ 0, 1 ] */ +/* qqq : cover it */ + +/* qqq : implement bypassingEmpty for all combinations of options */ +/* qqq : options bypassingEmpty of routine _.vectorize requires good coverage */ + +vectorize_body.defaults = +{ + routine : null, + propertyCondition : null, + bypassingFilteredOut : 1, + bypassingEmpty : 0, + vectorizingArray : 1, /* xxx : review : add option vectorizingCountable : 1. discuss */ + vectorizingMapVals : 0, + vectorizingMapKeys : 0, + vectorizingContainerAdapter : 0, + unwrapingContainerAdapter : 0, + select : 1, +} + +// + +function vectorize() +{ + let o = vectorize.head.call( this, vectorize, arguments ); + let result = vectorize.body.call( this, o ); + return result; +} + +vectorize.head = vectorize_head; +vectorize.body = vectorize_body; +vectorize.defaults = { ... vectorize_body.defaults }; + +// + +function vectorizeAll_body( o ) +{ + _.routine.assertOptions( vectorize, arguments ); + + let routine1 = _.vectorize.body.call( this, o ); + + _.routine.extend( all, o.routine ); + + return all; + + function all() + { + let result = routine1.apply( this, arguments ); + return _.all( result ); + } + +} + +vectorizeAll_body.defaults = { ... vectorize_body.defaults }; + +// + +function vectorizeAll() +{ + let o = vectorizeAll.head.call( this, vectorizeAll, arguments ); + let result = vectorizeAll.body.call( this, o ); + return result; +} + +vectorizeAll.head = vectorize_head; +vectorizeAll.body = vectorizeAll_body; +vectorizeAll.defaults = { ... vectorizeAll_body.defaults }; + +// + +function vectorizeAny_body( o ) +{ + _.routine.assertOptions( vectorize, arguments ); + + let routine1 = _.vectorize.body.call( this, o ); + _.routine.extend( any, o.routine ); + + return any; + + function any() + { + let result = routine1.apply( this, arguments ); + return !!_.any( result ); + } + +} + +vectorizeAny_body.defaults = { ... vectorize_body.defaults }; + +// + +function vectorizeAny() +{ + let o = vectorizeAny.head.call( this, vectorizeAny, arguments ); + let result = vectorizeAny.body.call( this, o ); + return result; +} + +vectorizeAny.head = vectorize_head; +vectorizeAny.body = vectorizeAny_body; +vectorizeAny.defaults = { ... vectorizeAny_body.defaults }; + +// + +function vectorizeNone_body( o ) +{ + _.routine.assertOptions( vectorize, arguments ); + + let routine1 = _.vectorize.body.call( this, o ); + _.routine.extend( none, o.routine ); + + return none; + + function none() + { + let result = routine1.apply( this, arguments ); + return _.none( result ); + } + +} + +vectorizeNone_body.defaults = { ... vectorize_body.defaults }; + +// + +function vectorizeNone() +{ + let o = vectorizeNone.head.call( this, vectorizeNone, arguments ); + let result = vectorizeNone.body.call( this, o ); + return result; +} + +vectorizeNone.head = vectorize_head; +vectorizeNone.body = vectorizeNone_body; +vectorizeNone.defaults = { ... vectorizeNone_body.defaults }; + +// + +/** + * The routine vectorizeAccess() creates proxy object for each element of passed vector {-vector-}. + * Proxy object provides access to existed properties of {-vector-} elements uses only get() + * and set() handlers. + * If get() handler is used, then routine returns new proxy object with vector of property values. + * If a property is a routine, then its routines can be applied to a set of arguments. The result is + * a new proxy with vector of returned values. + * To get original vector uses property `$`. + * If set() handler is used, then property of each proxy element is assigned to one value. + * + * @param { Long } vector - The vector of objects and vectors to get proxy access to properties. + * + * @example + * let obj1 = { a : 1, b : 2, c : 3 }; + * let obj2 = { a : 5, b : 6 }; + * let vector = _.vectorizeAccess( [ obj1, obj2 ] ); + * console.log( vector ); + * // log Proxy [ + * // [ { a : 1, b : 2, c : 3 }, { a : 5, b : 6 } ], + * // { get: [Function: get], set: [Function: set] } + * // ] + * console.log( vector[ '$' ] ); + * // log [ { a : 1, b : 2, c : 3 }, { a : 5, b : 6 } ] + * let vectorA = vector.a; // or vector[ 'a' ] + * console.log( vectorA ); + * // log Proxy [ [ 1, 5 ], { get: [Function: get], set: [Function: set] } ] + * + * @example + * let cb1 = ( e ) => Math.pow( e, 2 ); + * let cb2 = ( e ) => Math.sqrt( e, 2 ); + * let obj1 = { callback : cb1, name : 'obj1' }; + * let obj2 = { callback : cb2, name : 'obj2' }; + * let vector = _.vectorizeAccess( [ obj1, obj2 ] ); + * let result = vector.callback( 4 ); + * console.log( result ); + * // log Proxy [ [ 16, 2 ], { get: [Function: get], set: [Function: set] } ] + * + * @example + * let v1 = [ 1, 2, 3 ]; + * let v2 = [ 5, 6 ]; + * let vector = _.vectorizeAccess( [ v1, v2 ] ); + * vector[ 1 ] = 10; + * console.log( vector[ '$' ] ); + * // log [ [ 1, 10, 3 ], [ 5, 10 ] ] + * + * @returns { Proxy } - Proxy object, which provides access to existed properties in elements of vector. + * @function vectorizeAccess + * @throws { Error } If arguments.length is less or more then one. + * @throws { Error } If {-vector-} is not a Long. + * @namespace Tools + */ + +function vectorizeAccess( vector ) +{ + + _.assert( _.longIs( vector ) ); + _.assert( arguments.length === 1 ); + + let handler = + { + get, + set, + }; + + let proxy = new Proxy( vector, handler ); + + return proxy; + + /* */ + + function set( /* back, key, val, context */ ) + { + let back = arguments[ 0 ]; + let key = arguments[ 1 ]; + let val = arguments[ 2 ]; + let context = arguments[ 3 ]; + + vector.map( ( scalar ) => + { + _.assert( scalar[ key ] !== undefined, `One or several element(s) of vector does not have ${key}` ); + }); + + vector.map( ( scalar ) => + { + scalar[ key ] = val; + }); + + return true; + } + + /* */ + + function get( back, key, context ) + { + if( key === '$' ) + { + return vector; + } + + let routineIs = vector.some( ( scalar ) => _.routine.is( scalar[ key ] ) ); + + if( !routineIs ) + if( _.all( vector, ( scalar ) => scalar[ key ] === undefined ) ) + return; + + vector.map( ( scalar ) => + { + _.assert( scalar[ key ] !== undefined, `One or several element(s) of vector does not have ${String( key )}` ); + }); + + if( routineIs ) + return function() + { + let self = this; + let args = arguments; + let revectorizing = false; + let result = vector.map( ( scalar ) => + { + let r = scalar[ key ].apply( scalar, args ); + if( r !== scalar ) + revectorizing = true; + return r; // Dmytro : it returns result in vector, if it not exists, then result has only undefined => [ undefined, undefined, undefined ] + }); + if( revectorizing ) + { + return vectorizeAccess( result ); + } + else + { + return proxy; + } + } + + let result = vector.map( ( scalar ) => + { + return scalar[ key ]; + }); + + return vectorizeAccess( result ); + } + +} + +// -- +// implementation +// -- + +let ToolsExtension = +{ + + routineVectorize_functor : vectorize, + vectorize, + vectorizeAll, + vectorizeAny, + vectorizeNone, + + vectorizeAccess, + +} + +Object.assign( _, ToolsExtension ); + +// + +let FunctorExtension = +{ + + vectorize, + vectorizeAll, + vectorizeAny, + vectorizeNone, + + vectorizeAccess, + +} + +Object.assign( _.functor, FunctorExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Functor.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Functor_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Functor_s */ })(); + +/* */ /* begin of file Fuzzy_s */ ( function Fuzzy_s() { function Fuzzy_s_naked() { ( function _l1_Fuzzy_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.fuzzy = _.fuzzy || Object.create( null ); + +// -- +// fuzzy +// -- + +/** + * Returns true if entity ( src ) is a Boolean values - true and false or Symbol(maybe). + * @function is + * @param { * } src - An entity to check. + * @namespace Tools + * + * @example + * var got = _.fuzzy.is( true ); + * console.log( got ) + * // log true + * + * @example + * var got = _.fuzzy.is( false ); + * console.log( got ) + * // log true + * + * @example + * var got = _.fuzzy.is( _.maybe ); + * console.log( got ) + * // log true + * + * @example + * var got = _.fuzzy.is( '1' ); + * console.log( got ) + * // log false + * + */ + +function is( src ) +{ + return src === true || src === false || src === _.maybe; +} + +// + +/** + * Returns true if entity ( src ) is a Boolean or a Number or Symbol(maybe). + * @function fuzzyLike + * @param { * } src - An entity to check. + * @namespace Tools + * + * @example + * var got = _.fuzzy.like( true ); + * console.log( got ) + * // log true + * + * @example + * var got = _.fuzzy.like( false ); + * console.log( got ) + * // log true + * + * @example + * var got = _.fuzzy.like( _.maybe ); + * console.log( got ) + * // log true + * + * @example + * var got = _.fuzzy.like( 1 ); + * console.log( got ) + * // log true + * + * @example + * var got = _.fuzzy.like( '1' ); + * console.log( got ) + * // log false + */ + +function like( src ) +{ + if( src === _.maybe ) + return true; + return src === true || src === false || src === 0 || src === 1; + // let type = Object.prototype.toString.call( src ); + // return type === '[object Boolean]' || type === '[object Number]'; +} + +// + +/** + * Returns true if entity ( src ) is false or 0. + * @function likeFalse + * @param { * } src - An entity to check. + * @namespace Tools + * + * @example + * var got = _.fuzzy.likeFalse( true ); + * console.log( got ) + * // log false + * + * @example + * var got = _.fuzzy.likeFalse( false ); + * console.log( got ) + * // log true + * + * @example + * var got = _.fuzzy.likeFalse( _.maybe ); + * console.log( got ) + * // log false + * + * @example + * var got = _.fuzzy.likeFalse( 0 ); + * console.log( got ) + * // log true + * + * @example + * var got = _.fuzzy.likeFalse( '1' ); + * console.log( got ) + * // log false + * + */ + +function likeFalse( src ) +{ + if( !_.fuzzy.like( src ) ) + return false; + return !src; +} + +// + +/** + * Returns true if entity ( src ) is true or a Number which is not 0. + * @function likeTrue + * @param { * } src - An entity to check. + * @namespace Tools + * + * @example + * var got = _.fuzzy.likeTrue( true ); + * console.log( got ) + * // log true + * + * @example + * var got = _.fuzzy.likeTrue( false ); + * console.log( got ) + * // log false + * + * @example + * var got = _.fuzzy.likeTrue( _.maybe ); + * console.log( got ) + * // log true + * + * @example + * var got = _.fuzzy.likeTrue( 0 ); + * console.log( got ) + * // log false + * + * @example + * var got = _.fuzzy.likeTrue( 10 ); + * console.log( got ) + * // log true + * + */ + +function likeTrue( src ) +{ + if( !_.fuzzy.like( src ) ) + return false; + if( src === _.maybe ) + return false; + return !!src; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + + fuzzyIs : is, + fuzzyLike : like, + fuzzyLikeFalse : likeFalse, + fuzzyLikeTrue : likeTrue, + +} + +// + +let Extension = +{ + + is, + like, + likeFalse, + likeTrue, + +} + +Object.assign( _, ToolsExtension ); +Object.assign( _.fuzzy, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Fuzzy.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Fuzzy_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Fuzzy_s */ })(); + +/* */ /* begin of file Global_s */ ( function Global_s() { function Global_s_naked() { ( function _l1_Global_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const __ = _realGlobal_.wTools; +const Self = _.global = _.global || Object.create( null ); + +// -- +// implementation +// -- + +/* xxx : qqq : for junior : dicuss tests */ +function is( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.primitive.is( src ) ) + return false; + + // if( src === _global_ ) + // return true; + + if( _.prototype.has( src, _global_ ) ) + return true; + + return false; +} + +// + +function isReal( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + // if( _.primitive.is( src ) ) + // return false; + + if( src === _realGlobal_ ) + return true; + return false; +} + +// + +function isDerivative( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + // if( _.primitive.is( src ) ) + // return false; + + if( _.global.is( src ) && !_.global.isReal( src ) ) + return true; + return false; +} + +// -- +// extension +// -- + +var Extension = +{ + + is, + isReal, + isDerivative, + + get : __.global.get, + new : __.global.new, + open : __.global.open, + close : __.global.close, + openForChildren : __.global.openForChildren, + closeForChildren : __.global.closeForChildren, + setup : __.global.setup, + + _stack : __.global._stack, + +} + +// + +Object.assign( _.global, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Global.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Global_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Global_s */ })(); + +/* */ /* begin of file HashMap_s */ ( function HashMap_s() { function HashMap_s_naked() { ( function _l1_HashMap_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.hashMap = _.hashMap || Object.create( null ); + +// -- +// dichotomy +// -- + +function is( src ) +{ + if( !src ) + return false; + return src instanceof HashMap || src instanceof HashMapWeak; +} + +// + +function like( src ) +{ + return _.hashMap.is( src ); +} + +// + +function isEmpty() +{ + if( !this.like( src ) ) + return false; + return !src.size; +} + +// + +function isPopulated() +{ + if( !this.like( src ) ) + return false; + return !!src.size; +} + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return true; +} + +// -- +// maker +// -- + +function _makeEmpty( src ) +{ + return new HashMap(); +} + +// + +function makeEmpty( src ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 ); + if( arguments.length === 1 ) + _.assert( this.like( src ) ); + return new HashMap(); +} + +// + +function _makeUndefined( src, length ) +{ + return new HashMap(); +} + +// + +function makeUndefined( src, length ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + + if( arguments.length === 2 ) + { + _.assert( this.like( src ) ); + _.assert( _.number.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( _.number.is( src ) || this.like( src ) ); + } + + return new HashMap(); +} + +// + +function _make( src, length ) +{ + let result = new HashMap(); + if( src && length !== 0 ) + { + if( _.hashMap.is( src ) ) + for( let [ key, val ] of src ) + result.set( key, val ); + else if( _.aux.is( src ) ) + for( let key of src ) + result.set( key, src[ key ] ); + else _.assert( 0 ); + } + return result; +} + +// + +/* qqq : for junior : cover */ +function make( src, length ) +{ + _.assert( this.like( src ) ); + _.assert( arguments.length <= 2 ); + _.assert( arguments.length === 1 || _.hashMap.is( src ) || _.auxIs( src ) ); /* qqq : for junior : cover aux case */ + _.assert( arguments.length < 2 || length === 0 ); + return this._make( src, length ); +} + +// + +function _cloneShallow( src ) +{ + let result = new HashMap(); + for( let [ key, val ] of src ) + result.set( key, val ); + return result; +} + +// + +function cloneShallow( src ) +{ + _.assert( this.like( src ) ); + _.assert( arguments.length === 1 ); + return this._cloneShallow( src ); +} + +// + +function _empty( dst ) +{ + dst.clear(); + return dst; +} + +// + +function empty( dst ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( this.like( dst ) ); + return this._empty( dst ); +} + +// + +function fromProps( dstMap, srcMap ) +{ + if( arguments.length === 1 ) + { + srcMap = arguments[ 0 ]; + dstMap = null; + } + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( !_.primitive.is( srcMap ) ); + _.assert( dstMap === null || _.hashMap.is( dstMap ) ); + + if( dstMap === null ) + dstMap = new HashMap; + + for( let k in srcMap ) + { + dstMap.set( k, srcMap[ k ] ); + } + + return dstMap; +} + +// + +function from( src ) +{ + _.assert( arguments.length === 1 ); + if( this.is( src ) ) + return src; + if( _.aux.is( src ) ) + return this.fromProps( null, src ); + _.assert( 0, `Not clear how to convert ${_.strType( src )} to HashMap` ); +} + +// -- +// properties +// -- + +function _keys( src ) +{ + return [ ... src.keys() ]; +} + +// + +function keys( src ) +{ + _.assert( this.like( src ) ); + return this._keys( src ); +} + +// + +function _vals( src ) +{ + return [ ... src.values() ]; +} + +// + +function vals( src ) +{ + _.assert( this.like( src ) ); + return this._vals( src ); +} + +// + +function _pairs( src ) +{ + return [ ... src.entries() ]; +} + +// + +function pairs( src ) +{ + _.assert( this.like( src ) ); + return this._pairs( src ); +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + + // dichotomy + + hashMapIs : is.bind( _.hashMap ), + hashMapIsEmpty : isEmpty.bind( _.hashMap ), + hashMapIsPopulated : isPopulated.bind( _.hashMap ), + hashMapLike : like.bind( _.hashMap ), + + // maker + + hashMapMakeEmpty : makeEmpty.bind( _.hashMap ), + hashMapMakeUndefined : makeUndefined.bind( _.hashMap ), + hashMapMake : make.bind( _.hashMap ), + hashMapCloneShallow : cloneShallow.bind( _.hashMap ), + hashMapFrom : from.bind( _.hashMap ), + +} + +Object.assign( _, ToolsExtension ); + +// + +let Extension = +{ + + // + + NamespaceName : 'hashMap', + NamespaceNames : [ 'hashMap' ], + NamespaceQname : 'wTools/hashMap', + MoreGeneralNamespaceName : 'hashMap', + MostGeneralNamespaceName : 'countable', + TypeName : 'HashMap', + SecondTypeName : 'Map', + InstanceConstructor : HashMap, + tools : _, + + // dichotomy + + is, + like, + isEmpty, + isPopulated, + IsResizable, + + // maker + + _makeEmpty, + makeEmpty, /* qqq : for junior : cover */ + _makeUndefined, + makeUndefined, /* qqq : for junior : cover */ + _make, + make, /* qqq : for junior : cover */ + _cloneShallow, + cloneShallow, /* qqq : for junior : cover */ + fromProps, /* qqq : for junior : cover */ + from, /* qqq : for junior : cover */ + + // properties + + _keys, + keys, /* qqq : for junior : cover */ + _vals, + vals, /* qqq : for junior : cover */ + _pairs, + pairs, /* qqq : for junior : cover */ + + // meta + + namespaceOf : _.blank.namespaceOf, + namespaceWithDefaultOf : _.blank.namespaceWithDefaultOf, + _functor_functor : _.blank._functor_functor, + +} + +Object.assign( _.hashMap, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/HashMap.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, HashMap_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file HashMap_s */ })(); + +/* */ /* begin of file Interval_s */ ( function Interval_s() { function Interval_s_naked() { ( function _l1_Interval_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _global_.wTools; + +// -- +// range +// -- + +function intervalIs( range ) +{ + _.assert( arguments.length === 1 ); + if( !_.number.s.areAll( range ) ) + return false; + if( range.length !== 2 ) + return false; + return true; +} + +// + +function intervalIsValid( range ) +{ + _.assert( arguments.length === 1 ); + if( !_.intervalIs( range ) ) + return false; + if( !_.intIs( range[ 0 ] ) ) + return false; + if( !_.intIs( range[ 1 ] ) ) + return false; + return true; +} + +// -- +// implementation +// -- + +let ToolsExtension = +{ + + /* zzz : review and rearrange */ + + // range + + intervalIs, + intervalIsValid, /* xxx : remove later */ + intervalDefined : intervalIsValid, /* xxx : remove later */ + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Interval.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Interval_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Interval_s */ })(); + +/* */ /* begin of file Intervalc_s */ ( function Intervalc_s() { function Intervalc_s_naked() { ( function _l1_Intervalc_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.cinterval = _.cinterval || Object.create( null ); + +// -- +// +// -- + +// -- +// implementation +// -- + +let Extension = +{ +}; + +// + +Object.assign( _.cinterval, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Intervalc.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Intervalc_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Intervalc_s */ })(); + +/* */ /* begin of file Intervall_s */ ( function Intervall_s() { function Intervall_s_naked() { ( function _l1_Intervall_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.linterval = _.linterval || Object.create( null ); + +// -- +// +// -- + +// -- +// +// -- + +let Extension = +{ +}; + +// + +Object.assign( _.linterval, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Intervall.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Intervall_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Intervall_s */ })(); + +/* */ /* begin of file Intervalo_s */ ( function Intervalo_s() { function Intervalo_s_naked() { ( function _l1_Intervalo_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.ointerval = _.ointerval || Object.create( null ); + +// -- +// +// -- + +// -- +// implementation +// -- + +let Extension = +{ +}; + +// + +Object.assign( _.ointerval, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Intervalo.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Intervalo_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Intervalo_s */ })(); + +/* */ /* begin of file Introspector_s */ ( function Introspector_s() { function Introspector_s_naked() { ( function _l1_Introspector_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.introspector = _.introspector || Object.create( null ); + +// -- +// relation +// -- + +let Location = +{ + original : null, + filePath : null, + routineName : null, + routineAlias : null, + internal : null, + abstraction : null, + line : null, + col : null, + filePathLineCol : null, + routineFilePathLineCol : null, + fileName : null, + fileNameLineCol : null, +} + +// -- +// implementation +// -- + +/* qqq : for junior : write performance test for this +let basePath = _.path.dir( _.introspector.location({ level : 2 }).filePath ) +qqq : make it super optimal +qqq : implement routine _.introspector.dirPathOf( 2 ); +qqq : implement routine _.introspector.filePathOf( 2 ); +dont forget about performance test and optimization +*/ + +function location( o ) +{ + if( _.number.is( o ) ) + o = { level : o } + else if( _.strIs( o ) ) + o = { stack : o, level : 0 } + else if( _.error.is( o ) ) + o = { error : o, level : 0 } + else if( o === undefined ) + o = { stack : _.introspector.stack([ 1, Infinity ]) }; + + /* */ + + if( location.defaults ) + for( let e in o ) + { + if( location.defaults[ e ] === undefined ) + throw Error( 'Unknown option ' + e ); + } + + if( location.defaults ) + for( let e in location.defaults ) + { + if( o[ e ] === undefined ) + o[ e ] = location.defaults[ e ]; + } + + if( !( arguments.length === 0 || arguments.length === 1 ) ) + throw Error( 'Expects single argument or none' ); + + if( !_.mapIs( o ) ) + throw Error( 'Expects options map' ); + + if( !o.level ) + o.level = 0; + + /* */ + + if( !o.location ) + o.location = Object.create( null ); + + /* */ + + if( o.error ) + { + let location2 = o.error.location || Object.create( null ); + + var args0 = + [ + location2.filePath, + o.location.filePath, + o.error.filename, + o.error.fileName + ]; + o.location.filePath = _.longLeftDefined( args0 ).element; + + var args1 = + [ + location2.line, + o.location.line, + o.error.line, + o.error.linenumber, + o.error.lineNumber, + o.error.lineNo, + o.error.lineno + ]; + o.location.line = _.longLeftDefined( args1 ).element; + + var args2 = + [ + location2.col, + o.location.col, + o.error.col, + o.error.colnumber, + o.error.colNumber, + o.error.colNo, + o.error.colno + ]; + o.location.col = _.longLeftDefined( args2 ).element; + + } + + /* */ + + if( !o.stack ) + { + if( o.error ) + { + o.stack = _.introspector.stack( o.error, undefined ); + } + else + { + o.stack = _.introspector.stack(); + o.level += 1; + } + } + + if( o.stack === null || o.stack === undefined ) + return o.location; + + _.assert( _.strIs( o.stack ) || _.arrayIs( o.stack ) ); + + let stack = o.stack; + if( _.strIs( stack ) ) + stack = stack.split( '\n' ); + let stackFrame = stack[ o.level ]; + + return _.introspector.locationFromStackFrame({ stackFrame, location : o.location }); +} + +location.defaults = +{ + level : 0, + stack : null, + error : null, + location : null, +} + +// + +function location_( o ) +{ + + if( _.number.is( o ) ) + o = { level : o } + else if( _.strIs( o ) ) + o = { stack : o, level : 0 } + else if( _.error.is( o ) ) + o = { error : o, level : 0 } + else if( o === undefined ) + o = { stack : _.introspector.stack([ 1, Infinity ]) }; + + /* */ + + if( location_.defaults ) + for( let e in o ) + { + if( location_.defaults[ e ] === undefined ) + throw Error( 'Unknown option ' + e ); + } + + if( location_.defaults ) + for( let e in location_.defaults ) + { + if( o[ e ] === undefined ) + o[ e ] = location_.defaults[ e ]; + } + + if( !( arguments.length === 0 || arguments.length === 1 ) ) + throw Error( 'Expects single argument or none' ); + + if( !_.mapIs( o ) ) + throw Error( 'Expects options map' ); + + if( !o.level ) + o.level = 0; + + /* */ + + if( !o.location ) + o.location = Object.create( null ); + + /* */ + + if( o.error ) + { + let location2 = o.error.location || Object.create( null ); + + var args0 = + [ + location2.filePath, + o.location.filePath, + o.error.filename, + o.error.fileName + ]; + o.location.filePath = _.longLeftDefined( args0 ).element; + + var args1 = + [ + location2.line, + o.location.line, + o.error.line, + o.error.linenumber, + o.error.lineNumber, + o.error.lineNo, + o.error.lineno + ]; + o.location.line = _.longLeftDefined( args1 ).element; + + var args2 = + [ + location2.col, + o.location.col, + o.error.col, + o.error.colnumber, + o.error.colNumber, + o.error.colNo, + o.error.colno + ]; + o.location.col = _.longLeftDefined( args2 ).element; + + } + + /* */ + + if( !o.stack ) + { + if( o.error ) + { + o.stack = _.introspector.stack( o.error, undefined ); + } + else + { + o.stack = _.introspector.stack(); + o.level += 1; + } + } + + if( o.stack === null || o.stack === undefined ) + return o.location; + + _.assert( _.strIs( o.stack ) || _.arrayIs( o.stack ) ); + + let stack = o.stack; + if( _.strIs( stack ) ) + stack = stack.split( '\n' ); + let stackFrame = stack[ o.level ]; + + // return _.introspector.locationFromStackFrame({ stackFrame, location : o.location }); + + o.location.original = stackFrame; + _.introspector.locationNormalize( o.location ); + return o.location; + +} + +location_.defaults = +{ + level : 0, + stack : null, + error : null, + location : null, +} + +// + +function locationFromStackFrame( o ) +{ + + if( _.strIs( o ) ) + o = { stackFrame : o }; + + if( !( arguments.length === 1 ) ) + throw Error( 'Expects single argument' ); + + if( !_.mapIs( o ) ) + throw Error( 'Expects options map' ); + + /* */ + + if( locationFromStackFrame.defaults ) /* Dmytro : maybe it is the redundant condition, the routine has defaults */ + for( let e in o ) + { + if( locationFromStackFrame.defaults[ e ] === undefined ) + throw Error( 'Unknown option : ' + e ); + } + + if( locationFromStackFrame.defaults ) /* Dmytro : maybe it is the redundant condition, the routine has defaults */ + for( let e in locationFromStackFrame.defaults ) + { + if( o[ e ] === undefined ) + o[ e ] = locationFromStackFrame.defaults[ e ]; + } + + /* */ + + if( !( _.strIs( o.stackFrame ) ) ) + throw Error( `Expects string {- stackFrame -}, but got ${_.entity.strType( o.stackFrame )}` ); + + if( o.location && !_.mapIs( o.location ) ) + throw Error( 'Expects map option::location' ); + + /* */ + + if( !o.location ) + o.location = Object.create( null ); + o.location.original = o.stackFrame; + _.introspector.locationNormalize( o.location ); + return o.location; +} + +locationFromStackFrame.defaults = +{ + stackFrame : null, + location : null, +}; + +// + +function locationNormalize( o ) +{ + + if( !( arguments.length === 1 ) ) + throw Error( 'Expects single argument' ); + + if( !_.mapIs( o ) ) + throw Error( 'Expects options map' ); + + /* */ + + if( locationNormalize.defaults ) + for( let e in o ) + { + if( locationNormalize.defaults[ e ] === undefined ) + throw Error( 'Unknown option ' + e ); + } + + if( locationNormalize.defaults ) + for( let e in locationNormalize.defaults ) + { + if( o[ e ] === undefined ) + o[ e ] = locationNormalize.defaults[ e ]; + } + + /* */ + + let hadPath = !!o.filePath; + if( !o.filePath ) + o.filePath = pathFromStack(); + + pathCanonize(); + routineFromStack(); + routineAliasFromStack(); + internalForm(); + abstractionForm(); + + // if( !_.strIs( o.filePath ) ) + // return end(); + + if( !_.number.defined( o.line ) || !_.number.defined( o.col ) ) + o.filePath = lineColFromPath( o.filePath ); + + if( !_.number.is( o.line ) && hadPath ) + { + let path = pathFromStack(); + if( path ) + lineColFromPath( path ); + } + + return end(); + + /* */ + + function end() + { + let path = o.filePath; + + /* filePathLineCol */ + + o.filePathLineCol = path || ''; + if( _.number.defined( o.line ) ) + { + o.filePathLineCol += ':' + o.line; + if( _.number.defined( o.col ) ) + o.filePathLineCol += ':' + o.col; + } + + /* routineFilePathLineCol */ + + if( o.routineName ) + o.routineFilePathLineCol = o.routineName + ' @ ' + o.filePathLineCol; + + /* fileName */ + + if( path ) + { + let fileName = path; + _.assert( _.routine.is( fileName.lastIndexOf ) ); + let i1 = fileName.lastIndexOf( '/' ); + let i2 = fileName.lastIndexOf( '\\' ); + let i = Math.max( i1, i2 ); + if( i !== -1 ) + fileName = fileName.substr( i+1 ); + o.fileName = fileName; + } + + /* fileNameLineCol */ + + o.fileNameLineCol = o.fileName || ''; + if( _.number.defined( o.line ) ) + { + o.fileNameLineCol += ':' + o.line; + if( _.number.defined( o.col ) ) + o.fileNameLineCol += ':' + o.col; + } + + return o; + } + + /* */ + + function pathCanonize() + { + if( !o.filePath ) + return; + + if( _.path && _.path.canonize ) + o.filePath = _.path.canonize( o.filePath ); + } + + /* */ + + function routineFromStack() + { + let routineName; + + if( o.routineName ) + return o.routineName; + if( !o.original ) + return o.routineName; + + routineName = o.original; + + // if( !_.strIs( routineName ) ) // xxx /* Dmytro : deprecated comment, delete with label, please */ + // return '{-anonymous-}'; + if( !_.strIs( routineName ) ) // xxx /* Dmytro : deprecated comment, delete with label, please */ + { + routineName = '{-anonymous-}'; + } + else + { + routineName = routineName.replace( /at eval \(eval at/, '' ); + let t = /^\s*(?:at\s+)?([\w.<>]+)\s*.+/; + let executed = t.exec( routineName ); + if( executed ) + routineName = executed[ 1 ] || ''; + + routineName = routineName.replace( //gm, '{-anonymous-}' ); + + if( _.strEnds( routineName, '.' ) ) + routineName += '{-anonymous-}'; + } + + o.routineName = routineName; + return o.routineName; + } + + /* */ + + function routineAliasFromStack() + { + let routineAlias; + + if( o.routineAlias ) + return o.routineAlias; + if( !o.original ) + return o.routineAlias; + + routineAlias = null; + + let t = /\[as ([^\]]*)\]/; + let executed = t.exec( o.original ); + if( executed ) + routineAlias = executed[ 1 ] || null; + + if( routineAlias ) + routineAlias = routineAlias.replace( //gm, '{-anonymous-}' ); + + o.routineAlias = routineAlias; + return o.routineAlias; + } + + /* */ + + function internalForm() + { + + if( _.number.defined( o.internal ) ) + return; + + o.internal = 0; + + if( o.filePath ) + { + if( o.internal < 2 ) + if( _.strBegins( o.filePath, 'internal/' ) ) + o.internal = 2; + + if( o.internal < 2 ) + if( _.strBegins( o.filePath, 'node:internal/' ) ) + o.internal = 2; + + } + + } + + /* */ + + function abstractionForm() + { + + if( _.number.defined( o.abstraction ) ) + return; + + o.abstraction = 0; + + if( o.routineName ) + { + if( o.abstraction < 2 ) + if( _.strBegins( o.routineName, '__' ) || o.routineName.indexOf( '.__' ) !== -1 ) + o.abstraction = 2; + if( o.abstraction < 1 ) + if( _.strBegins( o.routineName, '_' ) || o.routineName.indexOf( '._' ) !== -1 ) + o.abstraction = 1; + } + + if( o.routineAlias ) + { + if( o.abstraction < 2 ) + if( _.strBegins( o.routineAlias, '__' ) || o.routineAlias.indexOf( '.__' ) !== -1 ) + o.abstraction = 2; + if( o.abstraction < 1 ) + if( _.strBegins( o.routineAlias, '_' ) || o.routineAlias.indexOf( '._' ) !== -1 ) + o.abstraction = 1; + } + + } + + /* */ + + function pathFromStack() + { + let path = o.original; + + if( !_.strIs( path ) ) + return; + + path = path.replace( /^\s+/, '' ); + path = path.replace( /^\w+@/, '' ); + path = path.replace( /^at/, '' ); + path = path.replace( /^\s+/, '' ); + path = path.replace( /\s+$/, '' ); + + let regexp = /^.*\(([^)]*)\).*$/; + var parsed = regexp.exec( path ); + if( parsed ) + path = parsed[ 1 ]; + + return path; + } + + /* line / col number from path */ + + function lineColFromPath( path ) + { + if( !path ) + { + if( o.line ) + o.line = numberFromToInt( o.line ); + if( o.col ) + o.col = numberFromToInt( o.col ) + } + else + { + let lineNumber, colNumber; + let postfix = /(.+?):(\d+)(?::(\d+))?[^:/]*$/; + let parsed = postfix.exec( path ); + + if( parsed ) + { + path = parsed[ 1 ]; + lineNumber = parsed[ 2 ]; + colNumber = parsed[ 3 ]; + } + + lineNumber = numberFromToInt( lineNumber ); + colNumber = numberFromToInt( colNumber ); + + if( !_.number.defined( o.line ) ) + if( _.number.defined( lineNumber ) ) + o.line = lineNumber; + + if( !_.number.defined( o.col ) ) + if( _.number.defined( colNumber ) ) + o.col = colNumber; + } + + if( !_.number.defined( o.line ) ) + o.line = null; + if( !_.number.defined( o.col ) ) + o.col = null; + + return path; + } + + /* */ + + function numberFromToInt( src ) + { + if( _.strIs( src ) ) + src = parseInt( src ); + else + src = Math.floor( Number( src ) ); + + return src; + } + +} + +locationNormalize.defaults = +{ + ... Location, +} + +// + +function locationToStack( o ) +{ + if( !( arguments.length === 1 ) ) + throw Error( 'Expects single argument' ); + + if( !_.mapIs( o ) ) + throw Error( 'Expects options map' ); + + /* */ + + // _.map.assertHasOnly( o, locationToStack.defaults ); + if( Config.debug ) + { + let extraKeys = mapButKeys( o, locationToStack.defaults ); + _.assert( extraKeys.length === 0, () => `Routine "locationToStack" does not expect options: ${ keysQuote( extraKeys ) }` ); + } + + _.introspector.locationNormalize( o ); + + if( !o.filePathLineCol ) + return null; + + // if( o.routineFilePathLineCol ) + // { + // _.assert( 0, 'not tested' ); + // } + + if( o.routineName ) + return `at ${o.routineName} (${o.filePathLineCol})`; + else + return `at (${o.filePathLineCol})`; + + /* + at Object.locationToStack (http://127.0.0.1:5000//builder/include/wtools/abase/l0/l3/Introspector.s:723:10) + */ + + /* */ + + function mapButKeys( srcMap, butMap ) + { + let result = []; + + for( let s in srcMap ) + if( !( s in butMap ) ) + result.push( s ); + + return result; + } + + /* */ + + function keysQuote( keys ) + { + let result = `"${ keys[ 0 ] }"`; + for( let i = 1 ; i < keys.length ; i++ ) + result += `, "${ keys[ i ] }"`; + return result.trim(); + } +} + +locationToStack.defaults = +{ + ... Location, +} + +// + +/** + * Routine stack() returns stack trace from provided argument {-stack-} as a string. If {-stack-} is not provided, + * then routine returns stack trace at a current position of code. + * + * @param { String|Array|Unroll|Error } stack - A stack to trace. If {-stack-} is not provided, then routine generates + * stack trace at a current code position. + * @param { Range } range - A range of lines selected from stack trace. If {-range-} is undefined, then routine returns + * full stack trace. If range[ 0 ] < 0, then routine counts lines from the end of stack trace. If stack[ 1 ] < 0, then + * routine counts end line from the end of stack trace. + * + * @example + * let stack; + * function function1() + * { + * function2(); + * } + * + * function function2() + * { + * function3(); + * } + * + * function function3() + * { + * stack = _.introspector.stack(); + * } + * + * function1(); + * console.log( stack ); + * // log + * //" at function3 (:10:17) + * // at function2 (:6:2) + * // at function1 (:2:2) + * // at :1:1" + * + * @example + * let stack; + * function function1() + * { + * function2(); + * } + * + * function function2() + * { + * function3(); + * } + * + * function function3() + * { + * stack = _.introspector.stack( [ 0, 1 ] ); + * } + * + * function1(); + * console.log( stack ); + * // log + * //" at function3 (:10:17) + * + * @returns { String } - Return stack trace from call point. + * @function stack + * @throws { Error } If arguments.length is more than two. + * @throws { Error } If {-range-} is not a Range. + * @namespace Tools + * @module Tools/base/Fundamental + */ + +function stack( stack, range ) +{ + + if( arguments.length === 1 ) + { + if( !_.error.is( stack ) ) + if( !_.strIs( stack ) ) + { + range = arguments[ 0 ]; + stack = undefined; + } + } + + if( stack === undefined || stack === null ) + { + stack = new Error(); + if( range === undefined ) + { + range = [ 1, Infinity ]; + } + else + { + if( _.number.is( range[ 0 ] ) ) /* Dmytro : previous implementation affects range - not a number value + number => NaN, so assertion does not word properly */ + range[ 0 ] += 1; + if( _.number.is( range[ 1 ] ) && range[ 1 ] >= 0 ) + range[ 1 ] += 1; + } + } + + if( range === undefined ) + range = [ 0, Infinity ]; + + if( arguments.length !== 0 && arguments.length !== 1 && arguments.length !== 2 ) + { + debugger; + throw Error( 'stack : expects one or two or none arguments' ); + } + + if( !_.intervalIs( range ) ) + { + debugger; + throw Error( 'stack : expects range but, got ' + _.entity.strType( range ) ); + } + + let first = range[ 0 ]; + let last = range[ 1 ]; + + // if( !_.number.is( first ) ) // Dmytro : it's unnecessary assertions, _.intervalIs checks number value in passed array + // { + // debugger; + // throw Error( 'stack : expects number range[ 0 ], but got ' + _.entity.strType( first ) ); + // } + // + // if( !_.number.is( last ) ) + // { + // debugger; + // throw Error( 'stack : expects number range[ 0 ], but got ' + _.entity.strType( last ) ); + // } + + let errIs = 0; + if( _.error.is( stack ) ) + { + stack = _.error.originalStack( stack ); + errIs = 1; + } + + if( !stack ) + return ''; + + if( !_.arrayIs( stack ) && !_.strIs( stack ) ) + return; + + // if( !_.arrayIs( stack ) && !_.strIs( stack ) ) // Dmytro : previous condition is almost identical + // { + // debugger; + // throw Error( 'stack expects array or string' ); + // } + + if( !_.arrayIs( stack ) ) + stack = stack.split( '\n' ); + + // debugger; + + /* remove redundant lines */ + + while( stack.length ) + { + let splice = 0; + splice |= ( _.strHas( stack[ 0 ], /(^| )at / ) === false && stack[ 0 ].indexOf( '@' ) === -1 ); + splice |= stack[ 0 ].indexOf( '(vm.js:' ) !== -1; + splice |= stack[ 0 ].indexOf( '(module.js:' ) !== -1; + splice |= stack[ 0 ].indexOf( '(internal/module.js:' ) !== -1; + if( splice ) + stack.splice( 0, 1 ); + else break; + } + + if( stack[ 0 ] ) + if( stack[ 0 ].indexOf( 'at ' ) === -1 && stack[ 0 ].indexOf( '@' ) === -1 ) // Dmytro : it's dubious - while loop removes all strings if stack[ 0 ] has not 'at ' or '@' + { + console.error( 'stack : failed to parse stack' ); + debugger; + } + + stack = stack.map( ( line ) => line.trim() ); + stack = stack.filter( ( line ) => line ); + + /* */ + + first = first === undefined ? 0 : first; + last = last === undefined ? stack.length : last; + + // if( _.number.is( first ) ) // Dmytro : first and last - is always some numbers, see above about assertions + if( first < 0 ) + first = stack.length + first; + + // if( _.number.is( last ) ) + if( last < 0 ) + last = stack.length + last + 1; + + /* */ + + if( first !== 0 || last !== stack.length ) + { + stack = stack.slice( first || 0, last ); + } + + /* */ + + stack = String( stack.join( '\n' ) ); + + return stack; +} + +// + +function stackRelative( stack, delta ) +{ + _.assert( delta === undefined || _.number.is( delta ) ); + _.assert( stack === undefined || stack === null || _.bool.is( stack ) || _.number.is( stack ) || _.strIs( stack ) ); + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + + if( _.strIs( stack ) ) + return stack; + if( stack === false ) + return ''; + + if( stack === undefined || stack === null || stack === true ) + stack = 1; + else if( _.number.is( stack ) ) + stack += 1; + + if( delta ) + stack += delta; + if( _.number.is( stack ) ) + stack = _.introspector.stack([ stack, Infinity ]); + + _.assert( _.strIs( stack ) ); + + return stack; +} + +// + +function stackRemoveLeft( stack, include, exclude ) +{ + if( arguments.length !== 3 ) + throw Error( 'Expects three arguments' ); + if( !_.regexpIs( include ) && include !== null ) + throw Error( 'Expects regexp either null as the second argument' ); + if( !_.regexpIs( exclude ) && exclude !== null ) + throw Error( 'Expects regexp either null as the third argument' ); + + if( !_.strIs( stack ) ) + return stack; + + stack = stack.split( '\n' ); + + for( let s = stack.length-1 ; s >= 0 ; s-- ) + { + let line = stack[ s ]; + if( include && include.test( line ) ) + { + stack.splice( s, 1 ); + continue; + } + if( exclude && exclude.test( line ) ) + { + stack.splice( s, 1 ); + continue; + } + } + + return stack.join( '\n' ); +} + +// + +function stackCondense( stack ) +{ + + if( arguments.length !== 1 ) + throw Error( 'Expects single arguments' ); + + if( !_.strIs( stack ) ) + { + debugger; + throw Error( 'Expects string' ); + } + + stack = stack.split( '\n' ); + + for( let s = stack.length-1 ; s >= 0 ; s-- ) + { + let line = stack[ s ]; + if( s > 0 ) + if( /(\W|^)__\w+/.test( line ) ) + { + stack.splice( s, 1 ); + continue; + } + if( _.strHas( line, '.test.' ) ) + line += ' *'; + stack[ s ] = line; + } + + return stack.join( '\n' ); +} + +// + +function stackFilter( stack, onEach ) +{ + let result = []; + + if( _.routine.is( stack ) ) + { + onEach = stack; + stack = undefined; + } + + if( !_.strIs( stack ) ) + stack = _.introspector.stack( stack, undefined ); // Dmytro : missed second argument, which has influence on the result + + _.assert( _.strIs( stack ) ); + _.assert( _.routine.is( onEach ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + stack = stack.split( '\n' ); + + stack.forEach( ( stackFrame, k ) => + { + let location = _.introspector.locationFromStackFrame( stackFrame ); + let r = onEach( location, k ); + if( r === undefined ) + return; + if( _.strIs( r ) ) + { + result.push( r ); + return; + } + _.assert( _.object.isBasic( r ) ); + _.assert( _.strIs( r.original ) ); + result.push( r.original ); + }); + + return result.join( '\n' ); +} + +// + +function code() +{ + return undefined; +} + +// -- +// +// -- + +let Extnesion = +{ + + Location, + + location, + location_, + locationFromStackFrame, + locationNormalize, /* aaa for Dmytro : write good test */ /* Dmytro : covered */ + locationToStack, + + stack, + stackRelative, + stackRemoveLeft, + stackCondense, + stackFilter, + + code, + +} + +// + +Object.assign( _.introspector, Extnesion ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Introspector.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Introspector_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Introspector_s */ })(); + +/* */ /* begin of file Itself_s */ ( function Itself_s() { function Itself_s_naked() { ( function _l1_Itself_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.itself = _.itself || Object.create( null ); + +_.assert( !!_.blank.make, 'Expects routine _.blank.make' ); + +// -- +// implementation +// -- + +function is( src ) +{ + return true; +} + +// + +function like( src ) +{ + return true; +} + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return false; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + + // dichotomy + + itselfIs : is.bind( _.itself ), + itselfLike : like.bind( _.itself ), + +} + +Object.assign( _, ToolsExtension ); + +// + +let ItselfExtension = +{ + + // fields + + NamespaceName : 'itself', + NamespaceNames : [ 'itself' ], + NamespaceQname : 'wTools/itself', + MoreGeneralNamespaceName : 'itself', + MostGeneralNamespaceName : 'itself', + TypeName : 'Itself', + TypeNames : [ 'Itself' ], + // SecondTypeName : 'Itself', + InstanceConstructor : null, + tools : _, + + // dichotomy + + is, + like, + IsResizable, + + // maker + + _makeEmpty : _.blank._makeEmpty, + makeEmpty : _.blank.makeEmpty, /* qqq : for junior : cover */ + _makeUndefined : _.blank._makeUndefined, + makeUndefined : _.blank.makeUndefined, /* qqq : for junior : cover */ + _make : _.blank._make, + make : _.blank.make, /* qqq : for junior : cover */ + _cloneShallow : _.blank._cloneShallow, + cloneShallow : _.blank.cloneShallow, /* qqq : for junior : cover */ + from : _.blank.from, /* qqq : for junior : cover */ + + // meta + + namespaceOf : _.blank.namespaceOf, + namespaceWithDefaultOf : _.blank.namespaceWithDefaultOf, + _functor_functor : _.blank._functor_functor, + +} + +Object.assign( _.itself, ItselfExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Itself.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Itself_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Itself_s */ })(); + +/* */ /* begin of file Logger_s */ ( function Logger_s() { function Logger_s_naked() { ( function _l1_Logger_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.logger = _.logger || Object.create( null ); + +// -- +// implementation +// -- + +function consoleIs( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( console.Console ) + if( src && src instanceof console.Console ) + return true; + + if( src !== console ) + return false; + + let result = Object.prototype.toString.call( src ); + if( result === '[object Console]' || result === '[object Object]' ) + return true; + + return false; +} + +// + +function is( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( !_.Logger ) + return false; + + if( src instanceof _.Logger ) + return true; + + return false; +} + +// + +function like( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.printer.is( src ) ) + return true; + + if( _.consoleIs( src ) ) + return true; + + if( src === _global_.logger ) + return true; + + return false; +} + +// + +function fromStrictly( src ) +{ + let result = src; + + _.assert( result === null || _.boolIs( result ) || _.numberIs( result ) || _.logger.is( result ) ); + + if( result === null ) + { + result = new _.Logger({ output : _global_.logger, verbosity : 1 }); + } + else if( _.boolIs( result ) ) + { + result = new _.Logger({ output : _global_.logger, verbosity : result ? 1 : 0 }); + } + else if( _.numberIs( result ) ) + { + result = new _.Logger({ output : _global_.logger, verbosity : result }); + } + else if( _.logger.is( result ) ) + { + } + else _.assert( 0 ); + + return result; +} + +// + +function maybe( src ) +{ + let result = src; + + _.assert( result === null || _.boolIs( result ) || _.numberIs( result ) || _.logger.like( result ) ); + + if( result === null ) + { + result = new _.Logger({ output : _global_.logger, verbosity : 1 }); + } + else if( _.boolIs( result ) ) + { + if( result ) + result = new _.Logger({ output : _global_.logger, verbosity : 1 }); + else + result = 0; + } + else if( _.numberIs( result ) ) + { + if( result > 0 ) + result = new _.Logger({ output : _global_.logger, verbosity : result }); + else + result = 0; + } + else if( _.logger.like( result ) ) + { + } + else _.assert( 0 ); + + return result; +} + +// + +function relativeMaybe( src, delta ) +{ + let result = src; + + _.assert( result === null || _.boolIs( result ) || _.numberIs( result ) || _.logger.is( result ) ); + _.assert( delta === undefined || _.numberDefined( delta ) || _.logger.like( delta ) ); + + if( _.logger.like( delta ) ) + return delta; + + delta = delta || 0; + + if( result === null ) + { + result = new _.Logger({ output : _global_.logger, verbosity : 1 + delta }); + } + else if( _.boolIs( result ) ) + { + if( result ) + result = new _.Logger({ output : _global_.logger, verbosity : 1 + delta }); + else if( delta > 0 ) + result = new _.Logger({ output : _global_.logger, verbosity : delta }); + else + result = 0; + } + else if( _.numberIs( result ) ) + { + result += delta; + if( result > 0 ) + result = new _.Logger({ output : _global_.logger, verbosity : result }); + else + result = 0; + } + else if( _.logger.is( result ) ) + { + if( delta !== 0 ) + result = new _.Logger({ output : result, verbosity : result.verbosity + delta }); + } + else _.assert( 0 ); + + return result; +} + +// + +function absoluteMaybe( src, verbosity ) +{ + let result = src; + + _.assert( result === null || _.boolIs( result ) || _.numberIs( result ) || _.logger.is( result ) ); + _.assert( verbosity === undefined || verbosity === null || _.boolIs( verbosity ) || _.numberDefined( verbosity ) || _.logger.like( verbosity ) ); + + if( _.logger.like( verbosity ) ) + return verbosity; + + if( verbosity !== null && verbosity !== undefined ) + { + if( verbosity === 0 || verbosity === false ) + { + if( _.logger.is( src ) ) + { + src.verbosity = 0; + return src; + } + return 0; + } + _.assert( _.numberIs( verbosity ) || _.boolIs( verbosity ) ); + } + + if( result === null ) + { + result = new _.Logger({ output : _global_.logger, verbosity : verbosityGet() }); + } + else if( _.boolIs( result ) ) + { + result = new _.Logger({ output : _global_.logger, verbosity : verbosityGet() }); + } + else if( _.numberIs( result ) ) + { + result = new _.Logger({ output : _global_.logger, verbosity : verbosityGet() }); + } + else if( _.logger.is( result ) ) + { + if( _.numberIs( verbosity ) ) + result.verbosity = verbosity; + } + else _.assert( 0 ); + + return result; + + function verbosityGet() + { + if( verbosity === undefined || verbosity === null || verbosity === true ) + return 1; + if( verbosity === false ) + return 0; + _.assert( _.numberIs( verbosity ) ); + return verbosity; + } + +} + +// + +function verbosityFrom( src ) +{ + let result = src; + + _.assert( _.boolIs( result ) || _.numberIs( result ) ); + _.assert( arguments.length === 1 ); + + if( _.boolIs( result ) ) + { + result = result ? 1 : 0; + } + + return result; +} + +// + +function verbosityRelative( src, delta ) +{ + let result = src; + + _.assert( _.boolIs( result ) || _.numberIs( result ) ); + _.assert( delta === undefined || _.numberDefined( delta ) ); + + delta = delta || 0; + + if( _.boolIs( result ) ) + { + if( result ) + result = 1 + delta; + else + result = delta; + } + else if( _.numberIs( result ) ) + { + result += delta; + } + + return result; +} + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + consoleIs, + loggerIs : is, + loggerLike : like, +} + +// + +Object.assign( _, ToolsExtension ); + +// -- +// logger extension +// -- + +let LoggerExtension = +{ + is, + like, + fromStrictly, /* qqq : cover */ + maybe, /* qqq : cover */ + relativeMaybe, /* qqq : cover */ + absoluteMaybe, /* qqq : cover */ + verbosityFrom, /* qqq : cover */ + verbosityRelative, /* qqq : cover */ +} + +// + +Object.assign( _.logger, LoggerExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Logger.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Logger_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Logger_s */ })(); + +/* */ /* begin of file Logic_s */ ( function Logic_s() { function Logic_s_naked() { ( function _l1_Logic_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.logic = _.logic || Object.create( null ); + +// -- +// logic +// -- + +function is( src ) +{ + if( src === true || src === false || src === _.maybe ) + return true; + if( !src ) + return false; + if( src instanceof _.logic.node.Abstract ) + return true; + return false; +} + +// + +function like( src ) +{ + return this.is( src ); +} + +// + +function isNode( src ) +{ + if( src instanceof _.logic.node.Abstract ) + return true; + return false; +} + +// -- +// extension +// -- + +let LogicExtension = +{ + + is, + like, + isNode + +} + +Object.assign( _.logic, LogicExtension ); + +// + +let ToolsExtension = +{ + + logicIs : is.bind( _.logic ), + logicLike : like.bind( _.logic ), + logicIsNode : isNode.bind( _.logic ), + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Logic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Logic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Logic_s */ })(); + +/* */ /* begin of file LogicNode_s */ ( function LogicNode_s() { function LogicNode_s_naked() { ( function _l1_LogicNode_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.logic = _.logic || Object.create( null ); +_.logic.node = _.logic.node || Object.create( null ); + +// -- +// implement +// -- + +// -- +// declare +// -- + +var Extension = +{ +} + +Object.assign( _.logic.node, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/LogicNode.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, LogicNode_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file LogicNode_s */ })(); + +/* */ /* begin of file Map_s */ ( function Map_s() { function Map_s_naked() { ( function _l1_Map_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.map = _.map || Object.create( null ); + +_.assert( !!_.props.extend, 'Expects routine _.props.exportString' ); + +// -- +// dichotomy +// -- + +/** + * The is() routine determines whether the passed value is an Object, + * and not inherits through the prototype chain. + * + * If the {-srcMap-} is an Object, true is returned, + * otherwise false is. + * + * @param { * } src - Entity to check. + * + * @example + * _.map.is( { a : 7, b : 13 } ); + * // returns true + * + * @example + * _.map.is( 13 ); + * // returns false + * + * @example + * _.map.is( [ 3, 7, 13 ] ); + * // returns false + * + * @returns { Boolean } Returns true if {-srcMap-} is an Object, and not inherits through the prototype chain. + * @function is + * @namespace Tools/map + */ + +function is( src ) +{ + + if( !src ) + return false; + + let proto = Object.getPrototypeOf( src ); + + if( proto === null ) + return true; + + if( proto === Object.prototype ) + { + if( src[ Symbol.iterator ] ) + return Object.prototype.toString.call( src ) !== '[object Arguments]'; + return true; + } + + return false; +} + +// + +function isPure( src ) +{ + if( !src ) + return false; + + if( Object.getPrototypeOf( src ) === null ) + return true; + + return false; +} + +// + +function isPolluted( src ) +{ + + if( !src ) + return false; + + let proto = Object.getPrototypeOf( src ); + + if( proto === null ) + return false; + + if( proto === Object.prototype ) + { + if( src[ Symbol.iterator ] ) + return Object.prototype.toString.call( src ) !== '[object Arguments]'; + return true; + } + + return false; +} + +// function is( src ) +// { +// +// if( !src ) +// return false; +// +// if( src[ Symbol.iterator ] ) +// return false; +// +// let proto = Object.getPrototypeOf( src ); +// +// if( proto === null ) +// return true; +// +// if( proto === Object.prototype ) +// return true; +// +// return false; +// } +// +// // +// +// function isPure( src ) +// { +// if( !src ) +// return false; +// +// if( src[ Symbol.iterator ] ) +// return false; +// +// if( Object.getPrototypeOf( src ) === null ) +// return true; +// +// return false; +// } +// +// // +// +// function isPolluted( src ) +// { +// +// if( !src ) +// return false; +// +// if( src[ Symbol.iterator ] ) +// return false; +// +// let proto = Object.getPrototypeOf( src ); +// +// if( proto === null ) +// return false; +// +// if( proto === Object.prototype ) +// return true; +// +// return false; +// } + +// + +function like( src ) +{ + return _.map.is( src ); +} + +// + +function isEmpty( src ) +{ + if( !this.like( src ) ) + return false; + return this.keys( src ).length === 0; +} + +// + +function isPopulated( src ) +{ + if( !this.like( src ) ) + return false; + return this.keys( src ).length > 0; +} + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return true; +} + +// -- +// maker +// -- + +function _makeEmpty( src ) +{ + return Object.create( null ); +} + +// + +function makeEmpty( src ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 ); + if( arguments.length === 1 ) + _.assert( this.like( src ) ); + return this._makeEmpty( src ); +} + +// + +function _makeUndefined( src ) +{ + return Object.create( null ); +} + +// + +function makeUndefined( src, length ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + + if( arguments.length === 2 ) + { + _.assert( this.like( src ) ); + _.assert( _.number.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( _.number.is( src ) || this.like( src ) ); + } + + return this._makeUndefined( src ); +} + +// + +function _make( src ) +{ + let dst = Object.create( null ); + if( src ) + this.extendUniversal( dst, src ); + // if( src ) + // Object.assign( dst, src ); + return dst; +} + +// + +function make( src, length ) +{ + _.assert( arguments.length === 0 || src === null || !_.primitive.is( src ) ); + _.assert( length === undefined || length === 0 ); + _.assert( arguments.length <= 2 ); + return this._make( ... arguments ); +} + +// + +function _cloneShallow( src ) +{ + let dst = Object.create( null ); + Object.assign( dst, src ); + return dst; +} + +// -- +// properties +// -- + +function _keys( o ) +{ + let result = []; + + _.routine.options( _keys, o ); + + let srcMap = o.srcMap; + let selectFilter = o.selectFilter; + + _.assert( this === _.map ); + _.assert( arguments.length === 1, 'Expects single argument' ); + // _.assert( !( srcMap instanceof Map ), 'not implemented' ); + _.assert( selectFilter === null || _.routine.is( selectFilter ) ); + _.assert( this.is( srcMap ) ); + + /* */ + + if( o.onlyEnumerable ) + { + let result1 = []; + + // _.assert( !_.primitive.is( srcMap ) ); + + if( o.onlyOwn ) + { + for( let k in srcMap ) + if( Object.hasOwnProperty.call( srcMap, k ) ) + result1.push( k ); + } + else + { + for( let k in srcMap ) + result1.push( k ); + } + + filter( srcMap, result1 ); + + } + else + { + // _.assert( !( srcMap instanceof Map ), 'not implemented' ); + + if( o.onlyOwn ) + { + filter( srcMap, Object.getOwnPropertyNames( srcMap ) ); + } + else + { + let proto = srcMap; + result = []; + do + { + filter( proto, Object.getOwnPropertyNames( proto ) ); + proto = Object.getPrototypeOf( proto ); + } + while( proto ); + /* qqq : for junior : map cant have prototype. rewrite */ + } + + } + + return result; + + /* */ + + function filter( srcMap, keys ) + { + + if( !selectFilter ) + { + /* qqq : for junior : rewrite without arrayAppend and without duplicating array */ + arrayAppendArrayOnce( result, keys ); + } + else for( let k = 0 ; k < keys.length ; k++ ) + { + let e = selectFilter( srcMap, keys[ k ] ); + if( e !== undefined ) + arrayAppendOnce( result, e ); + /* qqq : for junior : rewrite without arrayAppend and without duplicating array */ + } + + } + + /* */ + + function arrayAppendOnce( dst, element ) + { + let i = dst.indexOf( element ); + if( i === -1 ) + dst.push( element ); + return dst; + } + + /* */ + + function arrayAppendArrayOnce( dst, src ) + { + src.forEach( ( element ) => + { + let i = dst.indexOf( element ); + if( i === -1 ) + dst.push( element ); + }); + return dst; + } + +} + +_keys.defaults = +{ + srcMap : null, + onlyOwn : 0, + onlyEnumerable : 1, + selectFilter : null, +} + +// + +/** + * This routine returns an array of a given objects onlyEnumerable properties, + * in the same order as that provided by a for...in loop. + * Accept single object. Each element of result array is unique. + * Unlike standard [Object.keys]{@https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys} + * which accept object only props.keys accept any object-like entity. + * + * @see {@link wTools.props.onlyOwnKeys} - Similar routine taking into account own elements only. + * @see {@link wTools.props.vals} - Similar routine returning values. + * + * @example + * _.props.keys({ a : 7, b : 13 }); + * // returns [ "a", "b" ] + * + * @example + * let o = { onlyOwn : 1, onlyEnumerable : 0 }; + * _.props.keys.call( o, { a : 1 } ); + * // returns [ "a" ] + * + * @param { objectLike } srcMap - object of interest to extract keys. + * @param { objectLike } o - routine options can be provided through routine`s context. + * @param { boolean } [ o.onlyOwn = false ] - count only object`s own properties. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * @return { array } Returns an array with unique string elements. + * corresponding to the onlyEnumerable properties found directly upon object or empty array + * if nothing found. + * @function keys + * @throws { Exception } Throw an exception if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools/map + */ + +function keys( srcMap, o ) +{ + let result; + + _.assert( this === _.map ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( keys, o || null ); + _.assert( this.is( srcMap ) ); + + o.srcMap = srcMap; + + result = this._keys( o ); + + return result; +} + +keys.defaults = +{ + onlyOwn : 0, + onlyEnumerable : 1, +} + +// + +/** + * The props.allKeys() returns all properties of provided object as array, + * in the same order as that provided by a for...in loop. Each element of result array is unique. + * + * @param { objectLike } srcMap - The object whose properties keys are to be returned. + * + * @example + * let x = { a : 1 }; + * let y = { b : 2 }; + * Object.setPrototypeOf( x, y ); + * _.props.allKeys( x ); + * // returns [ "a", "b", "__defineGetter__", ... "isPrototypeOf" ] + * + * @return { array } Returns an array whose elements are strings + * corresponding to the all properties found on the object. + * @function allKeys + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @namespace Tools/map +*/ + +function allKeys( srcMap, o ) +{ + + _.assert( this === _.map ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( allKeys, o || null ); + _.assert( this.is( srcMap ) ); + + o.srcMap = srcMap; + // o.onlyOwn = 0; + // o.onlyEnumerable = 0; + + let result = this._keys( o ); + + return result; +} + +/* qqq : write test routine for each option */ +/* qqq : do the same for similar routines */ +/* qqq : adjust similar routine if they handle options no like routine allKeys */ +allKeys.defaults = +{ + onlyOwn : 0, + onlyEnumerable : 0, +} + +// + +function _vals( o ) +{ + + _.routine.options( _vals, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( o.selectFilter === null || _.routine.is( o.selectFilter ) ); + _.assert( o.selectFilter === null ); + _.assert( this === _.map ); + + let result = this._keys( o ); + + for( let k = 0 ; k < result.length ; k++ ) + { + result[ k ] = o.srcMap[ result[ k ] ]; + } + + return result; +} + +_vals.defaults = +{ + srcMap : null, + onlyOwn : 0, + onlyEnumerable : 1, + selectFilter : null, +} + +// + +/** + * The props.vals() routine returns an array of a given object's + * onlyEnumerable property values, in the same order as that provided by a for...in loop. + * + * It takes an object {-srcMap-} creates an empty array, + * checks if {-srcMap-} is an object. + * If true, it returns an array of values, + * otherwise it returns an empty array. + * + * @param { objectLike } srcMap - The object whose property values are to be returned. + * @param { objectLike } o - routine options can be provided through routine`s context. + * @param { boolean } [ o.onlyOwn = false ] - count only object`s own properties. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * + * @example + * _.props.vals( { a : 7, b : 13 } ); + * // returns [ "7", "13" ] + * + * @example + * let o = { onlyOwn : 1 }; + * let a = { a : 7 }; + * let b = { b : 13 }; + * Object.setPrototypeOf( a, b ); + * _.props.vals.call( o, a ) + * // returns [ 7 ] + * + * @returns { array } Returns an array whose elements are strings. + * corresponding to the onlyEnumerable property values found directly upon object. + * @function vals + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools/map + */ + +function vals( srcMap, o ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( vals, o || null ); + _.assert( this.is( srcMap ) ); + _.assert( this === _.map ); + + o.srcMap = srcMap; + + let result = this._vals( o ); + + return result; +} + +vals.defaults = +{ + onlyOwn : 0, + onlyEnumerable : 1, +} + +// + +/** + * The props.allVals() returns values of all properties of provided object as array, + * in the same order as that provided by a for...in loop. + * + * It takes an object {-srcMap-} creates an empty array, + * checks if {-srcMap-} is an object. + * If true, it returns an array of values, + * otherwise it returns an empty array. + * + * @param { objectLike } srcMap - The object whose property values are to be returned. + * + * @example + * _.props.allVals( { a : 7, b : 13 } ); + * // returns [ "7", "13", function __defineGetter__(), ... function prototype.isPrototypeFor() ] + * + * @returns { array } Returns an array whose elements are strings. + * corresponding to the onlyEnumerable property values found directly upon object. + * @function allVals + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @namespace Tools/map + */ + +function allVals( srcMap, o ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( allVals, o || null ); + _.assert( this.is( srcMap ) ); + _.assert( this === _.map ); + + o.srcMap = srcMap; + o.onlyOwn = 0; + o.onlyEnumerable = 0; + + let result = this._vals( o ); + + debugger; + return result; +} + +allVals.defaults = +{ +} + +// + +function _pairs( o ) +{ + + _.routine.options( _pairs, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( o.selectFilter === null || _.routine.is( o.selectFilter ) ); + _.assert( this.like( o.srcMap ) ); + _.assert( this === _.map ); + + let selectFilter = o.selectFilter; + + if( o.selectFilter ) + debugger; + + if( !o.selectFilter ) + o.selectFilter = function selectFilter( srcMap, k ) + { + return [ k, srcMap[ k ] ]; + } + + let result = this._keys( o ); + + return result; +} + +_pairs.defaults = +{ + srcMap : null, + onlyOwn : 0, + onlyEnumerable : 1, + selectFilter : null, +} + +// + +/** + * The map.pairs() converts an object into a list of unique [ key, value ] pairs. + * + * It takes an object {-srcMap-} creates an empty array, + * checks if {-srcMap-} is an object. + * If true, it returns a list of [ key, value ] pairs if they exist, + * otherwise it returns an empty array. + * + * @param { objectLike } srcMap - Object to get a list of [ key, value ] pairs. + * @param { objectLike } o - routine options can be provided through routine`s context. + * @param { boolean } [ o.onlyOwn = false ] - count only object`s own properties. + * @param { boolean } [ o.onlyEnumerable = true ] - count only object`s onlyEnumerable properties. + * + * @example + * _.map.pairs( { a : 7, b : 13 } ); + * // returns [ [ "a", 7 ], [ "b", 13 ] ] + * + * @example + * let a = { a : 1 }; + * let b = { b : 2 }; + * Object.setPrototypeOf( a, b ); + * _.map.pairs.call( { onlyOwn : 1 }, a ); + * // returns [ [ "a", 1 ] ] + * + * @returns { array } A list of [ key, value ] pairs. + * @function pairs + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @throws { Error } Will throw an Error if unknown option is provided. + * @namespace Tools/map + */ + +function pairs( srcMap, o ) +{ + + _.assert( this === _.map ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( pairs, o || null ); + + o.srcMap = srcMap; + + let result = this._pairs( o ); + + return result; +} + +pairs.defaults = +{ + onlyOwn : 0, + onlyEnumerable : 1, +} + +// + +/** + * The props.allPairs() converts all properties of the object {-srcMap-} into a list of unique [ key, value ] pairs. + * + * It takes an object {-srcMap-} creates an empty array, + * checks if {-srcMap-} is an object. + * If true, it returns a list of [ key, value ] pairs that repesents all properties of provided object{-srcMap-}, + * otherwise it returns an empty array. + * + * @param { objectLike } srcMap - Object to get a list of [ key, value ] pairs. + * + * @example + * _.props.allPairs( { a : 7, b : 13 } ); + * // returns [ [ "a", 7 ], [ "b", 13 ], ... [ "isPrototypeOf", function prototype.isPrototypeFor() ] ] + * + * @example + * let a = { a : 1 }; + * let b = { b : 2 }; + * Object.setPrototypeOf( a, b ); + * _.props.allPairs( a ); + * // returns [ [ "a", 1 ], [ "b", 2 ], ... [ "isPrototypeOf", function prototype.isPrototypeFor() ] ] + * + * @returns { array } A list of [ key, value ] pairs. + * @function allPairs + * @throws { Error } Will throw an Error if {-srcMap-} is not an objectLike entity. + * @namespace Tools/map + */ + +function allPairs( srcMap, o ) +{ + + _.assert( this === _.map ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + o = _.routine.options( allPairs, o || null ); + + o.srcMap = srcMap; + o.onlyOwn = 0; + o.onlyEnumerable = 0; + + let result = this._pairs( o ); + + debugger; + return result; +} + +allPairs.defaults = +{ +} + +// -- +// meta +// -- + +/* qqq : optimize */ +function namespaceOf( src ) +{ + + if( _.map.is( src ) ) + return _.map; + + return null; +} + +// -- +// extension +// -- + +/* qqq : for junior : duplicate routines */ + +let ToolsExtension = +{ + + // dichotomy + + mapIs : is.bind( _.map ), + mapIsPure : isPure.bind( _.map ), + mapIsPolluted : isPolluted.bind( _.map ), + mapIsEmpty : isEmpty.bind( _.map ), + mapIsPopulated : isPopulated.bind( _.map ), + mapLike : like.bind( _.map ), + + // maker + + mapMakeEmpty : makeEmpty.bind( _.map ), + mapMakeUndefined : makeUndefined.bind( _.map ), + mapMake : make.bind( _.map ), + mapCloneShallow : _.props.cloneShallow.bind( _.map ), + mapFrom : _.props.from.bind( _.map ), + + // amender + + mapExtend : _.props.extend.bind( _.map ), + mapSupplement : _.props.supplement.bind( _.map ), + +} + +Object.assign( _, ToolsExtension ); + +// + +let ExtensionMap = +{ + + // + + NamespaceName : 'map', + NamespaceNames : [ 'map' ], + NamespaceQname : 'wTools/map', + MoreGeneralNamespaceName : 'aux', + MostGeneralNamespaceName : 'props', + TypeName : 'Map', + TypeNames : [ 'Map' ], + // SecondTypeName : 'Map', + InstanceConstructor : null, + tools : _, + + // dichotomy + + is, + isPure, + isPolluted, + like, + + isEmpty, /* qqq : cover */ + isPopulated, /* qqq : cover */ + IsResizable, + + // maker + + _makeEmpty, + makeEmpty, /* qqq : for junior : cover */ + _makeUndefined, + makeUndefined, /* qqq : for junior : cover */ + _make, + make, /* qqq : for junior : cover */ + _cloneShallow, + cloneShallow : _.props.cloneShallow, /* qqq : for junior : cover */ + from : _.props.from, /* qqq : for junior : cover */ + + // properties + + _keys, + keys, /* qqq : for junior : cover */ + // onlyEnumerableKeys, /* qqq : for junior : implement and cover properly */ + allKeys, /* qqq : for junior : cover */ + + _vals, + vals, /* qqq : for junior : cover */ + // onlyEnumerableVals, /* qqq : for junior : implement and cover properly */ + allVals, /* qqq : for junior : cover */ + + _pairs, + pairs, /* qqq : for junior : cover */ + // onlyEnumerablePairs, /* qqq : for junior : implement and cover properly */ + allPairs, /* qqq : for junior : cover */ + + // amender + + _extendWithHashmap : _.props._extendWithHashmap, + _extendWithSet : _.props._extendWithSet, + _extendWithCountable : _.props._extendWithCountable, + _extendWithProps : _.props._extendWithProps, + _extendUniversal : _.props._extendUniversal, + extendUniversal : _.props.extendUniversal, + extend : _.props.extend, + + _supplementWithHashmap : _.props._supplementWithHashmap, + _supplementWithSet : _.props._supplementWithSet, + _supplementWithCountable : _.props._supplementWithCountable, + _supplementWithProps : _.props._supplementWithProps, + _supplementUniversal : _.props._supplementUniversal, + supplementUniversal : _.props.supplementUniversal, + supplement : _.props.supplement, + + // meta + + namespaceOf, + namespaceWithDefaultOf : _.props.namespaceWithDefaultOf, + _functor_functor : _.props._functor_functor, + +} + +Object.assign( _.map, ExtensionMap ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Map.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Map_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Map_s */ })(); + +/* */ /* begin of file Module_s */ ( function Module_s() { function Module_s_naked() { ( function _l1_Module_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const __ = _realGlobal_.wTools; +let ModuleFileNative = null; + +_.module = _.module || Object.create( null ); +__.module = __.module || Object.create( null ); + +// -- +// +// -- + +const _toolsPath = __dirname + '/../../../../node_modules/Tools'; +function toolsPathGet() +{ + return _toolsPath; +} + +// + +const _toolsDir = __dirname + '/../../../../wtools'; +function toolsDirGet() +{ + return _toolsDir; +} + +// -- +// module extension +// -- + +var ModuleExtension = +{ + + toolsPathGet, + toolsDirGet, + +} + +Object.assign( _.module, ModuleExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Module.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Module_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Module_s */ })(); + +/* */ /* begin of file Number_s */ ( function Number_s() { function Number_s_naked() { ( function _l1_Numbers_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.number = _.number || Object.create( null ); +_.numbers = _.number.s = _.numbers || _.number.s || Object.create( null ); + +// -- +// number +// -- + +/** + * @summary Checks if argument( src ) is a Number. + * @returns Returns true if ( src ) is a Number, otherwise returns false. + * + * @example + * numberIs( 5 ); + * // returns true + * + * @example + * numberIs( 'song' ); + * // returns false + * + * @param { * } src. + * @return {Boolean}. + * @function numberIs + * @namespace Tools + */ + +function is( src ) +{ + return typeof src === 'number'; + return Object.prototype.toString.call( src ) === '[object Number]'; +} + +// + +function like( src ) +{ + return _.number.is( src ) || _.bigInt.is( src ); +} + +// + +function isNotNan( src ) +{ + return _.number.is( src ) && !isNaN( src ); +} + +// + +function numberIsFinite( src ) +{ + if( !_.number.is( src ) ) + return false; + return isFinite( src ); +} + +// + +function isInfinite( src ) +{ + + if( !_.number.is( src ) ) + return false; + + return src === +Infinity || src === -Infinity; +} + +// + +function intIs( src ) +{ + + if( !_.number.is( src ) || !_.number.isFinite( src ) ) + return false; + + return Math.floor( src ) === src; +} + +// + +function areAll( src ) +{ + _.assert( arguments.length === 1 ); + + if( _.bufferTypedIs( src ) ) + return true; + + if( _.argumentsArray.like( src ) && !_.arrayIsEmpty( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( !_.number.is( src[ s ] ) ) + return false; + + return true; + } + + return false; +} + +// + +function areFinite( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + + if( !_.number.s.areAll( src ) ) + return false; + + if( _.longIs( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( !_.number.isFinite( src[ s ] ) ) + return false; + } + + return true; +} + +// + +function arePositive( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + + if( !_.number.s.areAll( src ) ) + return false; + + if( _.longIs( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( src[ s ] < 0 || !_.number.isNotNan( src[ s ] ) ) + return false; + } + + return true; +} + +// + +function areInt( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + + if( !_.number.s.areAll( src ) ) + return false; + + if( _.longIs( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( !_.intIs( src[ s ] ) ) + return false; + } + + return true; +} + +// -- +// number extension +// -- + +let NumberExtension = +{ + + is, + like, + + isNotNan, + isFinite : numberIsFinite, + defined : numberIsFinite, + isInfinite, + + intIs, + +} + +Object.assign( _.number, NumberExtension ); + +// -- +// numbers +// -- + +let NumbersExtension = +{ + + areAll, + + areFinite, + arePositive, + areInt, + +} + +Object.assign( _.numbers, NumbersExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + numberIs : is, + numberIsNotNan : isNotNan, + numberIsFinite, + numberDefined : numberIsFinite, + numberIsInfinite : isInfinite, + + intIs, + + numbersAreAll : areAll, + + numbersAreFinite : areFinite, + numbersArePositive : arePositive, + numbersAreInt : areInt, + +} + +Object.assign( _, ToolsExtension ); + +// + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Number.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Number_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Number_s */ })(); + +/* */ /* begin of file Object_s */ ( function Object_s() { function Object_s_naked() { ( function _l1_Object_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.object = _.object || Object.create( null ); + +// -- +// dichotomy +// -- + +/** + * Function is checks incoming param whether it is object. + * Returns "true" if incoming param is object. Othervise "false" returned. + * + * @example + * let obj = { x : 100 }; + * _.object.isBasic(obj); + * // returns true + * + * @example + * _.object.isBasic( 10 ); + * // returns false + * + * @param { * } src. + * @return { Boolean }. + * @function is + * @namespace Tools/object + */ + +function isBasic( src ) +{ + return Object.prototype.toString.call( src ) === '[object Object]'; +} + +// + +/** + * Function is checks incoming param whether it is object. + * Returns "true" if incoming param is object. Othervise "false" returned. + * + * @example + * let obj = { x : 100 }; + * _.object.is(obj); + * // returns true + * + * @example + * _.object.is( 10 ); + * // returns false + * + * @param { * } src. + * @return { Boolean }. + * @function is + * @namespace Tools/object + */ + +function is( src ) /* xxx : qqq : for junior : optimize */ +{ + + if( Object.prototype.toString.call( src ) === '[object Object]' ) + return true; + + if( _.primitive.is( src ) ) + return false; + + // if( _.vector.is( src ) ) + // return false; + + if( _.long.is( src ) ) + return false; + + if( _.set.is( src ) ) + return false; + + if( _.hashMap.is( src ) ) + return false; + + if( _.routine.isTrivial( src ) ) + return false; + + return true; +} + +// + +function like( src ) /* xxx : qqq : for junior : optimize */ +{ + return _.object.is( src ); + // if( _.object.isBasic( src ) ) + // return true; + // + // if( _.primitive.is( src ) ) + // return false; + // + // if( _.vector.is( src ) ) + // return false; + // + // if( _.routine.isTrivial( src ) ) + // return false; + // + // if( _.set.is( src ) ) + // return false; + // + // if( _.hashMap.is( src ) ) + // return false; + // + // return true; +} + +// + +function likeStandard( src ) /* xxx : qqq : for junior : optimize */ +{ + + if( _.primitive.is( src ) ) + return false; + if( _.vector.is( src ) ) + return false; + if( _.routine.isTrivial( src ) ) + return false; + if( _.set.is( src ) ) + return false; + if( _.hashMap.is( src ) ) + return false; + + if( _.date.is( src ) ) + return true + if( _.regexpIs( src ) ) + return true + if( _.bufferAnyIs( src ) ) + return true + + return false; +} + +// + +function isEmpty( src ) +{ + if( !this.like( src ) ) + return false; + return this.keys( src ).length === 0; +} + +// + +function isPopulated( src ) +{ + if( !this.like( src ) ) + return false; + return this.keys( src ).length > 0; +} + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return true; +} + +// -- +// maker +// -- + +function _makeEmpty( src ) +{ + if( src ) + { + let method = _.class.methodMakeEmptyOf( src ); + if( method ) + return method.call( src ); + } + return new src.constructor(); +} + +// + +function makeEmpty( src ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 ); + if( arguments.length === 1 ) + _.assert( this.like( src ) ); + return this._makeEmpty( src ); +} + +// + +function _makeUndefined( src ) +{ + if( src ) + { + let method = _.class.methodMakeUndefinedOf( src ); + if( method ) + return method.call( src ); + } + return new src.constructor(); +} + +// + +function makeUndefined( src, length ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( arguments.length === 2 ) + { + _.assert( this.like( src ) ); + _.assert( _.number.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( this.like( src ) ); + } + + return this._makeUndefined( src ); +} + +// + +function _make( src, length ) +{ + if( arguments.length === 1 || ( arguments.length === 2 && length === 1 ) ) + return this._cloneShallow( src ); + if( _.aux.is( src ) ) + return _.aux._cloneShallow( src ); + if( arguments.length === 2 ) + return new src.constructor( length ); + else + return new src.constructor( src ); +} + +// + +function make( src, length ) +{ + _.assert( this.like( src ) ); + _.assert( arguments.length >= 1 ); + _.assert( !_.aux.is( src ) || arguments.length === 1 || ( arguments.length === 2 && length === 1) ); + return this._make( ... arguments ); +} + +// + +function _cloneShallow( src ) +{ + let method = _.class.methodCloneShallowOf( src ); + if( method ) + return method.call( src ); + if( _.aux.is( src ) ) + return _.aux._cloneShallow( src ); + return new src.constructor( src ); +} + +// -- +// meta +// -- + +/* qqq : optimize */ +function namespaceOf( src ) +{ + + if( _.object.is( src ) ) + return _.object; + + return null; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + + // dichotomy + + objectIs : is.bind( _.object ), + objectIsBasic : isBasic.bind( _.object ), + objectIsEmpty : isEmpty.bind( _.object ), + objectIsPopulated : isPopulated.bind( _.object ), + objectLike : like.bind( _.object ), + objectLikeStandard : likeStandard.bind( _.object ), + + // maker + + objectMakeEmpty : makeEmpty.bind( _.object ), + objectMakeUndefined : makeUndefined.bind( _.object ), + objectMake : make.bind( _.object ), + objectCloneShallow : _.props.cloneShallow.bind( _.object ), + objectFrom : _.props.from.bind( _.object ), + +} + +Object.assign( _, ToolsExtension ); + +// + +let ObjectExtension = +{ + + // + + NamespaceName : 'object', + NamespaceNames : [ 'object' ], + NamespaceQname : 'wTools/object', + MoreGeneralNamespaceName : 'props', + MostGeneralNamespaceName : 'props', + TypeName : 'Object', + TypeNames : [ 'Object' ], + // SecondTypeName : 'Object', + InstanceConstructor : null, + tools : _, + + // dichotomy + + is, + isBasic, + like, + likeStandard, + + isEmpty, /* qqq : cover */ + isPopulated, /* qqq : cover */ + IsResizable, + + // maker + + _makeEmpty, + makeEmpty, /* qqq : for junior : cover */ + _makeUndefined, + makeUndefined, /* qqq : for junior : cover */ + _make, + make, /* qqq : for junior : cover */ + _cloneShallow, + cloneShallow : _.props.cloneShallow, /* qqq : for junior : cover */ + from : _.props.from, /* qqq : for junior : cover */ + + // properties + + _keys : _.props._keys, + keys : _.props.keys, /* qqq : for junior : cover */ + onlyOwnKeys : _.props.onlyOwnKeys, /* qqq : for junior : cover */ + onlyEnumerableKeys : _.props.onlyEnumerableKeys, /* qqq : for junior : implement and cover properly */ + allKeys : _.props.allKeys, /* qqq : for junior : cover */ + + _vals : _.props._vals, + vals : _.props.vals, /* qqq : for junior : cover */ + onlyOwnVals : _.props.onlyOwnVals, /* qqq : for junior : cover */ + onlyEnumerableVals : _.props.onlyEnumerableVals, /* qqq : for junior : implement and cover properly */ + allVals : _.props.allVals, /* qqq : for junior : cover */ + + _pairs : _.props._pairs, + pairs : _.props.pairs, /* qqq : for junior : cover */ + onlyOwnPairs : _.props.onlyOwnPairs, /* qqq : for junior : cover */ + onlyEnumerablePairs : _.props.onlyEnumerablePairs, /* qqq : for junior : implement and cover properly */ + allPairs : _.props.allPairs, /* qqq : for junior : cover */ + + // amender + + _extendWithHashmap : _.props._extendWithHashmap, + _extendWithSet : _.props._extendWithSet, + _extendWithCountable : _.props._extendWithCountable, + _extendWithProps : _.props._extendWithProps, + _extendUniversal : _.props._extendUniversal, + extendUniversal : _.props.extendUniversal, + extend : _.props.extend, + + _supplementWithHashmap : _.props._supplementWithHashmap, + _supplementWithSet : _.props._supplementWithSet, + _supplementWithCountable : _.props._supplementWithCountable, + _supplementWithProps : _.props._supplementWithProps, + _supplementUniversal : _.props._supplementUniversal, + supplementUniversal : _.props.supplementUniversal, + supplement : _.props.supplement, + + // meta + + namespaceOf, + namespaceWithDefaultOf : _.props.namespaceWithDefaultOf, + _functor_functor : _.props._functor_functor, + +} + +// + +Object.assign( _.object, ObjectExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Object.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Object_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Object_s */ })(); + +/* */ /* begin of file Pair_s */ ( function Pair_s() { function Pair_s_naked() { ( function _l1_Pair_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// range +// -- + +function is( src ) +{ + if( !_.longIs( src ) ) + return false; + if( src.length !== 2 ) + return false; + return true; +} + +// + +function make( src ) +{ + let result; + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + if( arguments.length === 2 ) + { + result = new Array( ... arguments ); + } + else if( arguments.length === 1 ) + { + if( _.routine.is( src ) ) + { + if( src === Array ) + result = new src( undefined, undefined ); + else + result = new src( 2 ); + } + else if( arguments[ 0 ].length === 2 ) + result = _.entity.cloneShallow( arguments[ 0 ] ); + else if( arguments[ 0 ].length === 0 ) + result = _.entity.makeUndefined( arguments[ 0 ], 2 ); + else + throw _.err( 'Length of pair should be 2' ); + } + else if( arguments.length === 0 ) + { + result = new Array( undefined, undefined ); + } + else + { + _.assert( 0, `Expects 0..2 arguments, but got ${arguments.length}` ); + } + _.assert( this.is( result ), 'Faild to make a new Pair' ); + return result; +} + +// -- +// define +// -- + +class Pair +{ + static[ Symbol.hasInstance ]( instance ) + { + return is( instance ); + } +} + +let Handler = +{ + construct( original, args ) + { + return Pair.make( ... args ); + } +}; + +const Self = new Proxy( Pair, Handler ); +Self.original = Pair; + +// + +var Extension = +{ + is, + make, +} + +// + +Object.assign( Self, Extension ); +_.assert( _.pair === undefined ); +_.pair = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Pair.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Pair_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Pair_s */ })(); + +/* */ /* begin of file Path_s */ ( function Path_s() { function Path_s_naked() { ( function _l1_Path_s_() +{ + +'use strict'; + +/** + * @summary Collection of cross-platform routines to operate paths reliably and consistently. + * @namespace wTools.path + * @extends Tools + */ + +const _global = _global_; +const _ = _global_.wTools; +_.path = _.path || Object.create( null ); + +// -- +// implementation +// -- + +// function _normalize( o ) +// { +// // let debug = 0; +// // if( 0 ) +// // debug = 1; +// +// // _.routine.assertOptions( _normalize, arguments ); +// _.assert( _.strIs( o.src ), 'Expects string' ); +// +// if( !o.src.length ) +// return ''; +// +// let result = o.src; +// +// result = this.refine( result ); +// +// // if( debug ) +// // console.log( 'normalize.refined : ' + result ); +// +// /* detrailing */ +// +// if( o.tolerant ) +// { +// /* remove "/" duplicates */ +// result = result.replace( this._delUpDupRegexp, this.upToken ); +// } +// +// let endsWithUp = false; +// let beginsWithHere = false; +// +// /* remove right "/" */ +// +// if( result !== this.upToken && !_.strEnds( result, this.upToken + this.upToken ) && _.strEnds( result, this.upToken ) ) +// { +// endsWithUp = true; +// result = _.strRemoveEnd( result, this.upToken ); +// } +// +// /* undoting */ +// +// while( !_.strBegins( result, this.hereUpToken + this.upToken ) && _.strBegins( result, this.hereUpToken ) ) +// { +// beginsWithHere = true; +// result = _.strRemoveBegin( result, this.hereUpToken ); +// } +// +// /* remove second "." */ +// +// if( result.indexOf( this.hereToken ) !== -1 ) +// { +// +// while( this._delHereRegexp.test( result ) ) +// result = result.replace( this._delHereRegexp, function( match, postSlash ) +// { +// return postSlash || ''; +// }); +// if( result === '' ) +// result = this.upToken; +// +// } +// +// /* remove .. */ +// +// if( result.indexOf( this.downToken ) !== -1 ) +// { +// +// while( this._delDownRegexp.test( result ) ) +// result = result.replace( this._delDownRegexp, function( /* match, notBegin, split, preSlash, postSlash */ ) +// { +// let match = arguments[ 0 ]; +// let notBegin = arguments[ 1 ]; +// let split = arguments[ 2 ]; +// let preSlash = arguments[ 3 ]; +// let postSlash = arguments[ 4 ]; +// +// if( preSlash === '' ) +// return notBegin; +// if( !notBegin ) +// return notBegin + preSlash; +// else +// return notBegin + ( postSlash || '' ); +// }); +// +// } +// +// /* nothing left */ +// +// if( !result.length ) +// result = '.'; +// +// /* dot and trail */ +// +// if( o.detrailing ) +// if( result !== this.upToken && !_.strEnds( result, this.upToken + this.upToken ) ) +// result = _.strRemoveEnd( result, this.upToken ); +// +// if( !o.detrailing && endsWithUp ) +// if( result !== this.rootToken ) +// result = result + this.upToken; +// +// if( !o.undoting && beginsWithHere ) +// result = this._dot( result ); +// +// // if( debug ) +// // console.log( 'normalize.result : ' + result ); +// +// return result; +// } +// +// _normalize.defaults = +// { +// src : null, +// tolerant : false, +// detrailing : false, +// undoting : false, +// } +// +// // +// +// /** +// * Regularize a path by collapsing redundant delimeters and resolving '..' and '.' segments,so A//B,A/./B and +// A/foo/../B all become A/B. This string manipulation may change the meaning of a path that contains symbolic links. +// On Windows,it converts forward slashes to backward slashes. If the path is an empty string,method returns '.' +// representing the current working directory. +// * @example +// let path = '/foo/bar//baz1/baz2//some/..' +// path = wTools.normalize( path ); // /foo/bar/baz1/baz2 +// * @param {string} src path for normalization +// * @returns {string} +// * @function normalize +// * @namespace Tools.path +// */ +// +// function normalize( src ) +// { +// let result = this._normalize({ src, tolerant : false, detrailing : false, undoting : false }); +// +// _.assert( _.strIs( src ), 'Expects string' ); +// _.assert( arguments.length === 1, 'Expects single argument' ); +// _.assert( result.lastIndexOf( this.upToken + this.hereToken + this.upToken ) === -1 ); +// _.assert( !_.strEnds( result, this.upToken + this.hereToken ) ); +// +// if( Config.debug ) +// { +// let i = result.lastIndexOf( this.upToken + this.downToken + this.upToken ); +// _.assert( i === -1 || !/\w/.test( result.substring( 0, i ) ) ); +// } +// +// return result; +// } +// +// // +// +// function canonize( src ) +// { +// let result = this._normalize({ src, tolerant : false, detrailing : true, undoting : true }); +// +// _.assert( _.strIs( src ), 'Expects string' ); +// _.assert( arguments.length === 1, 'Expects single argument' ); +// _.assert( result === this.upToken || _.strEnds( result, this.upToken + this.upToken ) || !_.strEnds( result, this.upToken ) ); +// _.assert( result.lastIndexOf( this.upToken + this.hereToken + this.upToken ) === -1 ); +// _.assert( !_.strEnds( result, this.upToken + this.hereToken ) ); +// +// if( Config.debug ) +// { +// let i = result.lastIndexOf( this.upToken + this.downToken + this.upToken ); +// _.assert( i === -1 || !/\w/.test( result.substring( 0, i ) ) ); +// } +// +// return result; +// } + +// -- +// extension +// -- + +let Extension = +{ + + // _normalize, + // normalize, + // canonize, + +} + +// + +Object.assign( _.path, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Path.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Path_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Path_s */ })(); + +/* */ /* begin of file Primitive_s */ ( function Primitive_s() { function Primitive_s_naked() { ( function _l1_Primitive_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.primitive = _.primitive || Object.create( null ); + +// -- +// primitive +// -- + + +function is( src ) +{ + if( !src ) + return true; + let t = Object.prototype.toString.call( src ); + return _.primitive._is( src, t ); +} + +// + +function like( src ) +{ + return _.primitive.is( src ); +} + +// + +function _primitiveIs_functor() +{ + const is = new Set(); + is.add( '[object Symbol]' ); + is.add( '[object Number]' ); + is.add( '[object BigInt]' ); + is.add( '[object Boolean]' ); + is.add( '[object String]' ); + return _primitiveIs; + + function _primitiveIs( src, typeStr ) + { + return is.has( typeStr ); + } + +} + +let _is = _primitiveIs_functor(); +_is.functor = _primitiveIs_functor; + +// -- +// meta +// -- + +/* qqq2 : full implementation is required */ +/* qqq2 : optimize */ +function namespaceOf( src ) +{ + + debugger; + if( _.str.is( src ) ) + return _.str; + if( _.number.is( src ) ) + return _.number; + if( _.symbol.is( src ) ) + return _.symbol; + + return null; +} + +// -- +// extension +// -- + +let PrimitiveExtension = +{ + + // + + NamespaceName : 'primitive', + NamespaceNames : [ 'primitive' ], + NamespaceQname : 'wTools/primitive', + MoreGeneralNamespaceName : 'primitive', + MostGeneralNamespaceName : 'primitive', + TypeName : 'Primitive', + TypeNames : [ 'Primitive' ], + // SecondTypeName : 'Primitive', + InstanceConstructor : null, + tools : _, + + // dichotomy + + is, + _is, + like, + + // maker + + _makeEmpty : _.blank._makeEmpty, + makeEmpty : _.blank.makeEmpty, /* qqq : for junior : cover */ + _makeUndefined : _.blank._makeUndefined, + makeUndefined : _.blank.makeUndefined, /* qqq : for junior : cover */ + _make : _.blank._make, + make : _.blank.make, /* qqq : for junior : cover */ + _cloneShallow : _.blank._cloneShallow, + cloneShallow : _.blank.cloneShallow, /* qqq : for junior : cover */ + from : _.blank.from, /* qqq : for junior : cover */ + + // meta + + namespaceOf, + namespaceWithDefaultOf : _.props.namespaceWithDefaultOf, + _functor_functor : _.props._functor_functor, + +} + +Object.assign( _.primitive, PrimitiveExtension ); + +// + +let ToolsExtension = +{ + + // dichotomy + + primitiveIs : is.bind( _.primitive ), + primitiveLike : like.bind( _.primitive ), + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Primitive.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Primitive_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Primitive_s */ })(); + +/* */ /* begin of file Printer_s */ ( function Printer_s() { function Printer_s_naked() { ( function _l1_Printer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.printer = _.printer || Object.create( null ); + +// -- +// printer +// -- + +function is( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( !src ) + return false; + + if( _.routine.is( src ) ) + return false; + + let prototype = Object.getPrototypeOf( src ); + if( !prototype ) + return false; + + if( src.MetaType === 'Printer' ) + return true; + + return false; +} + +// + +function like( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.printer.is( src ) ) + return true; + + if( _.consoleIs( src ) ) + return true; + + if( src === _global_.logger ) + return true; + + return false; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + printerIs : is, + printerLike : like, +} + +// + +let Extension = +{ + is, + like, +} + +Object.assign( _.printer, Extension ); +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Printer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Printer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Printer_s */ })(); + +/* */ /* begin of file Process_s */ ( function Process_s() { function Process_s_naked() { ( function _l1_Process_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.process = _.process || Object.create( null ); + +// -- +// +// -- + +// -- +// extension +// -- + +let Extension = +{ +} + +// + +Object.assign( _.process, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Process.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Process_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Process_s */ })(); + +/* */ /* begin of file PropertyTransformer_s */ ( function PropertyTransformer_s() { function PropertyTransformer_s_naked() { ( function _l1_PropertyTransformer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.props = _.props || Object.create( null ); +_.props.mapper = _.props.mapper || Object.create( null ); +_.props.condition = _.props.condition || Object.create( null ); + +// -- +// +// -- + +// -- +// +// -- + +let Extension = +{ +} + +Object.assign( _.props, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/PropertyTransformer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, PropertyTransformer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file PropertyTransformer_s */ })(); + +/* */ /* begin of file Prototype_s */ ( function Prototype_s() { function Prototype_s_naked() { ( function _l1_Prototype_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.prototype = _.prototype || Object.create( null ); + +// -- +// implementation +// -- + +/** + * @namespace Tools.prototype + * @module Tools/base/Proto + */ + +function _of( object ) +{ + return Object.getPrototypeOf( object ); +} + +// + +/** + * Iterate through prototypes. + * @param {object} proto - prototype + * @function each + * @namespace Tools.prototype + */ + +function each( proto, onEach ) +{ + let result = []; + + _.assert( _.routine.is( onEach ) || !onEach ); + _.assert( !_.primitive.is( proto ) || proto === null ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + while( proto ) + { + if( onEach ) + onEach.call( this, proto ); + result.push( proto ); + proto = Object.getPrototypeOf( proto ); + } + + return result; +} + +// + +function isPrototypeFor( superPrototype, subPrototype ) /* xxx : move */ +{ + _.assert( arguments.length === 2, 'Expects two arguments, probably you meant routine prototypeOf' ); + if( !superPrototype ) + return false; + if( !subPrototype ) + return false; + if( superPrototype === subPrototype ) + return true; + return Object.isPrototypeOf.call( superPrototype, subPrototype ); +} + +// + +/** + * Return proto owning names. + * @param {object} srcPrototype - src object to investigate proto stack. + * @function havingProperty + * @namespace Tools.prototype + */ + +function havingProperty( srcPrototype, name ) /* yyy qqq : names could be only string */ +{ + + _.assert( !_.primitive.is( srcPrototype ) ); + _.assert( _.strIs( name ) ); + + do + { + let has = true; + if( !Object.hasOwnProperty.call( srcPrototype, name ) ) + has = false; + if( has ) + return srcPrototype; + + srcPrototype = Object.getPrototypeOf( srcPrototype ); + } + while( srcPrototype !== Object.prototype && srcPrototype ); + + return null; +} + +// // +// +// /** +// * Does srcProto has insProto as prototype. +// * @param {object} srcProto - proto stack to investigate. +// * @param {object} insProto - proto to look for. +// * @function hasPrototype +// * @namespace Tools.prototype +// */ +// +// function hasPrototype( srcProto, insProto ) +// { +// +// while( srcProto !== null ) +// { +// if( srcProto === insProto ) +// return true; +// srcProto = Object.getPrototypeOf( srcProto ); +// } +// +// return false; +// } + +// + +function has( superPrototype, subPrototype ) /* xxx : move */ +{ + _.assert( arguments.length === 2, 'Expects two arguments' ); + // eslint-disable-next-line no-prototype-builtins + return _.prototype.isPrototypeFor( subPrototype, superPrototype ); +} + +// + +/** + * Is prototype. + * @function is + * @param {object} src - entity to check + * @namespace Tools + */ + +function is( src ) /* xxx : move */ +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + if( _.primitive.is( src ) ) + return false; + if( _.routine.is( src ) ) + return false; + return Object.hasOwnProperty.call( src, 'constructor' ); +} + +// + +function set( dst, src ) +{ + Object.setPrototypeOf( dst, src ); + return dst; +} + +// -- +// extension +// -- + +var Extension = +{ + + of : _of, + each, + isPrototypeFor, + havingProperty, + + // hasPrototype, + hasPrototype : has, /* xxx : remove */ + has, + is, + + set, + +} + +// + +var ToolsExtension = +{ + + // prototypeIsPrototypeOf : isPrototypeOf, /* xxx : remove */ + // prototypeHas : has, /* xxx : remove */ + prototypeIs : is + +} + +// + +Object.assign( Self, Extension ); +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Prototype.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Prototype_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Prototype_s */ })(); + +/* */ /* begin of file Regexp_s */ ( function Regexp_s() { function Regexp_s_naked() { ( function _l1_Regexp_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.regexp = _.regexp || Object.create( null ); +_.regexps = _.regexp.s = _.regexps || _.regexp.s || Object.create( null ); + +// -- +// regexp +// -- + +function is( src ) +{ + return Object.prototype.toString.call( src ) === '[object RegExp]'; +} + +// + +function isOld( src ) +{ + return Object.prototype.toString.call( src ) === '[object RegExp]'; +} + +// + +function isUsingInstanceOf( src ) +{ + return src instanceof RegExp; +} + +// + +function objectIs( src ) +{ + if( !_.RegexpObject ) + return false; + return src instanceof _.RegexpObject; +} + +// + +function like( src ) +{ + if( src instanceof RegExp || Object.prototype.toString.call( src ) === '[object String]' ) + return true; + return false; +} + +// + +function likeOld( src ) +{ + if( _.regexp.is( src ) || _.strIs( src ) ) + return true; + return false; +} + +// + +function likeUsingisUsingInstanceOf( src ) +{ + if( _.regexp.isUsingInstanceOf( src ) || _.strIs( src ) ) + return true; + return false; +} + +// + +function likeUnfolded( src ) +{ + if( src instanceof RegExp || Object.prototype.toString.call( src ) === '[object String]' ) + return true; + return false; +} + +// // +// +// function regexpsLike( srcs ) +// { +// if( !_.arrayIs( srcs ) ) +// return false; +// for( let s = 0 ; s < srcs.length ; s++ ) +// if( !_.regexpLike( srcs[ s ] ) ) +// return false; +// return true; +// } + +// + +function likeAll( src ) +{ + _.assert( arguments.length === 1 ); + + if( _.argumentsArray.like( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( !_.regexp.like( src[ s ] ) ) + return false; + return true; + } + + return _.regexp.like( src ); +} + +// + +/** + * Escapes special characters with a slash ( \ ). Supports next set of characters : .*+?^=! :${}()|[]/\ + * + * @example + * _.regexp.escape( 'Hello. How are you?' ); + * // returns "Hello\. How are you\?" + * + * @param {String} src Regexp string + * @returns {String} Escaped string + * @function escape + * @namespace Tools + */ + +function escape( src ) +{ + _.assert( _.strIs( src ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + return src.replace( /([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1' ); +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + + regexpIs : is, + regexpObjectIs : objectIs, + regexpLike : like, + regexpsLikeAll : likeAll, + + regexpEscape : escape, + +} + +Object.assign( _, ToolsExtension ) + +// + +let RegexpExtension = +{ + + // regexp + + is, + isOld, + isUsingInstanceOf, + objectIs, + like, + likeOld, + likeUsingisUsingInstanceOf, + likeUnfolded, + + escape, + +} + +Object.assign( _.regexp, RegexpExtension ) + +// + +let RegexpExtensions = +{ + + // regexps + + likeAll, + +} + +Object.assign( _.regexp.s, RegexpExtensions ) + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Regexp.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Regexp_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Regexp_s */ })(); + +/* */ /* begin of file Routine_s */ ( function Routine_s() { function Routine_s_naked() { ( function _l1_Routine_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.routine = _.routine || Object.create( null ); +_.routines = _.routine.s = _.routines || _.routine.s || Object.create( null ); +// _.ddds = _.ddd.s = _.ddds || _.ddd.s || Object.create( null ); + +_.routine.chainer = _.routine.chainer || Object.create( null ); +_.routine.tail = _.routine.tail || Object.create( null ); + +// -- +// routine +// -- + +function __mapButKeys( srcMap, butMap ) +{ + let result = []; + + for( let s in srcMap ) + if( !( s in butMap ) ) + result.push( s ); + + return result; +} + +// + +function __mapUndefinedKeys( srcMap ) +{ + let result = []; + + for( let s in srcMap ) + if( srcMap[ s ] === undefined ) + result.push( s ); + + return result; +} + +// + +function __keysQuote( keys ) +{ + let result = `"${ keys[ 0 ] }"`; + for( let i = 1 ; i < keys.length ; i++ ) + result += `, "${ keys[ i ] }"`; + return result.trim(); +} + +// + +function __primitiveLike( src ) +{ + if( _.primitive.is( src ) ) + return true; + if( _.regexpIs( src ) ) + return true; + if( _.routineIs( src ) ) + return true; + return false; +} + +// + +function __strType( src ) +{ + if( _.strType ) + return _.strType( src ); + return String( src ); +} + +// + +function __mapSupplementWithoutUndefined( dstMap, srcMap ) +{ + for( let k in srcMap ) + { + if( Config.debug ) + _.assert + ( + __primitiveLike( srcMap[ k ] ), + () => `Defaults map should have only primitive elements, but option::${ k } is ${ __strType( srcMap[ k ] ) }` + ); + if( dstMap[ k ] !== undefined ) + continue; + dstMap[ k ] = srcMap[ k ]; + } +} + +__mapSupplementWithoutUndefined.meta = Object.create( null ); +__mapSupplementWithoutUndefined.meta.locals = +{ + __primitiveLike, + __strType, +} + +// + +function __mapSupplementWithUndefined( dstMap, srcMap ) +{ + for( let k in srcMap ) + { + if( Config.debug ) + _.assert + ( + __primitiveLike( srcMap[ k ] ), + () => `Defaults map should have only primitive elements, but option::${ k } is ${ __strType( srcMap[ k ] ) }` + ); + if( Object.hasOwnProperty.call( dstMap, k ) ) + continue; + dstMap[ k ] = srcMap[ k ]; + } +} + +__mapSupplementWithUndefined.meta = Object.create( null ); +__mapSupplementWithUndefined.meta.locals = +{ + __primitiveLike, + __strType, +} + +// + +function __mapSupplementWithUndefinedTollerant( dstMap, srcMap ) +{ + for( let k in srcMap ) + { + if( Object.hasOwnProperty.call( dstMap, k ) ) + continue; + dstMap[ k ] = srcMap[ k ]; + } +} + +__mapSupplementWithUndefinedTollerant.meta = Object.create( null ); +__mapSupplementWithUndefinedTollerant.meta.locals = +{ +} + +// + +function __arrayFlatten( src ) +{ + let result = []; + if( src === null ) + return result; + if( !_.argumentsArray.like( src ) ) + result.push( src ); + else + for( let i = 0 ; i < src.length ; i++ ) + { + let e = src[ i ]; + if( _.array.is( e ) || _.argumentsArray.is( e ) ) + result.push( ... e ); + else + result.push( e ); + } + return result; +} + +// -- +// dichotomy +// -- + +function is( src ) +{ + let typeStr = Object.prototype.toString.call( src ); + return _.routine._is( src, typeStr ); +} + +// + +function _is( src, typeStr ) +{ + return typeStr === '[object Function]' || typeStr === '[object AsyncFunction]'; +} + +// + +function like( src ) +{ + let typeStr = Object.prototype.toString.call( src ); + return _.routine._like( src, typeStr ); +} + +// + +function _like( src, typeStr ) +{ + return typeStr === '[object Function]' || typeStr === '[object AsyncFunction]' || typeStr === '[object GeneratorFunction]' || typeStr === '[object AsyncGeneratorFunction]'; +} + +// + +function routineIsTrivial_functor() +{ + + const syncPrototype = Object.getPrototypeOf( Function ); + const asyncPrototype = Object.getPrototypeOf( _async ); + return routineIsTrivial; + + function routineIsTrivial( src ) + { + if( !src ) + return false; + let prototype = Object.getPrototypeOf( src ); + if( prototype === syncPrototype ) + return true; + if( prototype === asyncPrototype ) + return true; + return false; + } + + async function _async() + { + } + +} + +let isTrivial = routineIsTrivial_functor(); +isTrivial.functor = routineIsTrivial_functor; + +// + +function isSync( src ) +{ + return Object.prototype.toString.call( src ) === '[object Function]'; +} + +// + +function isAsync( src ) +{ + return Object.prototype.toString.call( src ) === '[object AsyncFunction]'; +} + +// + +function isGenerator( src ) +{ + let typeStr = Object.prototype.toString.call( src ); + return typeStr === '[object GeneratorFunction]' || typeStr === '[object AsyncGeneratorFunction]'; +} + +// + +function isSyncGenerator( src ) +{ + return Object.prototype.toString.call( src ) === '[object GeneratorFunction]'; +} + +// + +function isAsyncGenerator( src ) +{ + return Object.prototype.toString.call( src ) === '[object AsyncGeneratorFunction]'; +} + +// + +function are( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.argumentsArray.like( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( !_.routine.is( src[ s ] ) ) + return false; + return true; + } + + return _.routine.is( src ); +} + +// + +function withName( src ) +{ + if( !_.routine.like( src ) ) + return false; + if( !src.name ) + return false; + return true; +} + +// -- +// joiner +// -- + +/** + * Internal implementation. + * @param {object} object - object to check. + * @return {object} object - name in key/value format. + * @function _routineJoin + * @namespace Tools + */ + +function _join( o ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.bool.is( o.sealing ) ); + _.assert( _.bool.is( o.extending ) ); + _.assert( _.routine.is( o.routine ), 'Expects routine' ); + _.assert( _.longIs( o.args ) || o.args === undefined ); + + let routine = o.routine; + let args = o.args; + let context = o.context; + let result = act(); + + if( o.extending ) + { + _.props.extend( result, routine ); + + let o2 = + { + value : routine, + enumerable : false, + }; + Object.defineProperty( result, 'originalRoutine', o2 ); /* qqq : cover */ + + if( context !== undefined ) + { + let o3 = + { + value : context, + enumerable : false, + }; + Object.defineProperty( result, 'boundContext', o3 ); /* qqq : cover */ + } + + if( args !== undefined ) + { + let o3 = + { + value : args, + enumerable : false, + }; + Object.defineProperty( result, 'boundArguments', o3 ); /* qqq : cover */ + } + + } + + return result; + + /* */ + + function act() + { + + if( context !== undefined && args !== undefined ) + { + if( o.sealing === true ) + { + let name = routine.name || '__sealedContextAndArguments'; + _.assert( _.strIs( name ) ); + let __sealedContextAndArguments = + { + [ name ] : function() + { + return routine.apply( context, args ); + } + } + return __sealedContextAndArguments[ name ]; + } + else + { + // let a = _.arrayAppendArray( [ context ], args ); + let a = [ context ] + a.push( ... args ); + return Function.prototype.bind.apply( routine, a ); + } + } + else if( context !== undefined && args === undefined ) + { + if( o.sealing === true ) + { + let name = routine.name || '__sealedContext'; + let __sealedContext = + { + [ name ] : function() + { + return routine.call( context ); + } + } + return __sealedContext[ name ]; + } + else + { + return Function.prototype.bind.call( routine, context ); + } + } + else if( context === undefined && args !== undefined ) + { + if( o.sealing === true ) + { + let name = routine.name || '__sealedArguments'; + _.assert( _.strIs( name ) ); + let __sealedContextAndArguments = + { + [ name ] : function() + { + return routine.apply( this, args ); + } + } + return __sealedContextAndArguments[ name ]; + } + else + { + let name = routine.name || '__joinedArguments'; + let __joinedArguments = + { + [ name ] : function() + { + // let args2 = _.arrayAppendArrays( null, [ args, arguments ] ); + let args2 = [ ... args, ... arguments ]; + return routine.apply( this, args2 ); + } + } + return __joinedArguments[ name ]; + } + } + else if( context === undefined && args === undefined ) /* zzz */ + { + return routine; + } + else _.assert( 0 ); + } + +} + +// + +function constructorJoin( routine, args ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + + return _.routine._join + ({ + routine, + context : routine, + args : args || [], + sealing : false, + extending : false, + }); + +} + +// + +/** + * The join() routine creates a new function with its 'this' ( context ) set to the provided `context` + * value. Argumetns `args` of target function which are passed before arguments of binded function during + * calling of target function. Unlike bind routine, position of `context` parameter is more intuitive. + * + * @example + * let o = { z: 5 }; + * let y = 4; + * function sum( x, y ) + * { + * return x + y + this.z; + * } + * let newSum = _.routine.join( o, sum, [ 3 ] ); + * newSum( y ); + * // returns 12 + * + * @example + * function f1() + * { + * console.log( this ) + * }; + * let f2 = f1.bind( undefined ); // context of new function sealed to undefined (or global object); + * f2.call( o ); // try to call new function with context set to { z: 5 } + * let f3 = _.routine.join( undefined, f1 ); // new function. + * f3.call( o ) + * // log { z: 5 } + * + * @param {Object} context The value that will be set as 'this' keyword in new function + * @param {Function} routine Function which will be used as base for result function. + * @param {Array<*>} args Argumetns of target function which are passed before arguments of binded function during + calling of target function. Must be wraped into array. + * @returns {Function} New created function with preceding this, and args. + * @throws {Error} When second argument is not callable throws error with text 'first argument must be a routine' + * @thorws {Error} If passed arguments more than 3 throws error with text 'Expects 3 or less arguments' + * @function join + * @namespace Tools + */ + +function join( context, routine, args ) +{ + + _.assert( arguments.length <= 3, 'Expects 3 or less arguments' ); + + return _.routine._join + ({ + routine, + context, + args, + sealing : false, + extending : true, + }); + +} + +// + +/** + * The join() routine creates a new function with its 'this' ( context ) set to the provided `context` + * value. Argumetns `args` of target function which are passed before arguments of binded function during + * calling of target function. Unlike bind routine, position of `context` parameter is more intuitive. + * + * @example + * let o = { z: 5 }; + * let y = 4; + * function sum( x, y ) + * { + * return x + y + this.z; + * } + * let newSum = _.routine.join( o, sum, [ 3 ] ); + * newSum( y ); + * // returns 12 + * + * @example + * function f1() + * { + * console.log( this ) + * }; + * let f2 = f1.bind( undefined ); // context of new function sealed to undefined (or global object); + * f2.call( o ); // try to call new function with context set to { z: 5 } + * let f3 = _.routine.join( undefined, f1 ); // new function. + * f3.call( o ) + * // log { z: 5 } + * + * @param {Object} context The value that will be set as 'this' keyword in new function + * @param {Function} routine Function which will be used as base for result function. + * @param {Array<*>} args Argumetns of target function which are passed before arguments of binded function during + calling of target function. Must be wraped into array. + * @returns {Function} New created function with preceding this, and args. + * @throws {Error} When second argument is not callable throws error with text 'first argument must be a routine' + * @thorws {Error} If passed arguments more than 3 throws error with text 'Expects 3 or less arguments' + * @function routineJoin + * @namespace Tools + */ + +function join( context, routine, args ) +{ + + _.assert( arguments.length <= 3, 'Expects 3 or less arguments' ); + + return _.routine._join + ({ + routine, + context, + args, + sealing : false, + extending : true, + }); + +} + +// + +/** + * Return new function with sealed context and arguments. + * + * @example + * let o = { z : 5 }; + * function sum( x, y ) + * { + * return x + y + this.z; + * } + * let newSum = _.routine.seal( o, sum, [ 3, 4 ] ); + * newSum(); + * // returns : 12 + * + * @param { Object } context - The value that will be set as 'this' keyword in new function + * @param { Function } routine - Function which will be used as base for result function. + * @param { Array } args - Arguments wrapped into array. Will be used as argument to `routine` function + * @returns { Function } - Result function with sealed context and arguments. + * @function seal + * @namespace Tools + */ + +function seal( context, routine, args ) +{ + + _.assert( arguments.length <= 3, 'Expects 3 or less arguments' ); + + return _.routine._join + ({ + routine, + context, + args, + sealing : true, + extending : true, + }); + +} + +// -- +// options +// -- + +// // +// +// function mapOptionsApplyDefaults( options, defaults ) +// { +// +// _.assert( arguments.length === 2 ); +// _.map.assertHasOnly( options, defaults, `Does not expect options:` ); +// _.mapSupplementStructureless( options, defaults ); +// _.map.assertHasNoUndefine( options, `Options map should have no undefined fileds, but it does have` ); +// +// return options; +// } + +/* qqq : for Dmytro : bad : discuss +should be { defaults : {} } in the first argument +*/ + +function optionsWithoutUndefined( routine, options ) +{ + + if( _.argumentsArray.like( options ) ) + { + _.assert + ( + options.length === 0 || options.length === 1, + `Expects single options map, but got ${options.length} arguments` + ); + if( options.length === 0 ) + options = Object.create( null ) + else + options = options[ 0 ]; + } + + if( Config.debug ) + { + _.assert( arguments.length === 2, 'Expects exactly 2 arguments' ); + _.assert( _.routineIs( routine ) || _.aux.is( routine ) || routine === null, 'Expects an object with options' ); + _.assert( _.object.isBasic( options ) || options === null, 'Expects an object with options' ); + } + + if( options === null || options === undefined ) + options = Object.create( null ); + + let name = routine.name || ''; + let defaults = routine.defaults; + _.assert( _.aux.is( defaults ), `Expects map of defaults, but got ${_.strType( defaults )}` ); + + // if( options === undefined ) /* qqq : for Dmytro : bad : should be error */ + // options = Object.create( null ); + // if( defaults === null ) + // defaults = Object.create( null ); + + // let name = _.routineIs( defaults ) ? defaults.name : ''; + // defaults = ( _.routineIs( defaults ) && defaults.defaults ) ? defaults.defaults : defaults; + // _.assert( _.aux.is( defaults ), 'Expects defined defaults' ); + + /* */ + + if( Config.debug ) + { + let extraKeys = __mapButKeys( options, defaults ); + _.assert( extraKeys.length === 0, () => `Routine "${ name }" does not expect options: ${ __keysQuote( extraKeys ) }` ); + } + + __mapSupplementWithoutUndefined( options, defaults ); + + if( Config.debug ) + { + let undefineKeys = __mapUndefinedKeys( options ); + _.assert + ( + undefineKeys.length === 0, + () => `Options map for routine "${ name }" should have no undefined fields, but it does have ${ __keysQuote( undefineKeys ) }` + ); + } + + return options; +} + +optionsWithoutUndefined.meta = Object.create( null ); +optionsWithoutUndefined.meta.locals = +{ + __mapButKeys, + __mapUndefinedKeys, + __keysQuote, + __mapSupplementWithoutUndefined, +} + +// + +function assertOptionsWithoutUndefined( routine, options ) +{ + + if( _.argumentsArray.like( options ) ) + { + _.assert + ( + options.length === 0 || options.length === 1, + `Expects single options map, but got ${options.length} arguments` + ); + options = options[ 0 ]; + } + + if( Config.debug ) + { + _.assert( arguments.length === 2, 'Expects exactly 2 arguments' ); + _.assert( _.routineIs( routine ) || _.aux.is( routine ) || routine === null, 'Expects an object with options' ); + _.assert( _.object.isBasic( options ) || options === null, 'Expects an object with options' ); + } + + let name = routine.name || ''; + let defaults = routine.defaults; + _.assert( _.aux.is( defaults ), `Expects map of defaults, but got ${_.strType( defaults )}` ); + + /* */ + + if( Config.debug ) + { + + let extraKeys = __mapButKeys( options, defaults ); + _.assert( extraKeys.length === 0, () => `Routine "${ name }" does not expect options: ${ __keysQuote( extraKeys ) }` ); + + let undefineKeys = __mapUndefinedKeys( options ); + _.assert + ( + undefineKeys.length === 0, + () => `Options map for routine "${ name }" should have no undefined fields, but it does have ${ __keysQuote( undefineKeys ) }` + ); + + for( let k in defaults ) + { + _.assert + ( + __primitiveLike( defaults[ k ] ), + () => `Defaults map should have only primitive elements, but option::${ k } is ${ __strType( defaults[ k ] ) }` + ); + _.assert + ( + Reflect.has( options, k ), + `Options map does not have option::${k}` + ) + } + + } + + return options; +} + +assertOptionsWithoutUndefined.meta = Object.create( null ); +assertOptionsWithoutUndefined.meta.locals = +{ + __mapButKeys, + __mapUndefinedKeys, + __keysQuote, + __primitiveLike, + __strType, +} + +// + +function optionsWithUndefined( routine, options ) +{ + + if( _.argumentsArray.like( options ) ) + { + _.assert + ( + options.length === 0 || options.length === 1, + `Expects single options map, but got ${options.length} arguments` + ); + if( options.length === 0 ) + options = Object.create( null ) + else + options = options[ 0 ]; + } + + if( Config.debug ) + { + _.assert( arguments.length === 2, 'Expects exactly 2 arguments' ); + _.assert( _.routineIs( routine ) || _.aux.is( routine ) || routine === null, 'Expects an object with options' ); + _.assert( _.object.isBasic( options ) || options === null, 'Expects an object with options' ); + } + + if( options === null ) + options = Object.create( null ); + let name = routine.name || ''; + let defaults = routine.defaults; + _.assert( _.aux.is( defaults ), `Expects map of defaults, but got ${_.strType( defaults )}` ); + + /* */ + + if( Config.debug ) + { + let extraKeys = __mapButKeys( options, defaults ); + _.assert( extraKeys.length === 0, () => `Routine "${ name }" does not expect options: ${ __keysQuote( extraKeys ) }` ); + } + + __mapSupplementWithUndefined( options, defaults ); + + return options; +} + +optionsWithUndefined.meta = Object.create( null ); +optionsWithUndefined.meta.locals = +{ + __keysQuote, + __mapSupplementWithUndefined, +} + +// + +function optionsWithUndefinedTollerant( routine, options ) +{ + if( _.argumentsArray.like( options ) ) + { + _.assert + ( + options.length === 0 || options.length === 1, + `Expects single options map, but got ${options.length} arguments` + ); + if( options.length === 0 ) + options = Object.create( null ) + else + options = options[ 0 ]; + } + + if( Config.debug ) + { + _.assert( arguments.length === 2, 'Expects exactly 2 arguments' ); + _.assert( _.routineIs( routine ) || _.aux.is( routine ) || routine === null, 'Expects an object with options' ); + _.assert( _.object.isBasic( options ) || options === null, 'Expects an object with options' ); + } + + if( options === null ) + options = Object.create( null ); + let name = routine.name || ''; + let defaults = routine.defaults; + _.assert( _.aux.is( defaults ), `Expects map of defaults, but got ${_.strType( defaults )}` ); + + /* */ + + if( Config.debug ) + { + let extraKeys = __mapButKeys( options, defaults ); + _.assert( extraKeys.length === 0, () => `Routine "${ name }" does not expect options: ${ __keysQuote( extraKeys ) }` ); + } + + __mapSupplementWithUndefinedTollerant( options, defaults ); + + return options; +} + +optionsWithUndefinedTollerant.meta = Object.create( null ); +optionsWithUndefinedTollerant.meta.locals = +{ + __keysQuote, + __mapSupplementWithUndefinedTollerant, +} + + +// + +function assertOptionsWithUndefined( routine, options ) +{ + + if( _.argumentsArray.like( options ) ) + { + _.assert + ( + options.length === 0 || options.length === 1, + `Expects single options map, but got ${options.length} arguments` + ); + options = options[ 0 ]; + } + + if( Config.debug ) + { + _.assert( arguments.length === 2, 'Expects exactly 2 arguments' ); + _.assert( _.routineIs( routine ) || _.aux.is( routine ) || routine === null, 'Expects an object with options' ); + _.assert( _.object.isBasic( options ) || options === null, 'Expects an object with options' ); + } + + let name = routine.name || ''; + let defaults = routine.defaults; + _.assert( _.aux.is( defaults ), `Expects map of defaults, but got ${_.strType( defaults )}` ); + + /* */ + + if( Config.debug ) + { + + let extraKeys = __mapButKeys( options, defaults ); + _.assert( extraKeys.length === 0, () => `Routine "${ name }" does not expect options: ${ __keysQuote( extraKeys ) }` ); + + for( let k in defaults ) + { + _.assert + ( + __primitiveLike( defaults[ k ] ), + () => `Defaults map should have only primitive elements, but option::${ k } is ${ __strType( defaults[ k ] ) }` + ); + _.assert + ( + Reflect.has( options, k ), + `Options map does not have option::${k}` + ) + } + + } + + return options; +} + +assertOptionsWithUndefined.meta = Object.create( null ); +assertOptionsWithUndefined.meta.locals = +{ + __keysQuote, + __primitiveLike, + __strType, +} + +// + +function _verifyDefaults( defaults ) +{ + + for( let k in defaults ) + { + _.assert + ( + __primitiveLike( defaults[ k ] ), + () => `Defaults map should have only primitive elements, but option::${ k } is ${ __strType( defaults[ k ] ) }` + ); + } + +} + +_verifyDefaults.meta = Object.create( null ); +_verifyDefaults.meta.locals = +{ + __primitiveLike, + __strType, +} + +// -- +// amend +// -- + +/* qqq : for Dmytro : cover and optimize */ + +function _amend( o ) +{ + let dst = o.dst; + let srcs = o.srcs; + let srcIsVector = _.vector.is( srcs ); + let extended = false; + + _.assert( arguments.length === 1 ); + _.routine.assertOptions( _amend, o ); + _.assert( _.routine.is( dst ) || dst === null ); + _.assert( srcs === null || srcs === undefined || _.aux.is( srcs ) || _.routine.is( srcs ) || _.vector.is( srcs ) ); + _.assert( o.amending === 'extending', 'not implemented' ); + _.assert + ( + o.strategy === 'cloning' || o.strategy === 'replacing' || o.strategy === 'inheriting', + () => `Unknown strategy ${o.strategy}` + ); + + /* generate dst routine */ + + if( dst === null ) /* qqq : for Dmytro : good coverage required */ + dst = _dstMake( srcs ); + + /* extend dst routine */ + + let _dstAmend; + if( o.strategy === 'cloning' ) + _dstAmend = _dstAmendCloning; + else if( o.strategy === 'replacing' ) + _dstAmend = _dstAmendReplacing; + else if( o.strategy === 'inheriting' ) + _dstAmend = _dstAmendInheriting; + else _.assert( 0, 'not implemented' ); + + if( srcIsVector ) + for( let src of srcs ) + _dstAmend( dst, src ); + else + _dstAmend( dst, srcs ); + + /* qqq : for Dmytro : it should be optimal, no redundant cloning of body should happen + check and cover it by good test, please + */ + if( extended ) + if( dst.body ) + dst.body = bodyFrom( dst.body ); + + if( Config.debug ) + { + /* qqq : for Dmytro : cover, please */ + if( _.strEnds( dst.name, '_body' ) ) + { + _.assert( dst.body === undefined, 'Body of routine should not have its own body' ); + _.assert( dst.head === undefined, 'Body of routine should not have its own head' ); + _.assert( dst.tail === undefined, 'Body of routine should not have its own tail' ); + } + // xxx : uncomment? + // if( dst.defaults ) + // _.routine._verifyDefaults( dst.defaults ); + } + + return dst; + + /* */ + + function _dstMake( srcs ) + { + let dstMap = Object.create( null ); + + /* qqq : option amendment influence on it */ + if( srcIsVector ) + for( let src of srcs ) + { + if( src === null ) + continue; + _.props.extend( dstMap, src ); + } + else + { + if( srcs !== null ) + _.props.extend( dstMap, srcs ); + } + + let dstRoutine = null; + if( dstMap.body ) + { + dstRoutine = _.routine.unite + ({ + head : dstMap.head || null, + body : dstMap.body || null, + tail : dstMap.tail || null, + name : dstMap.name || null, + strategy : o.strategy, + }); + } + else + { + if( srcIsVector ) + dstRoutine = dstFrom( srcs[ 0 ] ); + else + dstRoutine = dstFrom( srcs ); + } + + _.assert( _.routine.is( dstRoutine ) ); + + return dstRoutine; + } + + /* */ + + function _dstAmendCloning( dst, src ) + { + _.assert( !!dst ); + _.assert( _.aux.is( src ) || _.routine.is( src ) ); + for( let s in src ) + { + let property = src[ s ]; + if( dst[ s ] === property ) + continue; + let d = Object.getOwnPropertyDescriptor( dst, s ); + if( d && !d.writable ) + continue; + extended = true; + if( _.object.isBasic( property ) ) + { + _.assert( !_.props.own( dst, s ) || _.object.isBasic( dst[ s ] ) ); + + if( dst[ s ] ) + _.props.extend( dst[ s ], property ); + else + dst[ s ] = property = _.props.extend( null, property ); + } + else + { + dst[ s ] = property; + } + } + } + + /* */ + + function _dstAmendInheriting( dst, src ) + { + _.assert( !!dst ); + _.assert( _.aux.is( src ) || _.routine.is( src ) ); + /* qqq : for Dmytro : on extending should inherit from the last one, on supplementing should inherit from the first one + implement, and cover in separate test + */ + for( let s in src ) + { + let property = src[ s ]; + if( dst[ s ] === property ) + continue; + let d = Object.getOwnPropertyDescriptor( dst, s ); + if( d && !d.writable ) + continue; + extended = true; + if( _.object.isBasic( property ) ) + { + property = Object.create( property ); + if( dst[ s ] ) + _.props.supplement( property, dst[ s ] ); + } + dst[ s ] = property; + } + } + + /* */ + + function _dstAmendReplacing( dst, src ) + { + _.assert( !!dst ); + _.assert( _.aux.is( src ) || _.routine.is( src ) ); + for( let s in src ) + { + let property = src[ s ]; + if( dst[ s ] === property ) + continue; + let d = Object.getOwnPropertyDescriptor( dst, s ); + if( d && !d.writable ) + continue; + extended = true; + dst[ s ] = property; + } + } + + /* */ + + function bodyFrom() + { + const body = dst.body; + let body2 = body; + _.assert( body.head === undefined, 'Body should not have own head' ); + _.assert( body.tail === undefined, 'Body should not have own tail' ); + _.assert( body.body === undefined, 'Body should not have own body' ); + { + let srcs; + if( srcIsVector ) + { + srcs = o.srcs.map( (src ) => propertiesBut( src ) ); + } + else + { + srcs = [ propertiesBut( o.srcs ) ]; + } + srcs.unshift( body ); + body2 = _.routine._amend + ({ + dst : o.strategy === 'replacing' ? body2 : null, + srcs, + strategy : o.strategy, + amending : o.amending, + }); + _.assert( body2.head === undefined, 'Body should not have own head' ); + _.assert( body2.tail === undefined, 'Body should not have own tail' ); + _.assert( body2.body === undefined, 'Body should not have own body' ); + } + return body2; + } + + /* */ + + function propertiesBut( src ) + { + if( !src ) + return src; + let result = _.props.extend( null, src ); + delete result.head; + delete result.body; + delete result.tail; + return result; + } + + /* */ + + /* xxx : make routine? */ + function routineClone( routine ) + { + _.assert( _.routine.is( routine ) ); + let name = routine.name; + // const routine2 = routine.bind(); + // _.assert( routine2 !== routine ); + const routine2 = + ({ + [ name ] : function() + { + return routine.apply( this, arguments ); + } + })[ name ]; + + let o2 = + { + value : routine, + enumerable : false, + }; + Object.defineProperty( routine2, 'originalRoutine', o2 ); /* qqq : for Dmytro : cover */ + + return routine2; + } + + /* */ + + function dstFrom( routine ) + { + return routineClone( routine ); + } +} + +// function _amend( o ) +// { +// let dst = o.dst; +// let srcs = o.srcs; +// let srcIsVector = _.vectorIs( srcs ); +// let extended = false; +// +// _.routine.assertOptions( _amend, o ); +// _.assert( arguments.length === 1 ); +// _.assert( _.routine.is( dst ) || dst === null ); +// _.assert( srcs === null || srcs === undefined || _.aux.is( srcs ) || _.routine.is( srcs ) || _.vector.is( srcs ) ); +// _.assert( o.amending === 'extending', 'not implemented' ); +// _.assert +// ( +// o.strategy === 'cloning' || o.strategy === 'replacing' || o.strategy === 'inheriting', +// () => `Unknown strategy ${o.strategy}` +// ); +// +// /* generate dst routine */ +// +// if( dst === null ) /* qqq : for Dmytro : good coverage required */ +// dst = _dstMake( srcs ); +// +// // /* shallow clone properties of dst routine */ +// // +// // if( o.strategy === 'cloning' ) +// // _fieldsClone( dst ); +// // else if( o.strategy === 'inheriting' ) +// // _fieldsInherit( dst ); +// +// /* extend dst routine */ +// +// let _dstAmend; +// if( o.strategy === 'cloning' ) +// _dstAmend = _dstAmendCloning; +// else if( o.strategy === 'replacing' ) +// _dstAmend = _dstAmendReplacing; +// else if( o.strategy === 'inheriting' ) +// _dstAmend = _dstAmendInheriting; +// else _.assert( 0, 'not implemented' ); +// +// if( srcIsVector ) +// for( let src of srcs ) +// _dstAmend( dst, src ); +// else +// _dstAmend( dst, srcs ); +// +// /* qqq : for Dmytro : it should be optimal, no redundant cloning of body should happen +// check and cover it by good test, please +// */ +// if( extended ) +// // if( dst.body && dst.body.defaults ) +// if( dst.body ) +// dst.body = bodyFrom( dst.body ); +// +// if( Config.debug ) +// { +// /* qqq : for Dmytro : cover, please */ +// if( _.strEnds( dst.name, '_body' ) ) +// { +// _.assert( dst.body === undefined, 'Body of routine should not have its own body' ); +// _.assert( dst.head === undefined, 'Body of routine should not have its own head' ); +// _.assert( dst.tail === undefined, 'Body of routine should not have its own tail' ); +// } +// // xxx : uncomment? +// // if( dst.defaults ) +// // _.routine._verifyDefaults( dst.defaults ); +// } +// +// return dst; +// +// /* */ +// +// function _dstMake( srcs ) +// { +// let dstMap = Object.create( null ); +// +// /* qqq : option amendment influence on it */ +// if( srcIsVector ) +// for( let src of srcs ) +// { +// if( src === null ) +// continue; +// _.props.extend( dstMap, src ); +// } +// else +// { +// if( srcs !== null ) +// _.props.extend( dstMap, srcs ); +// } +// +// if( dstMap.body ) +// { +// // dst = _.routine.uniteCloning( dstMap.head, dstMap.body ); +// dst = _.routine.unite +// ({ +// head : dstMap.head || null, +// body : dstMap.body || null, +// tail : dstMap.tail || null, +// name : dstMap.name || null, +// strategy : o.strategy, +// }); +// } +// else +// { +// if( srcIsVector ) +// dst = dstFrom( srcs[ 0 ] ); +// else +// dst = dstFrom( srcs ); +// } +// +// _.assert( _.routineIs( dst ) ); +// // _.props.extend( dst, dstMap ); +// +// return dst; +// } +// +// /* */ +// +// // function _fieldsClone( dst ) +// // { +// // +// // for( let s in dst ) +// // { +// // let property = dst[ s ]; +// // if( _.object.isBasic( property ) ) +// // { +// // property = _.props.extend( null, property ); +// // dst[ s ] = property; +// // } +// // } +// // +// // } +// // +// // /* */ +// // +// // function _fieldsInherit( dst ) +// // { +// // +// // for( let s in dst ) +// // { +// // let property = dst[ s ]; +// // if( _.object.isBasic( property ) ) +// // { +// // property = Object.create( property ); +// // dst[ s ] = property; +// // } +// // } +// // +// // } +// +// /* */ +// +// function _dstAmendCloning( dst, src ) +// { +// _.assert( !!dst ); +// _.assert( _.aux.is( src ) || _.routine.is( src ) ); +// for( let s in src ) +// { +// let property = src[ s ]; +// if( dst[ s ] === property ) +// continue; +// let d = Object.getOwnPropertyDescriptor( dst, s ); +// if( d && !d.writable ) +// continue; +// extended = true; +// if( _.object.isBasic( property ) ) +// { +// _.assert( !_.props.own( dst, s ) || _.object.isBasic( dst[ s ] ) ); +// +// if( dst[ s ] ) +// _.props.extend( dst[ s ], property ); +// else +// dst[ s ] = property = _.props.extend( null, property ); +// +// // property = _.props.extend( null, property ); +// // if( dst[ s ] ) +// // _.props.supplement( property, dst[ s ] ); +// } +// else +// { +// dst[ s ] = property; +// } +// } +// } +// +// /* */ +// +// function _dstAmendInheriting( dst, src ) +// { +// _.assert( !!dst ); +// _.assert( _.aux.is( src ) || _.routine.is( src ) ); +// /* qqq : for Dmytro : on extending should inherit from the last one, on supplementing should inherit from the first one +// implement, and cover in separate test +// */ +// for( let s in src ) +// { +// let property = src[ s ]; +// if( dst[ s ] === property ) +// continue; +// let d = Object.getOwnPropertyDescriptor( dst, s ); +// if( d && !d.writable ) +// continue; +// extended = true; +// if( _.object.isBasic( property ) ) +// { +// property = Object.create( property ); +// if( dst[ s ] ) +// _.props.supplement( property, dst[ s ] ); +// } +// dst[ s ] = property; +// } +// } +// +// /* */ +// +// function _dstAmendReplacing( dst, src ) +// { +// _.assert( !!dst ); +// _.assert( _.aux.is( src ) || _.routine.is( src ) ); +// for( let s in src ) +// { +// let property = src[ s ]; +// if( dst[ s ] === property ) +// continue; +// let d = Object.getOwnPropertyDescriptor( dst, s ); +// if( d && !d.writable ) +// continue; +// extended = true; +// dst[ s ] = property; +// } +// } +// +// /* */ +// +// function bodyFrom() +// { +// const body = dst.body; +// let body2 = body; +// _.assert( body.head === undefined, 'Body should not have own head' ); +// _.assert( body.tail === undefined, 'Body should not have own tail' ); +// _.assert( body.body === undefined, 'Body should not have own body' ); +// { +// // let srcs = srcIsVector ? _.map_( null, o.srcs, ( src ) => propertiesBut( src ) ) : [ propertiesBut( o.srcs ) ]; +// let srcs; +// if( srcIsVector ) +// { +// // debugger; +// srcs = o.srcs.map( (src ) => propertiesBut( src ) ); +// } +// else +// { +// srcs = [ propertiesBut( o.srcs ) ]; +// } +// srcs.unshift( body ); +// body2 = _.routine._amend +// ({ +// dst : o.strategy === 'replacing' ? body2 : null, +// srcs, +// strategy : o.strategy, +// amending : o.amending, +// }); +// _.assert( body2.head === undefined, 'Body should not have own head' ); +// _.assert( body2.tail === undefined, 'Body should not have own tail' ); +// _.assert( body2.body === undefined, 'Body should not have own body' ); +// } +// return body2; +// } +// +// /* */ +// +// function propertiesBut( src ) +// { +// if( !src ) +// return src; +// let result = _.props.extend( null, src ); +// delete result.head; +// delete result.body; +// delete result.taul; +// // return src ? _.mapBut_( null, src, [ 'head', 'body', 'tail' ] ) : src; +// return result; +// } +// +// /* */ +// +// /* xxx : make routine? */ +// function routineClone( routine ) +// { +// _.assert( _.routine.is( routine ) ); +// let name = routine.name; +// // const routine2 = routine.bind(); +// // _.assert( routine2 !== routine ); +// const routine2 = +// ({ +// [ name ] : function() +// { +// return routine.apply( this, arguments ); +// } +// })[ name ]; +// +// let o2 = +// { +// value : routine, +// enumerable : false, +// }; +// Object.defineProperty( routine2, 'originalRoutine', o2 ); /* qqq : for Dmytro : cover */ +// +// return routine2; +// } +// +// /* */ +// +// function dstFrom( routine ) +// { +// return routineClone( routine ); +// } +// +// /* */ +// +// } + +_amend.defaults = +{ + dst : null, + srcs : null, + strategy : 'cloning', /* qqq : for Dmytro : cover */ + amending : 'extending', /* qqq : for Dmytro : implement and cover */ +} + +// + +/** + * The routine _.routine.extendCloning() is used to copy the values of all properties + * from source routine to a target routine. + * + * It takes first routine (dst), and shallow clone each destination property of type map. + * Then it checks properties of source routine (src) and extends dst by source properties. + * The dst properties can be owerwriten by values of source routine + * if descriptor (writable) of dst property is set. + * + * If the first routine (dst) is null then + * routine _.routine.extendCloning() makes a routine from routines head and body + * @see {@link wTools.routine.unite} - Automatic routine generating + * from preparation routine and main routine (body). + * + * @param{ routine } dst - The target routine or null. + * @param{ * } src - The source routine or object to copy. + * + * @example + * var src = + * { + * head : _.routine.s.compose.head, + * body : _.routine.s.compose.body, + * someOption : 1, + * } + * var got = _.routine.extendCloning( null, src ); + * // returns [ routine routinesCompose ], got.option === 1 + * + * @example + * _.routine.extendCloning( null, _.routine.s.compose ); + * // returns [ routine routinesCompose ] + * + * @example + * _.routine.extendCloning( _.routine.s.compose, { someOption : 1 } ); + * // returns [ routine routinesCompose ], routinesCompose.someOption === 1 + * + * @example + * _.routine.s.composes.someOption = 22; + * _.routine.extendCloning( _.routine.s.compose, { someOption : 1 } ); + * // returns [ routine routinesCompose ], routinesCompose.someOption === 1 + * + * @returns { routine } It will return the target routine with extended properties. + * @function extendCloning + * @throws { Error } Throw an error if arguments.length < 1 or arguments.length > 2. + * @throws { Error } Throw an error if dst is not routine or not null. + * @throws { Error } Throw an error if dst is null and src has not head and body properties. + * @throws { Error } Throw an error if src is primitive value. + * @namespace Tools + */ + +function extendCloning( dst, ... srcs ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 || arguments.length === 3 ); + return _.routine._amend + ({ + dst, + srcs : [ ... srcs ], + strategy : 'cloning', + amending : 'extending', + }); + +} + +// qqq : for Dmytro : cover please +function extendInheriting( dst, ... srcs ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 || arguments.length === 3 ); + return _.routine._amend + ({ + dst, + srcs : [ ... srcs ], + strategy : 'inheriting', + amending : 'extending', + }); + +} + +// +/*qqq : for Dmytro : cover please */ +function extendReplacing( dst, ... srcs ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 || arguments.length === 3 ); + return _.routine._amend + ({ + dst, + srcs : [ ... srcs ], + strategy : 'replacing', + amending : 'extending', + }); + +} + +// + +function defaults( dst, src, defaults ) +{ + + if( arguments.length === 2 ) + { + defaults = arguments[ 1 ]; + _.assert( _.aux.is( defaults ) ); + return _.routine.extend( dst, { defaults } ); + } + else + { + _.assert( arguments.length === 3 ); + _.assert( _.aux.is( defaults ) ); + return _.routine.extend( dst, src, { defaults } ); + } + + // _.assert( dst === null || src === null ); + // _.assert( _.aux.is( defaults ) ); + // return _.routine.extend( dst, src, { defaults } ); +} + +// -- +// unite +// -- + +function unite_head( routine, args ) +{ + let o = args[ 0 ]; + + if( args[ 1 ] !== undefined ) + { + if( args.length === 3 ) + o = { head : args[ 0 ], body : args[ 1 ], tail : args[ 2 ] }; + else + o = { head : args[ 0 ], body : ( args.length > 1 ? args[ 1 ] : null ) }; + } + + _.routine.optionsWithoutUndefined( routine, o ); + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + _.assert( arguments.length === 2 ); + _.assert + ( + o.head === null || _.numberIs( o.head ) || _.routine.is( o.head ) || _.routine.s.are( o.head ) + , 'Expects either routine, routines or number of arguments {-o.head-}' + ); + _.assert( _.routine.is( o.body ), 'Expects routine {-o.body-}' ); + _.assert( o.tail === null || _.routine.is( o.tail ), () => `Expects routine {-o.tail-}, but got ${_.entity.strType( o.tail )}` ); + _.assert( o.body.defaults !== undefined, 'Body should have defaults' ); + + return o; +} + +// + +function unite_body( o ) +{ + + if( _.longIs( o.head ) ) + { + /* xxx : deprecate compose */ + /* qqq : for Dmytro : implement without compose */ + // let _head = _.routine.s.compose( o.head, function( /* args, result, op, k */ ) + // { + // let args = arguments[ 0 ]; + // let result = arguments[ 1 ]; + // let op = arguments[ 2 ]; + // let k = arguments[ 3 ]; + // _.assert( arguments.length === 4 ); + // _.assert( !_.unrollIs( result ) ); + // _.assert( _.object.isBasic( result ) ); + // return _.unrollAppend([ unitedRoutine, [ result ] ]); + // }); + let _head = _.routine.s.compose( o.head, function( /* args, result, op, k */ ) + { + let args = arguments[ 0 ]; + let result = arguments[ 1 ]; + let op = arguments[ 2 ]; + let k = arguments[ 3 ]; + _.assert( arguments.length === 4 ); + _.assert( !_.unrollIs( result ) ); + _.assert( _.object.isBasic( result ) ); + return _.unroll.from([ unitedRoutine, [ result ] ]); + }); + _.assert( _.routine.is( _head ) ); + o.head = function head() + { + let result = _head.apply( this, arguments ); + return result[ result.length-1 ]; + } + o.head.composed = _head.composed; + } + else if( _.number.is( o.head ) ) + { + o.head = headWithNargs_functor( o.head, o.body ); + } + + if( o.head === null ) + { + /* qqq : for Dmytro : cover please */ + if( o.body.defaults ) + o.head = headWithDefaults; + else + o.head = headWithoutDefaults; + } + + if( !o.name ) + { + _.assert( _.strDefined( o.body.name ), 'Body routine should have name' ); + o.name = o.body.name; + if( o.name.indexOf( '_body' ) === o.name.length-5 && o.name.length > 5 ) + o.name = o.name.substring( 0, o.name.length-5 ); + } + + /* generate body */ + + /* qqq : for Dmytro : cover in separate test routine */ + let body; + if( o.strategy === 'replacing' ) + body = o.body; + else + body = _.routine._amend + ({ + dst : null, + srcs : o.body, + strategy : o.strategy, + amending : 'extending', + }); + + /* make routine */ + + let unitedRoutine = _unite_functor( o.name, o.head, body, o.tail ); + + _.assert( _.strDefined( unitedRoutine.name ), 'Looks like your interpreter does not support dynamic naming of functions. Please use ES2015 or later interpreter.' ); + + /* qqq : for Dmytro : cover option::strategy */ + + _.routine._amend + ({ + dst : unitedRoutine, + srcs : body, + strategy : 'replacing', + amending : 'extending', + }); + + unitedRoutine.head = o.head; + unitedRoutine.body = body; + if( o.tail ) + unitedRoutine.tail = o.tail; + + _.assert + ( + unitedRoutine.defaults === body.defaults, + 'Something wrong, united routined should have same instance of defaults its body has' + ); + + return unitedRoutine; + + function headWithNargs_functor( nargs, body ) + { + _.assert( !!o.body.defaults ); + return function headWithDefaults( routine, args ) + { + _.assert( args.length <= nargs+1 ); + _.assert( arguments.length === 2 ); + let o = _.routine.options( routine, args[ nargs ] || Object.create( null ) ); + return _.unroll.from([ ... Array.prototype.slice.call( args, 0, nargs ), o ]); + } + } + + /* */ + + function headWithoutDefaults( routine, args ) + { + let o = args[ 0 ]; + _.assert( arguments.length === 2 ); + _.assert( args.length === 0 || args.length === 1, () => `Expects optional argument, but got ${args.length} arguments` ); + _.assert( args.length === 0 || o === undefined || o === null || _.auxIs( o ) ); + return o || null; + } + + /* */ + + function headWithDefaults( routine, args ) + { + let o = args[ 0 ]; + _.assert( arguments.length === 2 ); + _.assert( args.length === 0 || args.length === 1, () => `Expects optional argument, but got ${args.length} arguments` ); + _.assert( args.length === 0 || o === undefined || o === null || _.auxIs( o ) ); + return _.routine.options( routine, o || Object.create( null ) ); + } + + /* */ + + function _unite_functor() + { + const name = arguments[ 0 ]; + const head = arguments[ 1 ]; + const body = arguments[ 2 ]; + const tail = arguments[ 3 ]; + let r; + + _.assert( head === null || _.routineIs( head ) ); + _.assert( body === null || _.routineIs( body ) ); + _.assert( tail === null || _.routineIs( tail ) ); + + if( tail === null ) + r = + { + [ name ] : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + return result; + } + }; + else if( head === null ) + r = + { + [ name ] : function() + { + let result; + let o = arguments[ 0 ]; + + _.assert( arguments.length === 1, 'Expects single argument {-o-}.' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else if( _.mapIs( o ) ) + result = body.call( this, o ); + else + _.assert( 0, 'Unexpected type of {-o-}, expects options map or unroll.' ); + + result = tail.call( this, result, o ); + + return result; + } + }; + else + r = + { + [ name ] : function() + { + let result; + let o = head.call( this, unitedRoutine, arguments ); + + _.assert( !_.argumentsArray.is( o ), 'does not expect arguments array' ); + + if( _.unrollIs( o ) ) + result = body.apply( this, o ); + else + result = body.call( this, o ); + + debugger; + result = tail.call( this, result, o ); + + return result; + } + }; + + return r[ name ] + } +} + +unite_body.defaults = +{ + head : null, + body : null, + tail : null, + name : null, + strategy : null, +} + +// + +/* qqq : for Dmytro : write the article. it should explain why, when, what for! */ +function uniteCloning() +{ + let o = uniteCloning.head.call( this, uniteCloning, arguments ); + let result = uniteCloning.body.call( this, o ); + return result; +} + +uniteCloning.head = unite_head; +uniteCloning.body = unite_body; +uniteCloning.defaults = { ... unite_body.defaults, strategy : 'cloning' }; + +// + +function uniteInheriting() +{ + let o = uniteInheriting.head.call( this, uniteInheriting, arguments ); + let result = uniteInheriting.body.call( this, o ); + return result; +} + +uniteInheriting.head = unite_head; +uniteInheriting.body = unite_body; +uniteInheriting.defaults = { ... unite_body.defaults, strategy : 'inheriting' }; + +// + +function uniteReplacing() +{ + let o = uniteReplacing.head.call( this, uniteReplacing, arguments ); + let result = uniteReplacing.body.call( this, o ); + return result; +} + +uniteReplacing.head = unite_head; +uniteReplacing.body = unite_body; +uniteReplacing.defaults = { ... unite_body.defaults, strategy : 'replacing' }; + +// + +function _compose_old_head( routine, args ) +{ + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { bodies : args[ 0 ] }; + if( args[ 1 ] !== undefined ) + o.chainer = args[ 1 ]; + + // if( o.bodies === null ) + // debugger; + // o.bodies = _.arrayAppendArrays( [], [ o.bodies ] ); + // o.bodies = merge( o.bodies ); + + o.bodies = __arrayFlatten( o.bodies ); + o.bodies = o.bodies.filter( ( e ) => e !== null ); + + _.routine.options( routine, o ); + _.assert( _.routine.s.are( o.bodies ) ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 || args.length === 2 ); + _.assert( args.length === 1 || !_.object.isBasic( args[ 0 ] ) ); + _.assert( _.arrayIs( o.bodies ) || _.routine.is( o.bodies ) ); + _.assert( _.routine.is( args[ 1 ] ) || args[ 1 ] === undefined || args[ 1 ] === null ); + _.assert( o.chainer === null || _.routine.is( o.chainer ) ); + _.assert( o.tail === null || _.routine.is( o.tail ) ); + + return o; + + // function merge( arrays ) + // { + // let result = []; + // if( arrays === null ) + // return result; + // for( let i = 0 ; i < arrays.length ; i++ ) + // { + // let array = arrays[ i ]; + // if( _.array.is( array ) || _.argumentsArray.is( array ) ) + // result.push( ... array ); + // else + // result.push( array ); + // } + // return result; + // } +} + +_compose_old_head.locals = +{ + __arrayFlatten, +} + +// + +function _compose_old_body( o ) +{ + + if( o.chainer === null ) + o.chainer = _.routine.chainer.default; + + // if( o.chainer === null ) + // o.chainer = _.routine.chainer.original; + // o.bodies = __arrayFlatten( o.bodies ); + + let bodies = []; + for( let s = 0 ; s < o.bodies.length ; s++ ) + { + let src = o.bodies[ s ]; + _.assert( _.routine.is( src ) ); + if( src.composed ) + { + if( src.composed.chainer === o.chainer && src.composed.tail === o.tail ) + { + bodies.push( ... src.composed.elements ); + } + else + { + bodies.push( ... src ); + } + } + else + { + bodies.push( src ); + } + } + + o.bodies = bodies; + + let tail = o.tail; + let chainer = o.chainer; + let act; + + _.assert( _.routine.is( chainer ) ); + _.assert( tail === null || _.routine.is( tail ) ); + + /* */ + + if( bodies.length === 0 ) + act = function empty() + { + return []; + } + else act = function composition() + { + let result = []; + let args = _.unroll.from( arguments ); + for( let k = 0 ; k < bodies.length ; k++ ) + { + // _.assert( _.unrollIs( args ), () => `Expects unroll, but got ${_.entity.strType( args )}` ); + let routine = bodies[ k ]; + let r = routine.apply( this, args ); + _.assert( !_.argumentsArray.is( r ) ); + if( r !== undefined ) + _.unrollAppend( result, r ); + args = chainer( args, r, o, k ); + _.assert( args !== undefined && args !== false ); + if( args === _.dont ) + break; + args = _.unroll.from( args ); + } + return result; + } + + o.act = act; + act.composed = o; + + if( tail ) + { + _.routine.extend( compositionSupervise, act ); + return compositionSupervise; + } + + return act; + + function compositionSupervise() + { + // let result = tail( this, arguments, act, o ); + let result = tail.call( this, arguments, o ); + return result; + } +} + +_compose_old_body.defaults = +{ + bodies : null, + chainer : null, + tail : null, +} + +// + +function compose_old() +{ + let o = _.routine.s.compose_old.head( compose_old, arguments ); + let result = _.routine.s.compose_old.body( o ); + return result; +} + +compose_old.head = _compose_old_head; +compose_old.body = _compose_old_body; +compose_old.defaults = Object.assign( Object.create( null ), compose_old.body.defaults ); + +// + +function _compose_head( routine, args ) +{ + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { bodies : args[ 0 ] }; + if( args[ 1 ] !== undefined ) + o.chainer = args[ 1 ]; + + // if( o.bodies === null ) + // debugger; + // o.bodies = _.arrayAppendArrays( [], [ o.bodies ] ); + // o.bodies = merge( o.bodies ); + + // let bodies2 = __arrayFlatten( o.bodies ); + // if( bodies2.length && bodies2[ 0 ] === undefined ) + // debugger; + + o.bodies = __arrayFlatten( o.bodies ); + o.bodies = o.bodies.filter( ( e ) => e !== null ); + + _.routine.options( routine, o ); + _.assert( _.routine.s.are( o.bodies ) ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 || args.length === 2 ); + _.assert( args.length === 1 || !_.object.isBasic( args[ 0 ] ) ); + _.assert( _.arrayIs( o.bodies ) || _.routine.is( o.bodies ) ); + _.assert( _.routine.is( args[ 1 ] ) || args[ 1 ] === undefined || args[ 1 ] === null ); + _.assert( o.chainer === null || _.routine.is( o.chainer ) ); + _.assert( o.tail === null || _.routine.is( o.tail ) ); + + return o; + + // function merge( arrays ) + // { + // let result = []; + // if( arrays === null ) + // return result; + // for( let i = 0 ; i < arrays.length ; i++ ) + // { + // let array = arrays[ i ]; + // if( _.array.is( array ) || _.argumentsArray.is( array ) ) + // result.push( ... array ); + // else + // result.push( array ); + // } + // return result; + // } +} + +_compose_head.locals = +{ + __arrayFlatten, +} + +// + +function _compose_body( o ) +{ + + // if( o.chainer === null ) + // o.chainer = defaultChainer; + // o.bodies = __arrayFlatten( o.bodies ); + if( o.chainer === null ) + o.chainer = _.routine.chainer.default; + + let bodies = []; + for( let s = 0 ; s < o.bodies.length ; s++ ) + { + let body = o.bodies[ s ]; + _.assert( _.routine.is( body ) ); + if( body.composed ) + { + if( body.composed.chainer === o.chainer && body.composed.tail === o.tail ) + { + bodies.push( ... body.composed.elements ); + } + else + { + bodies.push( ... body ); + } + } + else + { + bodies.push( body ); + } + } + + o.bodies = bodies; + + let tail = o.tail; + let chainer = o.chainer; + + _.assert( _.routine.is( chainer ) ); + _.assert( tail === null || _.routine.is( tail ) ); + + /* */ + + if( bodies.length === 0 ) + o.act = compositionEmpty; + else if( bodies.length === 1 ) + o.act = compositionOfSingle; + else + o.act = composition; + + o.act.composed = o; + + if( tail ) + { + _.routine.extendReplacing( routineWithTail, o.act ); + return routineWithTail; + } + + return o.act; + + /* */ + + function compositionEmpty() + { + return []; + } + + function compositionOfSingle() + { + let result = []; + let args = _.unroll.from( arguments ); + // _.assert( _.unrollIs( args ), () => `Expects unroll, but got ${_.entity.strType( args )}` ); + let routine = bodies[ 0 ]; + let r = routine.apply( this, args ); + _.assert( !_.argumentsArray.is( r ) ); + if( r !== undefined ) + _.unrollAppend( result, r ); + return result; + } + + function composition() + { + let result = []; + let args = _.unroll.from( arguments ); + for( let k = 0 ; k < bodies.length ; k++ ) + { + // _.assert( _.unrollIs( args ), () => `Expects unroll, but got ${_.entity.strType( args )}` ); + let routine = bodies[ k ]; + let r = routine.apply( this, args ); + _.assert( !_.argumentsArray.is( r ) ); + if( r !== undefined ) + _.unrollAppend( result, r ); + args = chainer( args, r, o, k ); + if( args === _.dont ) + break; + _.assert( _.unroll.is( args ) ); + } + return result; + } + + // function defaultChainer( /* args, result, op, k */ ) + // { + // let args = arguments[ 0 ]; + // let result = arguments[ 1 ]; + // let op = arguments[ 2 ]; + // let k = arguments[ 3 ]; + // if( result === _.dont ) + // return result; + // return args; + // } + + function routineWithTail() + { + let result = tail.call( this, arguments, o ); + return result; + } +} + +_compose_body.defaults = +{ + chainer : null, + bodies : null, + tail : null, +} + +// + +function compose() +{ + let o = _.routine.s.compose.head( compose, arguments ); + let result = _.routine.s.compose.body( o ); + return result; +} + +compose.head = _compose_head; +compose.body = _compose_body; +compose.defaults = _compose_body.defaults; + +// -- +// chainers +// -- + +function defaultChainer( /* args, result, op, k */ ) +{ + let args = arguments[ 0 ]; + let result = arguments[ 1 ]; + let op = arguments[ 2 ]; + let k = arguments[ 3 ]; + if( result === _.dont ) + return result; + return args; +} + +// -- +// declaration +// -- + +let ChainerExtension = +{ + default : defaultChainer, +} + +Object.assign( _.routine.chainer, ChainerExtension ); + +// -- +// routine extension +// -- + +let RoutineExtension = +{ + + // fields + + NamespaceName : 'routine', + NamespaceNames : [ 'routine' ], + NamespaceQname : 'wTools/routine', + TypeName : 'Routine', + TypeNames : [ 'Routine', 'Function' ], + // SecondTypeName : 'Function', + InstanceConstructor : null, + tools : _, + + // dichotomy + + is, + _is, + like, + _like, + isTrivial, + isSync, + isAsync, + isGenerator, + isSyncGenerator, + isAsyncGenerator, + withName, + + // joiner + + _join, + constructorJoin, + join, + seal, + + // option + + optionsWithoutUndefined, + assertOptionsWithoutUndefined, + optionsWithUndefined, + optionsWithUndefinedTollerant, + assertOptionsWithUndefined, + options : optionsWithUndefined, + assertOptions : assertOptionsWithUndefined, + options_ : optionsWithUndefined, + optionsTollerant : optionsWithUndefinedTollerant, + assertOptions_ : assertOptionsWithUndefined, + _verifyDefaults, + + // options_deprecated, + // assertOptions_deprecated, + // optionsPreservingUndefines_deprecated, + // assertOptionsPreservingUndefines_deprecated, + + // amend + + _amend, + extend : extendCloning, + extendCloning, + extendInheriting, + extendReplacing, + defaults, + + // unite + + unite : uniteReplacing, + uniteCloning, + uniteCloning_replaceByUnite : uniteCloning, + uniteInheriting, + uniteReplacing, + /* qqq : cover routines uniteReplacing, uniteInheriting, uniteCloning */ + +} + +Object.assign( _.routine, RoutineExtension ); + +// -- +// routines extension +// -- + +let RoutinesExtension = +{ + + are, + compose_old, + compose, + +} + +Object.assign( _.routines, RoutinesExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + routineIs : is.bind( _.routine ), + _routineIs : _is.bind( _.routine ), + routineLike : like.bind( _.routine ), + _routineLike : _like.bind( _.routine ), + routineIsTrivial : isTrivial.bind( _.routine ), + routineIsSync : isSync.bind( _.routine ), + routineIsAsync : isAsync.bind( _.routine ), + routinesAre : are.bind( _.routine ), + routineWithName : withName.bind( _.routine ), + + routineIsGenerator : isGenerator.bind( _.routine ), + routineIsSyncGenerator : isSyncGenerator.bind( _.routine ), + routineIsAsyncGenerator : isAsyncGenerator.bind( _.routine ), + + _routineJoin : _join.bind( _.routine ), + constructorJoin : constructorJoin.bind( _.routine ), + routineJoin : join.bind( _.routine ), + routineSeal : seal.bind( _.routine ), + + routineExtend : extendCloning.bind( _.routine ), + routineDefaults : defaults.bind( _.routine ), + + routinesCompose : compose.bind( _.routines ), /* xxx : review */ + +} + +Object.assign( _, ToolsExtension ); + +// + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Routine.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Routine_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Routine_s */ })(); + +/* */ /* begin of file Seeker_s */ ( function Seeker_s() { function Seeker_s_naked() { ( function _l1_Seeker_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.seeker = _.seeker || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// seeker extension +// -- + +let SeekerExtension = +{ +} + +Object.assign( _.seeker, SeekerExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Seeker.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Seeker_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Seeker_s */ })(); + +/* */ /* begin of file Set_s */ ( function Set_s() { function Set_s_naked() { ( function _l1_Set_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.set = _.set || Object.create( null ); +_.sets = _.set.s = _.sets || _.set.s || Object.create( null ); + +// -- +// implementation +// -- + +function is( src ) +{ + if( !src ) + return false; + return src instanceof Set || src instanceof WeakSet; +} + +// + +function like( src ) +{ + return _.set.is( src ); +} + +// + +function isEmpty() +{ + return !src.size; +} + +// + +function isPopulated() +{ + return !!src.size; +} + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return true; +} + +// -- +// maker +// -- + +function _makeEmpty( src ) +{ + return new Set(); +} + +// + +function makeEmpty( src ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 ); + if( arguments.length === 1 ) + _.assert( this.like( src ) ); + return this._makeEmpty( src ); +} + +// + +function _makeUndefined( src, length ) +{ + return new Set(); +} + +// + +function makeUndefined( src, length ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + + if( arguments.length === 2 ) + { + _.assert( this.like( src ) ); + _.assert( _.number.is( length ) ); + } + else if( arguments.length === 1 ) + { + _.assert( _.number.is( src ) || this.like( src ) ); + } + + return new Set(); +} + +// + +function _make( src, length ) +{ + if( length === 0 ) + return new Set(); + else if( _.number.is( src ) ) + return new Set(); + else + return new Set([ ... src ]); +} + +// + +function make( src, length ) +{ + _.assert( arguments.length === 0 || src === null || _.countable.is( src ) || src === 0 ); + _.assert( arguments.length < 2 || length === 0 ); + _.assert( arguments.length <= 2 ); + return this._make( ... arguments ); +} + +// + +function _cloneShallow( src ) +{ + return new Set([ ... src ]); +} + +// + +function cloneShallow( src ) +{ + _.assert( _.countable.is( src ) ); + _.assert( arguments.length === 1 ); + return this._cloneShallow( src ); +} + +// + +function from( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( this.is( src ) ) + return src; + + if( _.containerAdapter.is( src ) ) + src = src.toArray().original; + + return this.make( src ); +} + +// // +// +// function from( src ) +// { +// _.assert( arguments.length === 1 ); +// if( _.set.adapterLike( src ) ) +// return src; +// if( src === null ) +// return new Set(); +// if( _.containerAdapter.is( src ) ) +// src = src.toArray().original; +// _.assert( _.longIs( src ) ); +// return new Set([ ... src ]); +// } + +// + +/* qqq : for junior : cover please */ +function as( src ) +{ + _.assert( src !== undefined ); + if( src === null ) + return new Set; + else if( _.set.is( src ) ) + return src; + else if( _.countable.like( src ) ) + return new Set([ ... src ]); + else + return new Set([ src ]); +} + +// // +// +// function asTest( src ) +// { +// if( src === null || src === undefined ) +// return new Set; +// if( src[ Symbol.iterator ] && !_.str.is( src ) ) +// return new Set( [ ... src ] ); +// if( src instanceof WeakSet ) +// return src; +// +// return new Set( [ src ] ); +// } + +// // +// +// function setsFrom( srcs ) +// { +// _.assert( arguments.length === 1 ); +// _.assert( _.longIs( srcs ) ); +// let result = []; +// for( let s = 0, l = srcs.length ; s < l ; s++ ) +// result[ s ] = _.set.from( srcs[ s ] ); +// return result; +// } + +// -- +// properties +// -- + +function _keys( src ) +{ + return [ ... src.keys() ]; +} + +// + +function keys( src ) +{ + _.assert( this.like( src ) ); + return this._keys( src ); +} + +// + +function _vals( src ) +{ + return [ ... src.values() ]; +} + +// + +function vals( src ) +{ + _.assert( this.like( src ) ); + return this._vals( src ); +} + +// + +function _pairs( src ) +{ + return [ ... src.entries() ]; +} + +// + +function pairs( src ) +{ + _.assert( this.like( src ) ); + return this._pairs( src ); +} + +// -- +// set extension +// -- + +let SetExtension = +{ + + // + + NamespaceName : 'set', + NamespaceNames : [ 'set' ], + NamespaceQname : 'wTools/set', + MoreGeneralNamespaceName : 'set', + MostGeneralNamespaceName : 'countable', + TypeName : 'Set', + TypeNames : [ 'Set' ], + InstanceConstructor : Set, + tools : _, + + // dichotomy + + is, + like, + // adapterLike, + isEmpty, + isPopulated, + IsResizable, + + // maker + + _makeEmpty, + makeEmpty, /* qqq : for junior : cover */ + _makeUndefined, + makeUndefined, /* qqq : for junior : cover */ + _make, + make, /* qqq : for junior : cover */ + _cloneShallow, + cloneShallow, /* qqq : for junior : cover */ + from, + as, + // asTest, + + // properties + + _keys, + keys, /* qqq : for junior : cover */ + _vals, + vals, /* qqq : for junior : cover */ + _pairs, + pairs, /* qqq : for junior : cover */ + + // meta + + namespaceOf : _.blank.namespaceOf, + namespaceWithDefaultOf : _.blank.namespaceWithDefaultOf, + _functor_functor : _.blank._functor_functor, + +} + +Object.assign( _.set, SetExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + // dichotomy + + setIs : is.bind( _.set ), + setIsEmpty : isEmpty.bind( _.set ), + setIsPopulated : isPopulated.bind( _.set ), + setLike : like.bind( _.set ), + + // maker + + setMakeEmpty : makeEmpty.bind( _.set ), + setMakeUndefined : makeUndefined.bind( _.set ), + setMake : make.bind( _.set ), + setCloneShallow : cloneShallow.bind( _.set ), + setFrom : from.bind( _.set ), + setAs : as.bind( _.set ), + +} + +Object.assign( _, ToolsExtension ); + +// + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Set.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Set_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Set_s */ })(); + +/* */ /* begin of file Sorted_s */ ( function Sorted_s() { function Sorted_s_naked() { ( function _l1_Sorted_s_() +{ + +'use strict'; + +// + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.sorted = _.sorted || Object.create( null ); + +// -- +// +// -- + +// -- +// extension +// -- + +let Extension = +{ +}; + +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Sorted.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Sorted_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Sorted_s */ })(); + +/* */ /* begin of file Str_s */ ( function Str_s() { function Str_s_naked() { ( function _l1_Str_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.str = _.str || Object.create( null ); +_.str.lines = _.str.lines || Object.create( null ); + +// -- +// str +// -- + +/** + * Function strIs checks incoming param whether it is string. + * Returns "true" if incoming param is string. Othervise "false" returned + * + * @example + * _.strIsIs( 'song' ); + * // returns true + * + * @example + * _.strIs( 5 ); + * // returns false + * + * @param {*} src. + * @return {Boolean}. + * @function strIs. + * @namespace Tools + */ + +function is( src ) +{ + let result = Object.prototype.toString.call( src ) === '[object String]'; + return result; +} + +// + +function like( src ) +{ + if( _.str.is( src ) ) + return true; + if( _.regexp.is( src ) ) + return true; + return false; +} + +// + +function strsAreAll( src ) +{ + _.assert( arguments.length === 1 ); + + if( _.argumentsArray.like( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( !_.strIs( src[ s ] ) ) + return false; + return true; + } + + return _.strIs( src ); +} + +// + +// function regexpLike( src ) +// { +// if( _.strIs( src ) ) +// return true; +// if( _.regexpIs( src ) ) +// return true; +// return false +// } +// +// // +// +// function strsLikeAll( src ) +// { +// _.assert( arguments.length === 1 ); +// +// if( _.argumentsArray.like( src ) ) +// { +// for( let s = 0 ; s < src.length ; s++ ) +// if( !_.regexpLike( src[ s ] ) ) +// return false; +// return true; +// } +// +// return regexpLike( src ); +// } + +// + +function defined( src ) +{ + if( !src ) + return false; + let result = Object.prototype.toString.call( src ) === '[object String]'; + return result; +} + +// + +function strsDefined( src ) +{ + if( _.argumentsArray.like( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( !_.strDefined( src[ s ] ) ) + return false; + return true; + } + return false; +} + +// + +function has( src, ins ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ), () => `Expects string, got ${_.entity.strType( src )}` ); + _.assert( _.regexpLike( ins ), () => `Expects string-like, got ${_.entity.strType( ins )}` ); + + if( _.strIs( ins ) ) + return src.indexOf( ins ) !== -1; + else + return ins.test( src ); + +} + +// -- +// converter +// -- + +/** + * Returns source string( src ) with limited number( limit ) of characters. + * For example: src : 'string', limit : 4, result -> 'stng'. + * Function can be called in two ways: + * - First to pass only source string and limit; + * - Second to pass all options map. Example: ({ src : 'string', limit : 5, delimeter : '.' }). + * + * @param {string|object} o - String to parse or object with options. + * @param {string} [ o.src=null ] - Source string. + * @param {number} [ o.limit=40 ] - Limit of characters in output. + * @param {string} [ o.delimeter=null ] - The middle part to fill the reduced characters, if boolLikeTrue - the default ( '...' ) is used. + * @param {function} [ o.onLength=null ] - callback function that calculates a length based on . + * @returns {string} Returns simplified source string. + * + * @example + * _.strShort_( 'string', 4 ); + * // returns o, o.result = 'stng' + * + * @example + * _.strShort_( 'a\nb', 3 ); + * // returns o, o.result = 'a\nb' + * + * @example + * _.strShort_( 'string', 0 ); + * // returns o, o.result = '' + * + * @example + * _.strShort_({ src : 'string', limit : 4 }); + * // returns o, o.result = 'stng' + * + * @example + * _.strShort_({ src : 'string', limit : 3, cutting : 'right' }); + * // returns o, o.result = 'str' + * + * @example + * _.strShort_({ src : 'st\nri\nng', limit : 1, heightLimit : 2, cutting : 'left', heightCutting : 'right' }); + * // returns o, o.result = 't\ni' + * + * @method short_ + * @throws { Exception } If no argument provided. + * @throws { Exception } If( arguments.length ) is not equal 1 or 2. + * @throws { Exception } If( o ) is extended with unknown property. + * @throws { Exception } If( o.src ) is not a String. + * @throws { Exception } If( o.limit ) is not a Number. + * @throws { Exception } If( o.delimeter ) is not a String or null or boolLikeTrue. + * + * @namespace Tools + * + */ + +function short_( o ) /* version with binary search cutting */ +{ + + if( arguments.length === 2 ) + o = { src : arguments[ 0 ], widthLimit : arguments[ 1 ] }; + else if( arguments.length === 1 ) + if( _.strIs( o ) ) + o = { src : arguments[ 0 ] }; + + _.routine.options( short_, o ); + + _.assert( _.strIs( o.src ) ); + _.assert( _.number.is( o.widthLimit ) ); + _.assert( o.widthLimit >= 0, 'Option::o.widthLimit must be greater or equal to zero' ); + _.assert + ( + _.number.is( o.heightLimit ) && o.heightLimit >= 0, + 'If provided option::o.heightLimit must be greater or equal to zero' + ); + _.assert( o.delimeter === null || _.strIs( o.delimeter ) || _.bool.likeTrue( o.delimeter )); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( !o.delimeter ) + o.delimeter = ''; + if( !o.heightDelimeter ) + o.heightDelimeter = ''; + if( o.widthLimit === 0 ) + o.widthLimit = Infinity; + if( o.heightLimit === 0 ) + o.heightLimit = Infinity; + + if( _.bool.likeTrue( o.delimeter ) ) + o.delimeter = '...'; + + if( !o.onLength ) + o.onLength = ( src ) => src.length; + + let src = o.src; + + let isOneLine = o.src.indexOf( '\n' ) === -1; + + if( isOneLine && o.onLength( o.src ) < o.widthLimit ) + { + o.changed = false; + o.result = o.src; + + return o; + } + + let options = Object.create( null ); /* width cutting options */ + options.limit = o.widthLimit; + options.delimeter = o.delimeter; + options.onLength = o.onLength; + options.cutting = o.cutting; + + if( isOneLine ) + { + options.src = src; + _.strShortWidth( options ); + + o.result = options.result; + o.changed = options.changed; + + return o; + } + else + { + let splitted = o.src.split( '\n' ); + + let options2 = Object.create( null ); /* height cutting */ + options2.src = splitted; + options2.limit = o.heightLimit; + options2.delimeter = o.heightDelimeter; + options2.cutting = o.heightCutting; + _._strShortHeight( options2 ); + + options.src = options2.result; + + _._strShortWidth( options ); + + let result = options.result.join( '\n' ); + + if( result === o.src ) + o.changed = false; + else if( result !== o.src ) + o.changed = true; + + o.result = result; + + return o; + } +} + +short_.defaults = +{ + src : null, + widthLimit : 40, + heightLimit : 0, + delimeter : null, /* xxx qqq : rename to 'widthDelimeter' */ + heightDelimeter : null, + onLength : null, + cutting : 'center', /* xxx qqq : rename to 'widthCutting' */ + heightCutting : 'center', +} + +// + +function shortWidth( o ) +{ + + if( arguments.length === 2 ) + o = { src : arguments[ 0 ], limit : arguments[ 1 ] }; + else if( arguments.length === 1 ) + if( _.strIs( o ) ) + o = { src : arguments[ 0 ] }; + + _.routine.options( shortWidth, o ); + + _.assert( _.strIs( o.src ) ); + _.assert( _.number.is( o.limit ) ); + _.assert( o.limit >= 0, 'Option::o.limit must be greater or equal to zero' ); + _.assert( o.delimeter === null || _.strIs( o.delimeter ) || _.bool.likeTrue( o.delimeter )); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + let originalSrc = o.src; + + if( !o.delimeter ) + o.delimeter = ''; + if( o.limit === 0 ) + o.limit = Infinity; + + if( _.bool.likeTrue( o.delimeter ) ) + o.delimeter = '...'; + + if( !o.onLength ) + o.onLength = ( src ) => src.length; + + let splitted = o.src.split( '\n' ); + + o.src = splitted; + _._strShortWidth( o ); + + o.src = originalSrc; + o.result = o.result.join( '\n' ); + + return o; +} + +shortWidth.defaults = +{ + src : null, + limit : 40, + onLength : null, + cutting : 'center', + delimeter : null +} + +// + +function _shortWidth( o ) +{ + /* + input : array of lines + output : array of lines ( each cutted down to o.limit ) + */ + _.assert( _.arrayIs( o.src ) ); + _.routine.options( _shortWidth, o ); + + let begin = ''; + let end = ''; + let fixLength = o.onLength( o.delimeter ); + + o.changed = false; + + let result = o.src.map( ( el ) => + { + let delimeter = o.delimeter; + fixLength = o.onLength( o.delimeter ); + + if( fixLength === o.limit ) + { + o.changed = true; + return o.delimeter; + } + else if( o.onLength( el ) + fixLength <= o.limit ) /* nothing to cut */ + { + return el; + } + else + { + if( o.onLength( delimeter ) > o.limit ) + { + el = delimeter; + delimeter = ''; + fixLength = 0; + } + + o.changed = true; + + if( o.cutting === 'left' ) + { + return delimeter + cutLeft( el ); + } + else if( o.cutting === 'right' ) + { + return cutRight( el ) + delimeter; + } + else + { + let [ begin, end ] = cutMiddle( el ); + return begin + delimeter + end; + } + } + }); + + o.result = result; + + return o; + + /* - */ + + function cutLeft( src ) + { + let startIndex = 0; + let endIndex = src.length - 1; + let endLength = o.onLength( src ); + let middleIndex = src.length - o.limit - 1; /* optimize default option::onLength */ + + while( endLength + fixLength > o.limit ) /* binary */ + { + [ begin, end ] = splitInTwo( src, middleIndex + 1 ); + endLength = o.onLength( end ); + + startIndex = middleIndex; /* all needed elements are in end */ + middleIndex = Math.floor( ( startIndex + endIndex ) / 2 ); + } + + while( o.onLength( end ) + fixLength <= o.limit ) /* add elements till o.limit is satisfied */ + { + /* + add elements and parts of element that might have been sliced, + example : onLength considers as 1 element substring of the same characters + 'aabbccdd' with o.limit = 2 might return 'cdd', but need 'ccdd' + */ + end = begin[ begin.length - 1 ] + end; + begin = begin.slice( 0, -1 ); + } + + return end.slice( 1 ); + } + + // + + function cutRight( src ) + { + let startIndex = 0; + let endIndex = src.length - 1; + let beginLength = o.onLength( src ); + let middleIndex = o.limit; /* optimize default option::onLength */ + + while( beginLength + fixLength > o.limit ) /* binary */ + { + [ begin, end ] = splitInTwo( src, middleIndex ); + beginLength = o.onLength( begin ); + + endIndex = middleIndex; /* all needed elements are in begin */ + middleIndex = Math.floor( ( startIndex + endIndex ) / 2 ); + } + + while( o.onLength( begin ) + fixLength <= o.limit ) /* add elements till o.limit is satisfied */ + { + /* + add elements and parts of element that might have been sliced, + example : onLength considers as 1 element substring of the same characters + 'aabbccdd' with o.limit = 2 might return 'aab', but need 'aabb' + */ + begin += end[ 0 ]; + end = end.slice( 1 ); + } + + return begin.slice( 0, -1 ); + } + + // + + function cutMiddle( src ) + { + let originalStr = src; + let chunkSize, middleIndexLeft, middleIndexRight; + + if( o.limit % 2 === 0 ) /* optimize default option::onLength */ + { + middleIndexLeft = ( o.limit / 2 ) - 1; + middleIndexRight = ( -o.limit / 2 ) + src.length; + } + else + { + middleIndexLeft = Math.floor( ( o.limit / 2 ) ); + middleIndexRight = Math.ceil( ( -o.limit / 2 ) ) + src.length; + } + + while( o.onLength( src ) + fixLength > o.limit ) /* binary */ + { + if( src.length <= 5 ) /* src.length = 4 || 3 || 2, base case */ + { + let index = Math.floor( src.length / 2 ); + begin = src.slice( 0, index ); + end = src.slice( index+1 ); + } + else /* begin : first 1/3, end : last 1/3 */ + { + begin = src.slice( 0, middleIndexLeft + 1 ); + end = src.slice( middleIndexRight ); + } + + /* delete middle, might delete part of the element, check later when desired length is obtained */ + src = begin + end; + + chunkSize = Math.floor( src.length / 3 ); /* split str into 3 'equal' parts, middle is to be removed */ + middleIndexLeft = chunkSize; + middleIndexRight = chunkSize * 2; + } + + while( o.onLength( begin + end ) + fixLength < o.limit ) /* overcut */ + { + if( o.onLength( begin ) > o.onLength( end ) ) /* shrink middle from the right */ + { + end = originalStr.slice( -end.length - 1 ); + } + else /* shrink middle from the left */ + { + begin = originalStr.slice( 0, begin.length + 1 ); + } + } + + /* + add parts of elements that might have been sliced, + example : onLength considers as 1 element substring of the same characters + 'aabbccdd' with o.limit = 2 might return 'ad', but need 'aadd' + */ + + let beginInitial = o.onLength( begin ); + let endInitial = o.onLength( end ); + + while( o.onLength( begin ) === beginInitial ) /* try to increase begin */ + { + begin = originalStr.slice( 0, begin.length + 1 );; + } + + while( o.onLength( end ) === endInitial ) /* try to increase end */ + { + end = originalStr.slice( -end.length - 1 ); + } + + return [ begin.slice( 0, -1 ), end.slice( 1 ) ]; + } + + // + + function splitInTwo( src, middle ) + { + let begin = src.slice( 0, middle ); + let end = src.slice( middle ); + return [ begin, end ]; + } + +} + +_shortWidth.defaults = +{ + src : null, + limit : 40, + delimeter : null, + onLength : null, + cutting : 'center', +} + +// + +function shortHeight( o ) +{ + + if( arguments.length === 2 ) + o = { src : arguments[ 0 ], limit : arguments[ 1 ] }; + else if( arguments.length === 1 ) + if( _.strIs( o ) ) + o = { src : arguments[ 0 ] }; + + _.routine.options( shortHeight, o ); + + _.assert( _.strIs( o.src ) ); + _.assert + ( + ( _.number.is( o.limit ) && o.limit >= 0 ), + 'option::o.limit must be greater or equal to zero' + ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + let originalSrc = o.src; + let splitted = o.src.split( '\n' ); + + if( !o.delimeter ) + o.delimeter = ''; + + o.src = splitted; + + _._strShortHeight( o ); + o.src = originalSrc; + o.result = o.result.join( '\n' ); + + return o; + +} + +shortHeight.defaults = +{ + src : null, + limit : null, + cutting : 'center', + delimeter : null, +} + +// + +function _shortHeight( o ) /* version with binary search cutting */ +{ + /* + input : array of lines + output : array of lines ( cutted down to o.limit ) + */ + + _.assert( _.arrayIs( o.src ) ); + _.routine.options( shortHeight, o ); + + o.changed = false; + + let delimeterLength = o.delimeter === '' ? 0 : 1; + + if( delimeterLength === o.limit ) + { + o.changed = true; + o.result = [ o.delimeter ]; + + return o; + } + + let result = cut( o.src.slice() ); + o.result = result; + + return o; + + /* - */ + + function cut( src ) + { + if( src.length + delimeterLength > o.limit ) + { + o.changed = true; + + if( o.cutting === 'left' ) + { + src = src.slice( - ( o.limit - delimeterLength ) ); + + if( o.delimeter !== '' ) + src.unshift( o.delimeter ); + } + else if( o.cutting === 'right' ) + { + src = src.slice( 0, o.limit - delimeterLength ); + + if( o.delimeter !== '' ) + src.push( o.delimeter ); + } + else + { + let [ left, right ] = handleHeightCuttingCenter( src ); + let result = []; + + result.push( ... left ); + + if( o.delimeter !== '' ) + result.push( o.delimeter ); + + if( right !== undefined ) /* no right when o.limit = 2 and there is a delimeter */ + result.push( ... right ); + + src = result; + + } + } + + return src; + } + + // + + function handleHeightCuttingCenter( src ) + { + let indexLeft, indexRight; + + let limit = o.limit - delimeterLength; + + if( limit === 1 ) + { + return [ src.slice( 0, 1 ) ]; + } + else if( limit % 2 === 0 ) + { + indexLeft = limit / 2; + indexRight = -indexLeft; + } + else + { + indexLeft = Math.floor( ( limit / 2 ) ) + 1; + indexRight = -indexLeft + 1; + } + + let splittedLeft = src.slice( 0, indexLeft ); + let splittedRight = src.slice( indexRight ); + + return [ splittedLeft, splittedRight ]; + } + +} + +_shortHeight.defaults = +{ + src : null, + limit : null, + cutting : 'center', + prefix : null, + postfix : null, + infix : null, +} + +// + +/** + * The routine concat() provides the concatenation of array of elements ( or single element ) + * into a String. Returned string can be formatted by using options in options map {-o-}. + * + * @example + * _.strConcat( 'str' ); + * // returns : 'str' + * + * @example + * _.strConcat( 11 ); + * // returns : '11' + * + * @example + * _.strConcat([ 1, 2, 'str', [ 3, 4 ] ]); + * // returns : '1 2 str 3,4 ' + * + * @example + * let options = + * { + * linePrefix : '** ', + * linePostfix : ' **' + * }; + * _.strConcat( [ 1, 2, 'str', [ 3, 4 ] ], options ); + * // returns : '** 1 2 str 3,4 **' + * + * @example + * let options = + * { + * linePrefix : '** ', + * linePostfix : ' **' + * }; + * _.strConcat( [ 'a\n', 'b\n', 'c' ], options ); + * // returns : + * // `** a ** + * // ** b ** + * // ** c ** + * + * @example + * let onToStr = ( src ) => String( src ) + '*'; + * let options = { onToStr }; + * _.strConcat( [ 'a', 'b', 'c' ], options ); + * // returns : 'a* b* c*' + * + * @example + * let onPairWithDelimeter = ( src1, src2 ) => src1 + ' ..' + src2; + * let options = { onPairWithDelimeter }; + * _.strConcat( [ 'a\n', 'b\n', 'c' ], options ); + * // returns : + * // `a .. + * // b .. + * // c` + * + * @param { ArrayLike|* } srcs - ArrayLike container with elements or single element to make string. + * If {-srcs-} is not ArrayLike, routine converts to string provided instance. + * @param { Map } o - Options map. + * @param { String } o.lineDelimter - The line delimeter. Default value is new line symbol '\n'. + * If an element of array has not delimeter at the end or next element has not delimeter at the begin, + * then routine inserts one space between this elements. + * @param { String } o.linePrefix - The prefix, which is added to each line. Default value is empty string. + * @param { String } o.linePostfix - The postfix, which is added to each line. Default value is empty string. + * @param { Map } o.optionsForToStr - The options for routine _.entity.exportString that uses as default callback {-o.onToStr-}. Default value is null. + * @param { Function } o.onToStr - The callback, which uses for conversion of each element of {-srcs-}. Accepts element {-src-} and options map {-o-}. + * @param { Function } o.onPairWithDelimeter - The callback, which uses for concatenation of two strings. + * The callback calls if first string {-src1-} end with line delimeter {-o.lineDelimter-} or second string {-src2-} + * begins with line delimeter. Additionally accepts options map {-o-}. + * @returns { String } - Returns concatenated string. + * @function concat + * @throws { Error } If arguments.length is less then one or greater than two. + * @throws { Error } If options map {-o-} has unknown property. + * @throws { Error } If property {-o.optionsForToStr-} is not a Aux. + * @throws { Error } If routine concat does not belong module Tools. + * @namespace Tools + */ + +function concat( srcs, o ) +{ + + o = _.routine.options( concat, o || Object.create( null ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( this.strConcat === concat ); + + if( o.onToStr === null ) + o.onToStr = onToStr; + + let defaultOptionsForToStr = + { + stringWrapper : '', + }; + + o.optionsForToStr = _.props.supplement( o.optionsForToStr, defaultOptionsForToStr ); + o.optionsForToStr.format = o.optionsForToStr.format || 'string.diagnostic'; + + if( _.routine.is( srcs ) ) + srcs = srcs(); + + if( !_.argumentsArray.like( srcs ) ) + srcs = [ srcs ]; + + let result = ''; + if( !srcs.length ) + return result; + + let concatenatePairWithLineDelimeter = o.onPairWithDelimeter ? o.onPairWithDelimeter : concatenateSimple; + + /* */ + + let a = 0; + + while( !result && a < srcs.length ) + { + result = o.onToStr( srcs[ a ], o ); + ++a; + } + + for( ; a < srcs.length ; a++ ) + { + let src = srcs[ a ]; + src = o.onToStr( src, o ); + + result = result.replace( /[^\S\n]\s*$/, '' ); + + if( _.strEnds( result, o.lineDelimter ) || _.strBegins( src, o.lineDelimter ) ) + result = concatenatePairWithLineDelimeter( result, src, o ); + else + result = `${result} ${src.replace( /^\s+/, '' )}`; + } + + /* */ + + if( o.linePrefix || o.linePostfix ) + { + result = result.split( o.lineDelimter ); + result = o.linePrefix + result.join( o.linePostfix + o.lineDelimter + o.linePrefix ) + o.linePostfix; + } + + /* */ + + return result; + + /* */ + + function onToStr( src, op ) + { + return _.entity.exportString( src, op.optionsForToStr ); + } + + /* */ + + function concatenateSimple( src1, src2 ) + { + return src1 + src2; + } +} + +concat.defaults = +{ + linePrefix : '', + linePostfix : '', + lineDelimter : '\n', + optionsForToStr : null, + onToStr : null, + onPairWithDelimeter : null, +} + +// + +function _beginOf( src, begin ) +{ + + // _.assert( _.strIs( src ), 'Expects string' ); + // _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.strIs( begin ) ) + { + if( src.lastIndexOf( begin, 0 ) === 0 ) + return begin; + } + else if( _.regexpIs( begin ) ) + { + let matched = begin.exec( src ); + if( matched && matched.index === 0 ) + return matched[ 0 ]; + } + else _.assert( 0, 'Expects string-like ( string or regexp )' ); + + return undefined; +} + +// + +function _endOf( src, end ) +{ + + // _.assert( _.strIs( src ), 'Expects string' ); + // _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.strIs( end ) ) + { + if( src.indexOf( end, src.length - end.length ) !== -1 ) + return end; + } + else if( _.regexpIs( end ) ) + { + // let matched = end.exec( src ); + let newEnd = RegExp( end.toString().slice(1, -1) + '$' ); + let matched = newEnd.exec( src ); + + //if( matched && matched.index === 0 ) + if( matched && matched.index + matched[ 0 ].length === src.length ) + return matched[ 0 ]; + } + else _.assert( 0, 'Expects string-like ( string or regexp )' ); + + return undefined; +} + +// + +/** + * Compares two strings. + * + * @param { String } src - Source string. + * @param { String } begin - String to find at begin of source. + * + * @example + * let scr = _.strBegins( "abc", "a" ); + * // returns true + * + * @example + * let scr = _.strBegins( "abc", "b" ); + * // returns false + * + * @returns { Boolean } Returns true if param( begin ) is match with first chars of param( src ), otherwise returns false. + * @function begins + * @throws { Exception } If one of arguments is not a String. + * @throws { Exception } If( arguments.length ) is not equal 2. + * @namespace Tools + */ + +function begins( src, begin ) +{ + + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( _.strIs( begin ) || _.regexpIs( begin ) || _.longIs( begin ), 'Expects string/regexp or array of strings/regexps {-begin-}' ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !_.longIs( begin ) ) + { + let result = _._strBeginOf( src, begin ); + return !( result === undefined ); + // return result === undefined ? false : true; + } + + for( let b = 0, blen = begin.length ; b < blen; b++ ) + { + let result = _._strBeginOf( src, begin[ b ] ); + if( result !== undefined ) + return true; + } + + return false; +} + +// + +/** + * Compares two strings. + * + * @param { String } src - Source string. + * @param { String } end - String to find at end of source. + * + * @example + * let scr = _.strEnds( "abc", "c" ); + * // returns true + * + * @example + * let scr = _.strEnds( "abc", "b" ); + * // returns false + * + * @return { Boolean } Returns true if param( end ) is match with last chars of param( src ), otherwise returns false. + * @function ends + * @throws { Exception } If one of arguments is not a String. + * @throws { Exception } If( arguments.length ) is not equal 2. + * @namespace Tools + */ + +function ends( src, end ) +{ + + _.assert( _.strIs( src ), () => `Expects argument::src of type::string, but got ${_.entity.strType( src )}` ); + _.assert( _.strIs( end ) || _.regexpIs( end ) || _.longIs( end ), 'Expects string/regexp or array of strings/regexps {-end-}' ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !_.longIs( end ) ) + { + let result = _._strEndOf( src, end ); + return !( result === undefined ); + } + + for( let b = 0, blen = end.length ; b < blen; b++ ) + { + let result = _._strEndOf( src, end[ b ] ); + if( result !== undefined ) + return true; + } + + return false; +} + +// + +/** + * Finds occurrence of( end ) at the end of source( src ) and removes it if exists. + * Returns begin part of a source string if occurrence was finded or empty string if arguments are equal, otherwise returns undefined. + * + * @param { String } src - The source string. + * @param { String } end - String to find. + * + * @example + * _.strBeginOf( 'abc', 'c' ); + * // returns 'ab' + * + * @example + * _.strBeginOf( 'abc', 'x' ); + * // returns undefined + * + * @returns { String } Returns part of source string without tail( end ) or undefined. + * @throws { Exception } If all arguments are not strings; + * @throws { Exception } If ( argumets.length ) is not equal 2. + * @function beginOf + * @namespace Tools + */ + +function beginOf( src, begin ) +{ + + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( _.strIs( begin ) || _.regexpIs( begin ) || _.longIs( begin ), 'Expects string/regexp or array of strings/regexps {-begin-}' ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !_.longIs( begin ) ) + { + let result = _._strBeginOf( src, begin ); + return result; + } + + for( let b = 0, blen = begin.length ; b < blen ; b++ ) + { + let result = _._strBeginOf( src, begin[ b ] ); + if( result !== undefined ) + return result; + } + + return undefined; +} + +// + +/** + * Finds occurrence of( begin ) at the begining of source( src ) and removes it if exists. + * Returns end part of a source string if occurrence was finded or empty string if arguments are equal, otherwise returns undefined. + * otherwise returns undefined. + * + * @param { String } src - The source string. + * @param { String } begin - String to find. + * + * @example + * _.strEndOf( 'abc', 'a' ); + * // returns 'bc' + * + * @example + * _.strEndOf( 'abc', 'c' ); + * // returns undefined + * + * @returns { String } Returns part of source string without head( begin ) or undefined. + * @throws { Exception } If all arguments are not strings; + * @throws { Exception } If ( argumets.length ) is not equal 2. + * @function endOf + * @namespace Tools + */ + +function endOf( src, end ) +{ + + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( _.strIs( end ) || _.regexpIs( end ) || _.longIs( end ), 'Expects string/regexp or array of strings/regexps {-end-}' ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !_.longIs( end ) ) + { + let result = _._strEndOf( src, end ); + return result; + } + + for( let b = 0, blen = end.length ; b < blen; b++ ) + { + let result = _._strEndOf( src, end[ b ] ); + if( result !== undefined ) + return result; + } + + return undefined; +} + +// + +/** + * Finds substring prefix ( begin ) occurrence from the very begining of source ( src ) and removes it. + * Returns original string if source( src ) does not have occurrence of ( prefix ). + * + * @param { String } src - Source string to parse. + * @param { String } prefix - String that is to be dropped. + * @returns { String } Returns string with result of prefix removement. + * + * @example + * _.strRemoveBegin( 'example', 'exa' ); + * // returns mple + * + * @example + * _.strRemoveBegin( 'example', 'abc' ); + * // returns example + * + * @function removeBegin + * @throws { Exception } Throws a exception if( src ) is not a String. + * @throws { Exception } Throws a exception if( prefix ) is not a String. + * @throws { Exception } Throws a exception if( arguments.length ) is not equal 2. + * @namespace Tools + * + */ + +function removeBegin( src, begin ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( _.strIs( begin ) || _.regexpIs( begin ), 'Expects string/regexp {-begin-}' ); + + let result = src; + let beginOf = _._strBeginOf( result, begin ); + if( beginOf !== undefined ) + result = result.substr( beginOf.length, result.length ); + return result; +} + +// + +/** + * Removes occurrence of postfix ( end ) from the very end of string( src ). + * Returns original string if no occurrence finded. + * @param { String } src - Source string to parse. + * @param { String } postfix - String that is to be dropped. + * @returns { String } Returns string with result of postfix removement. + * + * @example + * _.strRemoveEnd( 'example', 'le' ); + * // returns examp + * + * @example + * _.strRemoveEnd( 'example', 'abc' ); + * // returns example + * + * @function removeEnd + * @throws { Exception } Throws a exception if( src ) is not a String. + * @throws { Exception } Throws a exception if( postfix ) is not a String. + * @throws { Exception } Throws a exception if( arguments.length ) is not equal 2. + * @namespace Tools + * + */ + +function removeEnd( src, end ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( _.strIs( end ) || _.regexpIs( end ), 'Expects string/regexp {-end-}' ); + + let result = src; + let endOf = _._strEndOf( result, end ); + if( endOf !== undefined ) + result = result.substr( 0, result.length - endOf.length ); + + return result; +} + +// + +/** + * Finds substring or regexp ( insStr ) first occurrence from the source string ( srcStr ) and removes it. + * Returns original string if source( src ) does not have occurrence of ( insStr ). + * + * @param { String } srcStr - Source string to parse. + * @param { String } insStr - String/RegExp that is to be dropped. + * @returns { String } Returns string with result of substring removement. + * + * @example + * _.strRemove( 'source string', 's' ); + * // returns ource tring + * + * @example + * _.strRemove( 'example', 's' ); + * // returns example + * + * @function remove + * @throws { Exception } Throws a exception if( srcStr ) is not a String. + * @throws { Exception } Throws a exception if( insStr ) is not a String or a RegExp. + * @throws { Exception } Throws a exception if( arguments.length ) is not equal 2. + * @namespace Tools + * + */ + +function remove( srcStr, insStr ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( srcStr ), 'Expects string {-src-}' ); + _.assert( _.strIs( insStr ) || _.regexpIs( insStr ), 'Expects string/regexp {-begin-}' ); + + let result = srcStr; + + result = result.replace( insStr, '' ); + + return result; +} + +// -- +// str extension +// -- + +let StrExtension = +{ + + // dichotomy + + is, + like, + + defined, + + has, + + short_, + _shortWidth, + shortHeight, + _shortHeight, + + concat, + + _beginOf, + _endOf, + + begins, + ends, + + beginOf, + endOf, + + removeBegin, + removeEnd, + remove, + +} + +Object.assign( _.str, StrExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + // dichotomy + + strIs : is, + strsAreAll, + // regexpLike, + // strsLikeAll, + strDefined : defined, + strsDefined, + + strHas : has, + + // converter + + strstrShort_ : short_, /* xxx : remove */ + strShort_ : short_, + strShortWidth : shortWidth, + _strShortWidth : _shortWidth, + strShortHeight : shortHeight, + _strShortHeight : _shortHeight, + // strShort, /* original version without binary search cutting */ + // strShort_2, /* non-binary search implementation */ + strConcat : concat, + + // + + _strBeginOf : _beginOf, + _strEndOf : _endOf, + + strBegins : begins, + strEnds : ends, + + strBeginOf : beginOf, + strEndOf : endOf, + + strRemoveBegin : removeBegin, + strRemoveEnd : removeEnd, + strRemove : remove, + +} + +Object.assign( _, ToolsExtension ); + +// + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Str.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Str_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Str_s */ })(); + +/* */ /* begin of file Stringer_s */ ( function Stringer_s() { function Stringer_s_naked() { ( function _l1_Stringer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.stringer = _.stringer || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// stringer extension +// -- + +let StringerExtension = +{ +} + +Object.assign( _.stringer, StringerExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Stringer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Stringer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Stringer_s */ })(); + +/* */ /* begin of file StrLines_s */ ( function StrLines_s() { function StrLines_s_naked() { ( function _l1_Str_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.str = _.str || Object.create( null ); +_.str.lines = _.str.lines || Object.create( null ); + +// -- +// lines +// -- + +function split( src, eol ) +{ + if( _.arrayIs( src ) ) + return src; + _.assert( _.strIs( src ) || _.arrayIs( src ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + if( eol === undefined ) + eol = _.str.lines.Eol.default; + return src.split( eol ); +} + +// + +function join( src, eol ) +{ + _.assert( _.strIs( src ) || _.arrayIs( src ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + if( eol === undefined ) + eol = _.str.lines.Eol.default; + let result = src; + if( _.arrayIs( src ) ) + result = src.join( eol ); + return result; +} + +// + +/** + * Remove espace characters and white spaces at the begin or at the end of each line. + * Input arguments can be strings or arrays of strings. If input is a string, it splits it in lines and + * removes the white/escape characters from the beggining and the end of each line. If input is an array, + * it treats it as a single string split into lines, where each entry corresponds to a line. Therefore, + * it removes the white/escape characters only from the beggining and the end of the strings in the array. + * + * @param { String/Array } [ src ] - Source string or array of strings. + * @returns { String/Array } Returns string/array with empty lines and spaces removed. + * + * @example input string + * _.str.lines.strip( ' Hello \r\n\t World \n\n ' ); + * // returns 'Hello\nWorld' + * + * @example input array + * _.str.lines.strip( [ ' Hello \r\n\t world \n\n ', '\n! \n' ] ); + * // returns [ 'Hello \r\n\t world', '!' ] + * + * @example input strings + * _.str.lines.strip( ' Hello \r\n\t', ' World \n\n ! \n\n', '\n\n' ); + * // returns [ 'Hello', 'World\n!', '' ] + * + * @example input arrays + * _.str.lines.strip( [ ' Hello \r\n\t world \n\n ', '\n! \n' ], [ '\n\nHow\n\nAre ', ' \r\nyou ? \n'], [ '\t\r\n ' ] ); + * // returns [ [ 'Hello \r\n\t world', '!' ], [ 'How\n\nAre', 'you ?' ], [] ] + * + * @method strip + * @throws { Exception } Throw an exception if( src ) is not a String or Array. + * @namespace Tools/str/lines/strip + */ + +/* qqq : measure time and optimize. ask */ +function strip( src ) +{ + + if( arguments.length > 1 ) + { + let result = _.unroll.make( null ); + for( let a = 0 ; a < arguments.length ; a++ ) + result[ a ] = _.str.lines.strip( arguments[ a ] ); + return result; + } + + _.assert( _.strIs( src ) || _.arrayIs( src ) ); + _.assert( arguments.length === 1 ); + + let lines = _.strLinesSplit( src ); + lines = lines.map( ( line ) => line.trim() ).filter( ( line ) => line ); + + if( _.strIs( src ) ) + lines = _.str.lines.join( lines ); + return lines; +} + +// + +function atLeft( src, index, eol ) +{ + let result; + + _.assert( _.number.is( index ) ); + + if( index < 0 ) + { + result = Object.create( null ); + result.src = src; + result.lineIndex = index; + result.charInterval = [ 0, -1 ]; + return result; + } + + let o2 = Object.create( null ); + o2.src = src; + o2.eol = eol; + o2.onEach = onEach; + o2.interval = [ index, index ]; + o2.withLine = false; + this.eachLeft( o2 ); + + if( !result ) + { + result = Object.create( null ); + result.src = src; + result.lineIndex = index; + result.charInterval = [ src.length, src.length-1 ]; + } + + delete result.eol; + delete result.onEach; + delete result.interval; + delete result.withLine; + + return result; + + function onEach( it ) + { + result = it; + result.line = src.slice( it.charInterval[ 0 ], it.charInterval[ 1 ]-it.nl.length+1 ); + } + +} + +// + +function atRight( src, index, eol ) +{ + let result; + + _.assert( _.number.is( index ) ); + + if( index < 0 ) + { + result = Object.create( null ); + result.src = src; + result.lineIndex = index; + result.charInterval = [ src.length, src.length-1 ]; + return result; + } + + let o2 = Object.create( null ); + o2.src = src; + o2.eol = eol; + o2.onEach = onEach; + o2.interval = [ index, index ]; + o2.withLine = false; + + this.eachRight( o2 ); + + if( !result ) + { + result = Object.create( null ); + result.src = src; + result.lineIndex = index; + result.charInterval = [ 0, -1 ]; + } + + delete result.eol; + delete result.onEach; + delete result.interval; + delete result.withLine; + + return result; + + function onEach( it ) + { + result = it; + result.line = src.slice( it.charInterval[ 0 ], it.charInterval[ 1 ]-it.nl.length+1 ); + } + +} + +// + +function _eachLeft( o ) +{ + + if( o.eol === undefined ) + o.eol = _.str.lines.Eol.default; + else if( !_.str.is( o.eol ) ) + o.eol = [ ... o.eol ]; + + const lastIndex = o.interval ? o.interval[ 1 ] : Infinity; + const src = o.src; + let foundTokenIndex; + let foundOffset; + let handleEach; + + o.charInterval = [ -1, -1 ]; + o.lineIndex = -1; + + if( o.interval && o.interval[ 1 ] < 0 ) + { + o.charInterval[ 0 ] = 0; + return o; + } + + o.nl = ''; + + if( o.interval ) + { + if( o.withLine ) + handleEach = handleWithIntervalWithLine; + else + handleEach = handleWithIntervalWithoutLine; + } + else + { + if( o.withLine ) + handleEach = handleWithoutIntervalWithLine; + else + handleEach = handleWithoutIntervalWithoutLine; + } + + if( _.str.is( o.eol ) ) + single(); + else + multiple(); + + if( !o.interval || o.lineIndex < o.interval[ 1 ] ) + { + o.lineIndex += 1; + o.charInterval[ 0 ] = src.length; + _.assert( o.charInterval[ 1 ] === src.length - 1 ); + if( o.withLine ) + o.line = ''; + } + + return o; + + /* */ + + function single() + { + + o.nl = o.eol; + while( o.lineIndex !== lastIndex ) + { + o.charInterval[ 0 ] = Math.max( o.charInterval[ 0 ], o.charInterval[ 1 ] ) + 1; + o.charInterval[ 1 ] = src.indexOf( o.eol, o.charInterval[ 0 ] ); + o.lineIndex += 1; + + if( o.charInterval[ 1 ] === -1 ) + { + o.charInterval[ 1 ] = src.length - 1; + o.nl = ''; + handleEach(); + break; + } + else + { + o.charInterval[ 1 ] += o.nl.length - 1; + handleEach(); + } + + } + + } + + /* */ + + function multiple() + { + + foundTokenIndex = -1; + foundOffset = src.length; + + let first = indexInit(); + + if( first.length === 1 ) + { + o.eol = o.eol[ foundTokenIndex ]; + return single(); + } + + if( first.length === 0 ) + { + + o.lineIndex = 0; + o.charInterval[ 0 ] = 0; + o.charInterval[ 1 ] = src.length-1; + handleEach(); + + return; + } + + while( o.lineIndex !== lastIndex ) + { + o.charInterval[ 0 ] = Math.max( o.charInterval[ 0 ], o.charInterval[ 1 ] ) + 1; + o.charInterval[ 1 ] = indexOf( first ); + o.lineIndex += 1; + + if( o.charInterval[ 1 ] === o.src.length ) + { + o.charInterval[ 1 ] = src.length - 1; + o.nl = ''; + handleEach(); + break; + } + else + { + o.nl = o.eol[ foundTokenIndex ]; + o.charInterval[ 1 ] += o.nl.length - 1; + handleEach(); + } + + } + + } + + /* */ + + function indexInit() + { + let first = []; + for( let i = o.eol.length - 1 ; i >= 0 ; i-- ) + { + let offset = src.indexOf( o.eol[ i ] ); + if( offset !== -1 ) + { + first.unshift( offset ); + if( foundOffset >= offset ) + { + foundOffset = offset; + foundTokenIndex = i; + } + } + else + { + o.eol.splice( i, 1 ); + foundTokenIndex -= 1; + } + } + return first; + } + + /* */ + + function indexOf( first ) + { + if( first[ foundTokenIndex ] >= o.charInterval[ 0 ] ) + return first[ foundTokenIndex ]; + foundOffset = src.length; + for( let i = first.length - 1; i >= 0 ; i-- ) + { + let offset = first[ i ]; + if( offset < o.charInterval[ 0 ] ) + { + offset = src.indexOf( o.eol[ i ], first[ i ]+1 ); + if( offset === -1 ) + { + tokenDelete( first, i ); + if( first.length === 0 ) + return src.length; + } + else + { + first[ i ] = offset; + if( foundOffset >= offset ) + { + foundOffset = offset; + foundTokenIndex = i; + } + } + } + else + { + if( foundOffset >= offset ) + { + foundOffset = offset; + foundTokenIndex = i; + } + } + } + return first[ foundTokenIndex ]; + } + + /* */ + + function tokenDelete( first, i ) + { + o.eol.splice( i, 1 ); + first.splice( i, 1 ); + if( foundTokenIndex > i ) + foundTokenIndex -= 1; + } + + /* */ + + function handleWithoutIntervalWithoutLine() + { + o.onEach( o ); + } + + /* */ + + function handleWithIntervalWithoutLine() + { + if( o.interval && o.interval[ 0 ] > o.lineIndex ) + return; + o.onEach( o ); + } + + /* */ + + function handleWithoutIntervalWithLine() + { + o.line = src.slice( o.charInterval[ 0 ], o.charInterval[ 1 ] - o.nl.length + 1 ); + o.onEach( o ); + } + + /* */ + + function handleWithIntervalWithLine() + { + if( o.interval && o.interval[ 0 ] > o.lineIndex ) + return; + o.line = src.slice( o.charInterval[ 0 ], o.charInterval[ 1 ] - o.nl.length + 1 ); + o.onEach( o ); + } + + /* */ + +} + +_eachLeft.defaults = +{ + src : null, + eol : null, + interval : null, + withLine : true, +} + +// + +function eachLeft( o ) +{ + + if( !_.map.is( o ) ) + { + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( arguments.length === 3 ) + o = { src : arguments[ 0 ], interval : arguments[ 1 ], onEach : arguments[ 2 ] }; + else + o = { src : arguments[ 0 ], onEach : arguments[ 1 ] }; + } + else + { + _.assert( arguments.length === 1 ); + } + + if( o.withLine === undefined ) + o.withLine = true; + + _.assert( _.routine.is( o.onEach ) ); + _.assert( _.str.is( o.src ) ); + + return this._eachLeft( o ); +} + +// + +function _eachRight( o ) +{ + + if( o.eol === undefined ) + o.eol = _.str.lines.Eol.default; + else if( !_.str.is( o.eol ) ) + o.eol = [ ... o.eol ]; + + const lastIndex = o.interval ? o.interval[ 1 ] : Infinity; + const src = o.src; + let foundTokenIndex; + let foundOffset; + let nnl = ''; + let handleEach; + + if( o.interval ) + { + if( o.withLine ) + handleEach = handleWithIntervalWithLine; + else + handleEach = handleWithIntervalWithoutLine; + } + else + { + if( o.withLine ) + handleEach = handleWithoutIntervalWithLine; + else + handleEach = handleWithoutIntervalWithoutLine; + } + + o.charInterval = [ o.src.length, o.src.length ]; + o.lineIndex = -1; + + if( o.interval && o.interval[ 1 ] < 0 ) + { + o.charInterval[ 1 ] = o.src.length-1; + return o; + } + + o.nl = ''; + + if( _.str.is( o.eol ) ) + single(); + else + multiple(); + + if( !o.interval || o.lineIndex < o.interval[ 1 ] ) + { + o.lineIndex += 1; + o.charInterval[ 1 ] = -1; + _.assert( o.charInterval[ 0 ] === 0 ); + if( o.withLine ) + o.line = ''; + } + + return o; + + /* */ + + function single() + { + + while( o.lineIndex !== lastIndex ) + { + + o.lineIndex += 1; + o.nl = nnl; + + o.charInterval[ 1 ] = o.charInterval[ 0 ] - 1; + let right = o.charInterval[ 1 ] - o.nl.length; + if( right >= 0 || o.lineIndex === 0 ) + o.charInterval[ 0 ] = src.lastIndexOf( o.eol, right ); + else + o.charInterval[ 0 ] = -1; + + if( o.charInterval[ 0 ] === -1 ) + { + o.charInterval[ 0 ] = 0; + handleEach(); + break; + } + else + { + nnl = o.eol; + o.charInterval[ 0 ] += nnl.length; + handleEach(); + } + + } + + } + + /* */ + + function multiple() + { + + foundTokenIndex = -1; + foundOffset = 0; + + let first = indexInit(); + + if( first.length === 1 ) + { + o.eol = o.eol[ foundTokenIndex ]; + return single(); + } + + if( first.length === 0 ) + { + o.lineIndex = 0; + o.charInterval[ 0 ] = 0; + o.charInterval[ 1 ] = src.length-1; + handleEach(); + return; + } + + while( o.lineIndex !== lastIndex ) + { + + o.lineIndex += 1; + o.nl = nnl; + + o.charInterval[ 1 ] = o.charInterval[ 0 ] - 1; + o.charInterval[ 0 ] = indexOf( first ); + + if( o.charInterval[ 0 ] === -1 ) + { + o.charInterval[ 0 ] = 0; + handleEach(); + break; + } + else + { + nnl = o.eol[ foundTokenIndex ]; + handleEach(); + } + + } + + } + + /* */ + + function indexInit() + { + let first = []; + for( let i = o.eol.length - 1 ; i >= 0 ; i-- ) + { + let offset = src.lastIndexOf( o.eol[ i ] ); + if( offset !== -1 ) + { + offset += o.eol[ i ].length; + first.unshift( offset ); + if( foundOffset <= offset ) + { + foundOffset = offset; + foundTokenIndex = i; + } + } + else + { + o.eol.splice( i, 1 ); + foundTokenIndex -= 1; + } + } + return first; + } + + /* */ + + function indexOf( first ) + { + let left = o.charInterval[ 0 ] - nnl.length - 1; + if( first[ foundTokenIndex ] <= left ) + return first[ foundTokenIndex ]; + foundOffset = -1; + for( let i = first.length - 1; i >= 0 ; i-- ) + { + let offset = first[ i ]; + if( offset > left ) + { + if( left >= 0 ) + offset = src.lastIndexOf( o.eol[ i ], left ); + else + offset = -1; + if( offset === -1 ) + { + tokenDelete( first, i ); + if( first.length === 0 ) + return -1; + } + else + { + offset += o.eol[ i ].length; + first[ i ] = offset; + if( foundOffset <= offset ) + { + foundOffset = offset; + foundTokenIndex = i; + } + } + } + else + { + if( foundOffset <= offset ) + { + foundOffset = offset; + foundTokenIndex = i; + } + } + } + return first[ foundTokenIndex ]; + } + + /* */ + + function tokenDelete( first, i ) + { + o.eol.splice( i, 1 ); + first.splice( i, 1 ); + if( foundTokenIndex > i ) + foundTokenIndex -= 1; + } + + /* */ + + function handleWithoutIntervalWithoutLine() + { + o.onEach( o ); + } + + /* */ + + function handleWithIntervalWithoutLine() + { + if( o.interval && o.interval[ 0 ] > o.lineIndex ) + return; + o.onEach( o ); + } + + /* */ + + function handleWithoutIntervalWithLine() + { + o.line = src.slice( o.charInterval[ 0 ], o.charInterval[ 1 ] - o.nl.length + 1 ); + o.onEach( o ); + } + + /* */ + + function handleWithIntervalWithLine() + { + if( o.interval && o.interval[ 0 ] > o.lineIndex ) + return; + o.line = src.slice( o.charInterval[ 0 ], o.charInterval[ 1 ] - o.nl.length + 1 ); + o.onEach( o ); + } + + /* */ + +} + +_eachRight.defaults = +{ + ... _eachLeft.defaults, +} + +// + +function eachRight( o ) +{ + + if( !_.map.is( o ) ) + { + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( arguments.length === 3 ) + o = { src : arguments[ 0 ], interval : arguments[ 1 ], onEach : arguments[ 2 ] }; + else + o = { src : arguments[ 0 ], onEach : arguments[ 1 ] }; + } + else + { + _.assert( arguments.length === 1 ); + } + + if( o.withLine === undefined ) + o.withLine = true; + + _.assert( _.routine.is( o.onEach ) ); + _.assert( _.str.is( o.src ) ); + + return this._eachRight( o ); +} + +// -- +// str extension +// -- + +let Eol = +{ + any : [ '\r\n', '\n\r', '\n' ], + posix : '\n', + windows : '\r\n', + mac : '\n\r', + default : '\n', +} + +let StrLinesExtension = +{ + + Eol, + + split, + join, + strip, + + atLeft, + atRight, + at : atLeft, + + _eachLeft, + eachLeft, + _eachRight, + eachRight, + each : eachLeft, + +} + +Object.assign( _.str.lines, StrLinesExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + strLinesSplit : split, + strLinesJoin : join, + strLinesStrip : strip, + +} + +Object.assign( _, ToolsExtension ); + +// + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/StrLines.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, StrLines_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file StrLines_s */ })(); + +/* */ /* begin of file Symbol_s */ ( function Symbol_s() { function Symbol_s_naked() { ( function _l1_Symbol_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.symbol = _.symbol || Object.create( null ); + +// -- +// symbol +// -- + +function is( src ) +{ + let result = Object.prototype.toString.call( src ) === '[object Symbol]'; + return result; +} + +// + +function exportStringCodeShallow( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + _.assert( _.symbol.is( src ) ); + + let text = src.toString().slice( 7, -1 ); + let result = `Symbol.for(${text ? ' \'' + text + '\' )' : ')'}`; + return result; +} + +// + +function exportStringDiagnosticShallow( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + _.assert( _.symbol.is( src ) ); + + let text = src.toString().slice( 7, -1 ); + let result = `{- Symbol${text ? ' ' + text + ' ' : ' '}-}`; + return result; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + symbolIs : is +} + +// + +let Extension = +{ + + // dichotomy + + is, + + // exporter + + exportString : exportStringDiagnosticShallow, + // exportStringDiagnosticShallow : exportStringDiagnosticShallow, + exportStringCodeShallow, + exportStringDiagnosticShallow, + // exportStringDiagnostic : exportStringDiagnosticShallow, + // exportStringCode : exportStringCodeShallow, + + // symbols + + def : Symbol.for( 'def' ), + null : Symbol.for( 'null' ), + undefined : Symbol.for( 'undefined' ), + void : Symbol.for( 'void' ), + nothing : Symbol.for( 'nothing' ), + anything : Symbol.for( 'anything' ), + maybe : Symbol.for( 'maybe' ), + unknown : Symbol.for( 'unknown' ), + dont : Symbol.for( 'dont' ), + self : Symbol.for( 'self' ), + optional : Symbol.for( 'optional' ), + + unroll : Symbol.for( 'unroll' ), + prototype : Symbol.for( 'prototype' ), + constructor : Symbol.for( 'constructor' ), + +} + +Object.assign( _, ToolsExtension ); +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Symbol.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Symbol_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Symbol_s */ })(); + +/* */ /* begin of file Time_s */ ( function Time_s() { function Time_s_naked() { ( function _l1_Time_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.time = _.time || Object.create( null ); + +// -- +// time +// -- + +function timerIs( src ) +{ + if( !src ) + return false; + return _.strIs( src.type ) && !!src.time && !!src.cancel; +} + +// + +function competitorIs( src ) +{ + if( !src ) + return false; + if( !_.mapIs( src ) ) + return false; + return src.competitorRoutine !== undefined; +} + +// + +/** + * The routine timerInBegin() checks the state of timer {-timer-}. If {-timer-} is created and + * timer methods is not executed, then routine returns true. Otherwise, false is returned. + * + * @example + * let timer = _.time.begin( 500, () => 'executed', () => 'canceled' ); + * _.time.timerInBegin( timer ); + * // returns : true + * + * @example + * let timer = _.time.begin( 500, () => 'executed', () => 'canceled' ); + * _.time.cancel( timer ); + * _.time.timerInBegin( timer ); + * // returns : false + * + * @example + * let timer = _.time.begin( 500, () => 'executed', () => 'canceled' ); + * _.time.out( 2000, () => _.time.timerInBegin( timer ) ); + * // returns : false + * + * @param { Timer } timer - The timer to check. + * @returns { Boolean } - Returns true if timer methods is not executed. Otherwise, false is returned. + * @function timerInBegin + * @throws { Error } If arguments is not provided. + * @throws { Error } If {-timer-} is not a Timer. + * @namespace wTools.time + * @extends Tools + */ + +function timerInBegin( timer ) +{ + _.assert( _.timerIs( timer ) ); + return timer.state === 0; +} + +// + +/** + * The routine timerInCancelBegun() checks the state of timer {-timer-}. If {-timer-} starts executing of callback + * {-onCancel-} and not finished it, then routine returns true. Otherwise, false is returned. + * + * @example + * let timer = _.time.begin( 500, () => 'executed', () => 'canceled' ); + * _.time.timerInCancelBegun( timer ); + * // returns : false + * + * @example + * let timer = _.time.begin( 500, () => 'executed', onCancel ); + * _.time.cancel( timer ); + * function onCancel() + * { + * _.time.timerInCancelBegun( timer ); + * // returns : true + * return 'canceled'; + * } + * + * @example + * let timer = _.time.begin( 500, () => 'executed', () => 'canceled' ); + * _.time.out( 2000, () => _.time.timerInCancelBegun( timer ) ); + * // returns : false + * + * @param { Timer } timer - The timer to check. + * @returns { Boolean } - Returns true if timer starts canceling and not finished it. + * Otherwise, false is returned. + * @function timerInCancelBegun + * @throws { Error } If arguments is not provided. + * @throws { Error } If {-timer-} is not a Timer. + * @namespace wTools.time + * @extends Tools + */ + +function timerInCancelBegun( timer ) +{ + _.assert( _.timerIs( timer ) ); + return timer.state === -1; +} + +// + +/** + * The routine timerInCancelEnded() checks the state of timer {-timer-}. If {-timer-} finished executing of + * callback {-onCancel-}, then routine returns true. Otherwise, false is returned. + * + * @example + * let timer = _.time.begin( 500, () => 'executed', () => 'canceled' ); + * _.time.timerInCancelEnded( timer ); + * // returns : false + * + * @example + * let timer = _.time.begin( 500, () => 'executed', onCancel ); + * _.time.cancel( timer ); + * function onCancel() + * { + * _.time.timerInCancelEnded( timer ); + * // returns : false + * return 'canceled'; + * } + * + * @example + * let timer = _.time.begin( 500, () => 'executed', () => 'canceled' ); + * _.time.out( 2000, () => _.time.timerInCancelEnded( timer ) ); + * // returns : false + * + * @example + * let timer = _.time.begin( 500, () => 'executed', () => 'canceled' ); + * _.time.cancel( timer ); + * // returns : true + * + * @param { Timer } timer - The timer to check. + * @returns { Boolean } - Returns true if timer starts canceling and finished it. + * Otherwise, false is returned. + * @function timerInCancelEnded + * @throws { Error } If arguments is not provided. + * @throws { Error } If {-timer-} is not a Timer. + * @namespace wTools.time + * @extends Tools + */ + +function timerInCancelEnded( timer ) +{ + _.assert( _.timerIs( timer ) ); + return timer.state === -2; +} + +// + +function timerIsCanceled( timer ) +{ + _.assert( _.timerIs( timer ) ); + return timer.state === -1 || timer.state === -2; +} + +// + +/** + * The routine timerInEndBegun() checks the state of timer {-timer-}. If {-timer-} starts executing of callback + * {-onTime-} and not finished it, then routine returns true. Otherwise, false is returned. + * + * @example + * let timer = _.time.begin( 500, () => 'executed', () => 'canceled' ); + * _.time.timerInEndBegun( timer ); + * // returns : false + * + * @example + * let timer = _.time.begin( 500, () => 'executed', onCancel ); + * _.time.cancel( timer ); + * function onCancel() + * { + * _.time.timerInEndBegun( timer ); + * // returns : false + * return 'canceled'; + * } + * + * @example + * let timer = _.time.begin( 500, onTime, () => 'canceled' ); + * function onTime() + * { + * _.time.timerInEndBegun( timer ); + * // returns : true + * return 'executed'; + * } + * + * @param { Timer } timer - The timer to check. + * @returns { Boolean } - Returns true if timer starts executing of callback {-onTime-} and not finished it. + * Otherwise, false is returned. + * @function timerInEndBegun + * @throws { Error } If arguments is not provided. + * @throws { Error } If {-timer-} is not a Timer. + * @namespace wTools.time + * @extends Tools + */ + +function timerInEndBegun( timer ) +{ + _.assert( _.timerIs( timer ) ); + return timer.state === 1; +} + +// + +/** + * The routine timerInEndEnded() checks the state of timer {-timer-}. If {-timer-} finished executing of callback + * {-onTime-}, then routine returns true. Otherwise, false is returned. + * + * @example + * let timer = _.time.begin( 500, () => 'executed', () => 'canceled' ); + * _.time.timerInEndEnded( timer ); + * // returns : false + * + * @example + * let timer = _.time.begin( 500, () => 'executed', onCancel ); + * _.time.cancel( timer ); + * function onCancel() + * { + * _.time.timerInEndEnded( timer ); + * // returns : false + * return 'canceled'; + * } + * + * @example + * let timer = _.time.begin( 500, () => 'executed', () => 'canceled' ); + * _.time.out( 2000, () => _.time.timerInEndEnded( timer ) ); + * // returns : true + * + * @param { Timer } timer - The timer to check. + * @returns { Boolean } - Returns true if timer finished executing of callback {-onTime-}. + * Otherwise, false is returned. + * @function timerInEndEnded + * @throws { Error } If arguments is not provided. + * @throws { Error } If {-timer-} is not a Timer. + * @namespace wTools.time + * @extends Tools + */ + +function timerInEndEnded( timer ) +{ + _.assert( _.timerIs( timer ) ); + return timer.state === 2; +} + +// -- +// +// -- + +let _TimeInfinity = Math.pow( 2, 31 )-1; + +// + +function _begin( delay, onTime, onCancel ) +{ + let native; + + if( delay >= _TimeInfinity ) + delay = _TimeInfinity; + + _.assert( arguments.length === 1 || arguments.length === 2 || arguments.length === 3 ); + + if( delay > 0 ) + native = setTimeout( time, delay ); + else + native = soon( timeNonCancelable ) || null; + + let timer = Object.create( null ); + timer.onTime = onTime; + timer.onCancel = onCancel; + timer._time = _time; + timer._cancel = _cancel; + timer.time = native === null ? timeNonCancelable : time; + timer.cancel = cancel; + timer.state = 0; + timer.type = 'delay'; + timer.native = native; + return timer; + + /* */ + + function _time() + { + if( timer.state === 1 || timer.state === -1 ) + return; + + _.assert( timer.state > -2, 'Cannot change state of timer.' ); + _.assert( timer.state < 2, 'Timer can be executed only one time.' ); + + timer.state = 1; + try + { + if( onTime ) + timer.result = onTime( timer ); + } + finally + { + _.assert( timer.state === 1 ); + timer.state = 2; + } + } + + /* */ + + function _cancel() + { + if( timer.state === 1 || timer.state === -1 ) + return; + + _.assert( timer.state < 2, 'Cannot change state of timer.' ); + _.assert( timer.state > -2, 'Timer can be canceled only one time.' ); + + timer.state = -1; + clearTimeout( timer.native ); + try + { + if( onCancel ) + timer.result = onCancel( timer ); + } + finally + { + _.assert( timer.state === -1 ); + timer.state = -2; + } + } + + /* */ + + function timeNonCancelable() + { + if( timer.state !== 0 ) + return; + return time.call( this, arguments ); + } + + /* */ + + function time() + { + timer._time(); + clearTimeout( timer.native ); + return timer; + } + + /* */ + + function cancel() + { + return timer._cancel(); + } + +} + +// + +function _finally( delay, onTime ) +{ + _.assert( arguments.length === 2 ); + let timer = _.time._begin( delay, onTime, onTime ); + return timer; +} + +// + +function _periodic( delay, onTime, onCancel ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects exactly two or three arguments' ); + + let native = setInterval( time, delay ); + + let timer = Object.create( null ); + timer.onTime = onTime; + timer.onCancel = onCancel; + timer._time = _time; + timer._cancel = _cancel; + timer.time = time; + timer.cancel = cancel; + timer.state = 0; + timer.type = 'periodic'; + timer.native = native; + return timer; + + /* */ + + function _time() + { + _.assert( timer.state !== -1 && timer.state !== -2, 'Illegal call, timer is canceled. Please, use new timer.' ); + + timer.state = 1; + try + { + if( onTime ) + timer.result = onTime( timer ); + } + finally + { + if( timer.result === undefined || timer.result === _.dont ) /* Dmytro : if it needs, change to any other stop value */ + timer.cancel(); + else + timer.state = 2; + } + } + + /* */ + + function _cancel() + { + + _.assert( timer.state !== -1 && timer.state !== -2, 'Illegal call, timer is canceled.' ); + + timer.state = -1; + clearInterval( timer.native ); + try + { + if( onCancel ) + timer.result = onCancel( timer ); + } + finally + { + timer.state = -2; + } + } + + /* */ + + function time() + { + return timer._time(); + } + + /* */ + + function cancel() + { + return timer._cancel(); + } + +} + +// + +function _cancel( timer ) +{ + _.assert( _.timerIs( timer ) ); + + timer.cancel(); + + return timer; +} + +// + +/** + * The routine begin() make new timer for procedure {-procedure-}. The timer executes callback {-onTime-} only once. + * Callback {-onTime-} executes when time delay {-delay-} is elapsed. If the timer is canceled, then the callback + * {-onCancel-} is executed. + * + * @example + * let timer = _.time.begin( 500, () => 'executed', () => 'canceled' ); + * _.time.out( 1000, () => + * { + * console.log( timer.result ); + * // log : 'executed' + * return null; + * }); + * console.log( timer.result ); + * // log : undefined + * + * @example + * let timer = _.time.begin( 500, () => 'executed', () => 'canceled' ); + * _.time.cancel( timer ); + * console.log( timer.result ); + * // log : 'canceled' + * + * @param { Number } delay - The time delay. + * @param { Procedure|Undefined } procedure - The procedure for timer. + * @param { Function|Undefined|Null } onTime - The callback to execute when time is elapsed. + * @param { Function|Undefined|Null } onCancel - The callback to execute when timer is canceled. + * @returns { Timer } - Returns timer. + * @function begin + * @throws { Error } If arguments.length is less than 2 or great than 4. + * @throws { Error } If {-delay-} is not a Number. + * @throws { Error } If {-onTime-} neither is a Function, nor undefined, nor null. + * @throws { Error } If {-onCancel-} neither is a Function, nor undefined, nor null. + * @namespace wTools.time + * @extends Tools + */ + +function begin( /* delay, procedure, onTime, onCancel */ ) +{ + let delay = arguments[ 0 ]; + let procedure = arguments[ 1 ]; + let onTime = arguments[ 2 ]; + let onCancel = arguments[ 3 ]; + + if( !_.procedureIs( procedure ) ) + { + onTime = arguments[ 1 ] === undefined ? null : arguments[ 1 ]; + onCancel = arguments[ 2 ] === undefined ? null : arguments[ 2 ]; + } + + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4 ); + _.assert( _.number.is( delay ) ); + _.assert( _.routine.is( onTime ) || onTime === undefined || onTime === null ); + _.assert( _.routine.is( onCancel ) || onCancel === undefined || onCancel === null ); + + return this._begin( delay, onTime, onCancel ); +} + +// + +/** + * The routine finally() make new timer for procedure {-procedure-}. The timer executes callback {-onTime-} only once. + * Callback {-onTime-} executes when time delay {-delay-} is elapsed or if the timer is canceled. + * + * @example + * let timer = _.time.finally( 500, () => 'executed' ); + * _.time.out( 1000, () => + * { + * console.log( timer.result ); + * // log : 'executed' + * return null; + * }); + * console.log( timer.result ); + * // log : undefined + * + * @example + * let timer = _.time.finally( 500, () => 'executed', () => 'canceled' ); + * _.time.cancel( timer ); + * console.log( timer.result ); + * // log : 'executed' + * + * @param { Number } delay - The time delay. + * @param { Procedure|Undefined } procedure - The procedure for timer. + * @param { Function|Undefined|Null } onTime - The callback to execute when time is elapsed. + * @param { Function|Undefined|Null } onCancel - The callback to execute when timer is canceled. + * @returns { Timer } - Returns timer. + * @function finally + * @throws { Error } If arguments.length is less than 2 or great than 3. + * @throws { Error } If {-delay-} is not a Number. + * @throws { Error } If {-onTime-} neither is a Function, nor undefined, nor null. + * @namespace wTools.time + * @extends Tools + */ + +function finally_( delay, procedure, onTime ) +{ + if( arguments.length === 2 ) + if( !_.procedureIs( procedure ) ) + onTime = arguments[ 1 ] === undefined ? null : arguments[ 1 ]; + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( _.number.is( delay ) ); + _.assert( _.routine.is( onTime ) || onTime === undefined || onTime === null ); + + return this._finally( delay, onTime ); +} + +// + +/** + * The routine periodic() make new periodic timer for procedure {-procedure-}. The timer executes callback {-onTime-} + * periodically with time interval {-delay-}. If callback {-onTime-} returns undefined or Symbol _.dont, then the + * callback {-onCancel-} executes and timer stops. + * If the times is canceled, then the callback {-onCancel-} is executed. + * + * @example + * let result = []; + * function onTime() + * { + * if( result.length < 3 ) + * return result.push( 1 ); + * else + * return undefined; + * } + * let timer = _.time.periodic( 500, onTime, () => 'canceled' ); + * _.time.out( 3000, () => + * { + * console.log( result ); + * // log : [ 1, 1, 1 ] + * console.log( timer.result ); + * // log : 'canceled' + * return null; + * }); + * console.log( timer.result ); + * // log : undefined + * + * @example + * let result = []; + * function onTime() + * { + * if( result.length < 3 ) + * return result.push( 1 ); + * else + * return undefined; + * } + * let timer = _.time.periodic( 500, onTime, () => 'canceled' ); + * _.time.cancel( timer ); + * console.log( result ); + * // log : [] + * console.log( timer.result ); + * // log : 'canceled' + * + * @param { Number } delay - The time delay. + * @param { Procedure|Undefined } procedure - The procedure for timer. + * @param { Function } onTime - The callback to execute when time is elapsed. + * @param { Function|Undefined|Null } onCancel - The callback to execute when timer is canceled. + * @returns { Timer } - Returns periodic timer. + * @function begin + * @throws { Error } If arguments.length is less than 2 or great than 4. + * @throws { Error } If {-delay-} is not a Number. + * @throws { Error } If {-onTime-} is not a Function. + * @throws { Error } If {-onCancel-} neither is a Function, nor undefined, nor null. + * @namespace wTools.time + * @extends Tools + */ + +function periodic( /* delay, procedure, onTime, onCancel */ ) +{ + let delay = arguments[ 0 ]; + let procedure = arguments[ 1 ]; + let onTime = arguments[ 2 ]; + let onCancel = arguments[ 3 ]; + + if( !_.procedureIs( procedure ) ) + { + onTime = arguments[ 1 ] === undefined ? null : arguments[ 1 ]; + onCancel = arguments[ 2 ] === undefined ? null : arguments[ 2 ]; + } + + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4 ); + _.assert( _.number.is( delay ) ); + _.assert( _.routine.is( onTime ) ); + _.assert( _.routine.is( onCancel ) || onCancel === undefined || onCancel === null ); + + return this._periodic( delay, onTime, onCancel ); +} + +// + +/** + * The routine cancel() cancels timer {-timer-}. + * + * @example + * let timer = _.time.begin( 500, () => 'executed', () => 'canceled' ); + * let canceled = _.time.cancel( timer ); + * console.log( timer.result ); + * // log : 'canceled' + * console.log( timer === canceled ); + * // log : true + * + * @example + * let timer = _.time.periodic( 500, () => 'executed', () => 'canceled' ); + * let canceled = _.time.cancel( timer ); + * console.log( timer.result ); + * // log : 'canceled' + * console.log( timer === canceled ); + * // log : true + * + * @param { Timer } timer - The timer to cancel. + * @returns { Timer } - Returns canceled timer. + * @function cancel + * @throws { Error } If {-timer-} is not a Timer. + * @namespace wTools.time + * @extends Tools + */ + +function cancel( timer ) +{ + return _.time._cancel( ... arguments ); +} + +// + +/** + * The routine _now_functor() make the better function to get current time in ms. + * The returned function depends on environment. + * + * @example + * let now = _.time._now_functor(); + * console.log( _.routine.is( now ) ); + * // log : true + * console.log( now() ); + * // log : 1603172830154 + * + * @returns { Function } - Returns function to get current time in ms. + * @function _now_functor + * @namespace wTools.time + * @extends Tools + */ + +function _now_functor() +{ + let now; + + let majorVersion = 0; + if( typeof process !== 'undefined' && process.versions !== undefined ) + majorVersion = Number( process.versions.node.match( /^\d+/ )[ 0 ] ); + if( typeof performance !== 'undefined' && performance.now !== undefined && majorVersion < 16 ) + now = _.routine.join( performance, performance.now ); + else if( Date.now ) + now = _.routine.join( Date, Date.now ); + else + now = function(){ return Date().getTime() }; + + return now; +} + +// + +/** + * The routine soon() execute routine {-h-} asynchronously as soon as possible. In NodeJS interpreter it + * executes on nextTick, in another interpreters in async queue. + * + * @example + * let result = [ _.time.now() ]; + * _.time.soon( () => result.push( _.time.now() ) ); + * // the delta ( result[ 1 ] - result[ 0 ] ) is small as possible + * + * @param { Function } h - The routine to execute. + * @returns { Undefined } - Returns undefined, executes routine {-h-}. + * @function soon + * @throws { Error } If arguments is not provided. + * @throws { Error } If {-h-} is not a Function. + * @namespace wTools.time + * @extends Tools + */ + +const soon = typeof process === 'undefined' ? function( h ){ return setTimeout( h, 0 ) } : process.nextTick; + +// -- +// implementation +// -- + +/* qqq : make namespace _.timer */ +let TimeExtension = +{ + + /* qqq : for junior : bad */ + timerIs, /* qqq : cover */ + competitorIs, /* xxx : move */ + + timerInBegin, + timerInCancelBegun, + timerInCancelEnded, + timerIsCanceled, + timerInEndBegun, + timerInEndEnded, + + _begin, + _finally, + _periodic, + _cancel, + + begin, + finally : finally_, + periodic, + cancel, + + _now_functor, + now : _now_functor(), + soon, + +} + +// + +Object.assign( _.time, TimeExtension ); + +// + +let ToolsExtension = +{ + + /* qqq : for junior : bad */ + timerIs, + competitorIs, /* xxx : move */ + +} + +// + +Object.assign( _, ToolsExtension ); + +/* qqq : for junior : replace Routines+Fields -> {- name of namespace -}Extension in all files */ + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Time.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Time_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Time_s */ })(); + +/* */ /* begin of file Type_s */ ( function Type_s() { function Type_s_naked() { ( function _l1_Type_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _global_.wTools; + +// -- +// type test +// -- + +function undefinedIs( src ) +{ + if( src === undefined ) + return true; + return false; +} + +// + +function nullIs( src ) +{ + if( src === null ) + return true; + return false; +} + +// + +function nothingIs( src ) +{ + if( src === null ) + return true; + if( src === undefined ) + return true; + if( src === _.nothing ) + return true; + return false; +} + +// + +function definedIs( src ) +{ + return src !== undefined && src !== null && !Number.isNaN( src ) && src !== _.nothing; +} + +// + +// function primitiveIs( src ) +// { +// if( !src ) +// return true; +// let t = Object.prototype.toString.call( src ); +// return t === '[object Symbol]' || t === '[object Number]' || t === '[object BigInt]' || t === '[object Boolean]' || t === '[object String]'; +// } + +// + +function consequenceIs( src ) +{ + if( !src ) + return false; + + let prototype = Object.getPrototypeOf( src ); + + if( !prototype ) + return false; + + return prototype.shortName === 'Consequence'; +} + +// + +function consequenceLike( src ) +{ + if( _.consequenceIs( src ) ) + return true; + + if( _.promiseIs( src ) ) + return true; + + return false; +} + +// + +function promiseIs( src ) +{ + if( !src ) + return false; + return src instanceof Promise; +} + +// + +function promiseLike( src ) +{ + if( !src ) + return false; + // if( !_.object.isBasic( src ) ) + // return false; + return _.routine.is( src.then ) && _.routine.is( src.catch ) && ( src.constructor ) && ( src.constructor.name !== 'wConsequence' ); +} + +// + +function typeOf( src, constructor ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( arguments.length === 2 ) + { + return _.typeOf( src ) === constructor; + } + + if( src === null || src === undefined ) + { + return null; + } + else if( _.number.is( src ) || _.bool.is( src ) || _.strIs( src ) ) /* yyy */ + { + return src.constructor; + } + else if( src.constructor ) + { + _.assert( _.routine.is( src.constructor ) && src instanceof src.constructor ); + return src.constructor; + } + else + { + return null; + } + +} + +// // +// +// function prototypeIsStandard( src ) +// { +// +// if( !_.workpiece.prototypeIs( src ) ) +// return false; +// +// if( !Object.hasOwnProperty.call( src, 'Composes' ) ) +// return false; +// +// return true; +// } + +// + +/** + * Checks if argument( cls ) is a constructor. + * @function constructorIs + * @param {Object} cls - entity to check + * @namespace Tools + */ + +function constructorIs( cls ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + return _.routine.is( cls ) && !instanceIs( cls ); +} + +// + +/** + * Is instance of a class. + * @function instanceIs + * @param {object} src - entity to check + * @namespace Tools + */ + +function instanceIs( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.primitive.is( src ) ) + return false; + + if( Object.hasOwnProperty.call( src, 'constructor' ) ) + return false; + if( !Reflect.has( src, 'constructor' ) ) + return false; + + let prototype = Object.getPrototypeOf( src ); + _.assert( prototype !== undefined ); + + if( prototype === null ) + return false; + // if( prototype === undefined ) + // return false; + if( prototype === Object.prototype ) + return false; + if( _.routine.is( prototype ) ) + return false; + + // return Object.hasOwnProperty.call( prototype, 'constructor' ); + + return true; +} + +// + +function workerIs( src ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 ); + if( arguments.length === 1 ) + { + if( typeof WorkerGlobalScope !== 'undefined' && src instanceof WorkerGlobalScope ) + return true; + if( typeof Worker !== 'undefined' && src instanceof Worker ) + return true; + return false; + } + else + { + return typeof WorkerGlobalScope !== 'undefined'; + } +} + +// + +function streamIs( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + return _.object.isBasic( src ) && _.routine.is( src.pipe ) +} + +// +// xxx : remove from here +// +// function consoleIs( src ) +// { +// _.assert( arguments.length === 1, 'Expects single argument' ); +// +// if( console.Console ) +// if( src && src instanceof console.Console ) +// return true; +// +// if( src !== console ) +// return false; +// +// let result = Object.prototype.toString.call( src ); +// if( result === '[object Console]' || result === '[object Object]' ) +// return true; +// +// return false; +// } +// +// // +// +// function loggerIs( src ) +// { +// _.assert( arguments.length === 1, 'Expects single argument' ); +// +// if( !_.Logger ) +// return false; +// +// if( src instanceof _.Logger ) +// return true; +// +// return false; +// } + +// + +function processIs( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + // let type = _.entity.strType( src ); + let type = _.entity.strTypeSecondary( src ); + if( type === 'ChildProcess' || type === 'process' ) + return true; + + return false; +} + +// + +function procedureIs( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + if( !src ) + return false; + if( !_.Procedure ) + return false; + return src instanceof _.Procedure; +} + +// + +function definitionIs( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( !src ) + return false; + + if( !_.Definition ) + return false; + + return src instanceof _.Definition; +} + +// + +function traitIs( trait ) +{ + if( !_.definitionIs( trait ) ) + return false; + return trait.defGroup === 'trait'; +} + +// + +function blueprintIsDefinitive( blueprint ) +{ + if( !blueprint ) + return false; + if( !_.blueprint.isDefinitive ) + return false; + return _.blueprint.isDefinitive( blueprint ); +} + +// + +function blueprintIsRuntime( blueprint ) +{ + if( !blueprint ) + return false; + if( !_.blueprint.isRuntime ) + return false; + return _.blueprint.isRuntime( blueprint ); +} + +// -- +// implementation +// -- + +let ToolsExtension = +{ + + // primitive + + undefinedIs, + nullIs, + nothingIs, + definedIs, + + // + + consequenceIs, + consequenceLike, + promiseIs, + promiseLike, + + typeOf, + constructorIs, + instanceIs, + + workerIs, + streamIs, + // consoleIs, + // loggerIs, + processIs, + procedureIs, + + definitionIs, /* xxx : move to namespace::property */ + traitIs, /* xxx : move to namespace::property */ + + blueprintIsDefinitive, + blueprintIsRuntime, + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Type.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Type_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Type_s */ })(); + +/* */ /* begin of file Units_s */ ( function Units_s() { function Units_s_naked() { ( function _l1_Units_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.units = _.units || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +var Extension = +{ + +} + +// + +var ToolsExtension = +{ + +} + +// + +Object.assign( _.units, Extension ); +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Units.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Units_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Units_s */ })(); + +/* */ /* begin of file Unroll_s */ ( function Unroll_s() { function Unroll_s_naked() { ( function _l1_Unroll_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.unroll = _.unroll || Object.create( null ); + +// -- +// unroll +// -- + +/** + * The routine is() determines whether the passed value is an instance of type Unroll ( unroll-array ). + * + * If {-src-} is an Unroll, then returns true, otherwise returns false. + * + * @param { * } src - The object to be checked. + * + * @example + * _.unroll.is( _.unroll.make( [ 1, 'str' ] ) ); + * // returns true + * + * @example + * _.unroll.is( [] ); + * // returns false + * + * @example + * _.unroll.is( 1 ); + * // returns false + * + * @returns { boolean } Returns true if {-src-} is an Unroll. + * @function is + * @namespace Tools/unroll + */ + +function is( src ) +{ + if( !_.arrayIs( src ) ) + return false; + return !!src[ unrollSymbol ]; +} + +// + +function isEmpty( src ) +{ + if( !_.unroll.is( src ) ) + return false; + return src.length === 0; +} + +// + +/** + * The routine isPopulated() determines whether the unroll-array has elements (length). + * + * If {-src-} is an unroll-array and has one or more elements, then returns true, otherwise returns false. + * + * @param { * } src - The object to be checked. + * + * @example + * let src = _.unroll.from( [ 1, 'str' ] ); + * _.isPopulated( src ); + * // returns true + * + * @example + * let src = _.unroll.make( [] ) + * _.isPopulated( src ); + * // returns false + * + * @returns { boolean } Returns true if argument ( src ) is an Unroll and has one or more elements ( length ). + * @function isPopulated + * @namespace Tools/unroll + */ + +function isPopulated( src ) +{ + if( !_.unroll.is( src ) ) + return false; + return src.length > 0; +} + +// + +function like( src ) +{ + return _.unroll.is( src ); +} + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return true; +} + +// -- +// maker +// -- + +// function _makeEmpty( src ) +// { +// return _.unroll._make(); +// } +// +// // +// +// function makeEmpty( src ) +// { +// _.assert( arguments.length === 0 || arguments.length === 1 ); +// return _.unroll._makeEmpty( ... arguments ); +// } + +// + +/** + * The routine makeUndefined() returns a new Unroll with length equal to {-length-}. + * If the argument {-length-} is not provided, routine returns new Unroll with the length defined from {-src-}. + * + * @param { Long|Number|Null } src - Any Long, Number or null. If {-length-} is not provided, then routine defines length from {-src-}. + * @param { Number|Long|Null } length - Defines length of new Unroll. If null is provided, then length defines by {-src-}. + * + * @example + * _.unroll.makeUndefined(); + * // returns [] + * + * @example + * _.unroll.makeUndefined( null ); + * // returns [] + * + * @example + * _.unroll.makeUndefined( null, null ); + * // returns [] + * + * @example + * _.unroll.makeUndefined( 3 ); + * // returns [ undefined, undefined, undefined] + * + * @example + * _.unroll.makeUndefined( 3, null ); + * // returns [ undefined, undefined, undefined] + * + * @example + * _.unroll.makeUndefined( [ 1, 2, 3 ] ); + * // returns [ undefined, undefined, undefined ] + * + * @example + * _.unroll.makeUndefined( [ 1, 2, 3 ], null ); + * // returns [ undefined, undefined, undefined ] + * + * @example + * _.unroll.makeUndefined( [ 1, 2, 3 ], 4 ); + * // returns [ undefined, undefined, undefined, undefined ] + * + * @example + * _.unroll.makeUndefined( [ 1, 2, 3, 4 ], [ 1, 2 ] ); + * // returns [ undefined, undefined ] + * + * @example + * let src = new F32x( [ 1, 2, 3, 4, 5 ] ); + * let got = _.unroll.makeUndefined( src, 3 ); + * console.log( got ); + * // log [ undefined, undefined, undefined ] + * + * @returns { Unroll } Returns a new Unroll with length equal to {-length-} or defined from {-src-}. + * If null passed, routine returns the empty Unroll. + * @function makeUndefined + * @throws { Error } If arguments.length is less then one or more then two. + * @throws { Error } If argument {-src-} is not a Long, not null. + * @throws { Error } If argument {-length-} is not a number, not a Long. + * @namespace Tools/unroll + */ + +// function _makeUndefined( src, length ) +// { +// if( arguments.length === 0 ) +// return _.unroll._make(); +// +// if( _.longIs( length ) ) +// { +// length = length.length; +// } +// if( length === undefined || length === null ) +// { +// if( src === null ) +// { +// length = 0; +// } +// else if( _.longLike( src ) ) +// { +// length = src.length; +// } +// else if( _.number.is( src ) ) +// { +// length = src; +// src = null; +// } +// else _.assert( 0 ); +// } +// +// _.assert( _.number.isFinite( length ) ); +// _.assert( _.longIs( src ) || src === null ); +// +// return _.unroll._make( length ); +// } +// +// // +// +// function makeUndefined( src, length ) +// { +// _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); +// // _.assert( _.number.isFinite( length ) ); +// // _.assert( _.longIs( src ) || src === null ); +// return _.unroll._makeUndefined( ... arguments ); +// } + +// + +// function _makeFilling( type, value, length ) +// { +// if( arguments.length === 2 ) +// { +// value = arguments[ 0 ]; +// length = arguments[ 1 ]; +// } +// +// if( _.longIs( length ) ) +// length = length.length; +// +// let result = this._make( type, length ); +// for( let i = 0 ; i < length ; i++ ) +// result[ i ] = value; +// +// return result; +// } + +// + +/** + * The routine make() returns a new unroll-array maiden from {-src-}. + * + * Unroll constructed by attaching symbol _.unroll Symbol to ordinary array. Making an unroll normalizes its content. + * + * @param { Number|Long|Set|Null|Undefined } src - The number or other instance to make unroll-array. If null is provided, + * then routine returns an empty Unroll. + * + * @example + * let src = _.unroll.make(); + * // returns [] + * _.unrollIs( src ); + * // returns true + * + * @example + * let src = _.unroll.make( null ); + * // returns [] + * _.unrollIs( src ); + * // returns true + * + * @example + * let src = _.unroll.make( null, null ); + * // returns [] + * _.unrollIs( src ); + * // returns true + * + * @example + * let src = _.unroll.make( 3 ); + * // returns [ undefined, undefined, undefined ] + * _.unrollIs( src ); + * // returns true + * + * @example + * let src = _.unroll.make( [ 1, 2, 'str' ] ); + * // returns [ 1, 2, 'str' ] + * _.unrollIs( src ); + * // returns true + * + * @returns { Unroll } - Returns a new Unroll maiden from {-src-}. + * Otherwise, it returns the empty Unroll. + * @function make + * @throws { Error } If arguments.length is more then one. + * @throws { Error } If {-src-} is not a number, not a Long, not Set, not null, not undefined. + * @namespace Tools/unroll + */ + +function _make( src, length ) +{ + let result = _.array._make( ... arguments ); + result[ unrollSymbol ] = true; + if + ( + ( src !== null && src !== undefined && !_.unroll.is( src ) ) + || ( src !== null && src !== undefined && !_.unroll.is( src ) ) + ) + result = _.unroll.normalize( result ); + return result; + + // let result; + // result = _.array._make( ... arguments ); + // result[ unrollSymbol ] = true; + // if( src !== null && src !== undefined && !_.unroll.is( src ) ) + // result = _.unroll.normalize( result ); + // return result; +} + +// + +// function make( src, length ) +// { +// _.assert( arguments.length === 0 || src === null || _.countable.is( src ) || _.numberIs( src ) ); +// _.assert( length === undefined || !_.number.is( src ) || !_.number.is( length ) ); +// _.assert( arguments.length < 2 || _.number.is( length ) || _.countable.is( length ) ); +// _.assert( arguments.length <= 2 ); +// return this._make( ... arguments ); +// // _.assert( arguments.length === 0 || arguments.length === 1 ); +// // _.assert( arguments.length === 0 || src === null || _.number.is( src ) || _.countable.is( src ) ); +// // return _.unroll._make( src ); +// } + +// + +function _cloneShallow( src ) +{ + let result = _.array._cloneShallow( ... arguments ); + result[ unrollSymbol ] = true; + if( !_.unroll.is( src ) ) + result = _.unroll.normalize( result ); + return result; +} + +// + +// function cloneShallow( src ) +// { +// _.assert( arguments.length === 1 ); +// return _.unroll._cloneShallow( src ); +// } + +// + +/** + * The routine from() performs conversion of {-src-} to unroll-array. + * + * If {-src-} is not unroll-array, routine from() returns new unroll-array. + * If {-src-} is unroll-array, then routine returns {-src-}. + * + * @param { Long|Set|Number|Null|Undefined } src - The number, array-like object or Unroll. If null is provided, + * then routine returns an empty Unroll. + * + * @example + * let got = _.unroll.from( null ); + * // returns [] + * _.unrollIs( got ); + * // returns true + * + * @example + * let got = _.unroll.from( 3 ); + * // returns [ undefined, undefined, undefined ] + * _.unrollIs( got ); + * // returns true + * + * @example + * let got = _.unroll.from( [ 1, 2, 'str' ] ); + * // returns [ 1, 2, 'str' ] + * console.log( _.unrollIs( got ) ); + * // log true + * + * @example + * let got = _.unroll.from( new F32x( [ 1, 2, 0 ] ) ); + * // returns [ 1, 2, 0 ] + * console.log( _.unrollIs( got ) ); + * // log true + * + * @example + * let got = _.unroll.from( new Set( [ 1, 2, 'str' ] ) ); + * // returns [ 1, 2, 'str' ] + * console.log( _.unrollIs( got ) ); + * // log true + * + * @example + * let src = _.unroll.make( [ 1, 2, 'str' ] ); + * let got = _.unroll.from( src ); + * // returns [ 1, 2, 'str' ] + * console.log ( src === got ); + * // log true + * + * @returns { Unroll } Returns Unroll converted from {-src-}. If {-src-} is Unroll, then routine returns {-src-}. + * @function from + * @throws { Error } If arguments.length is less or more then one. + * @throws { Error } If argument {-src-} is not Long, not number, not Set, not null, not undefined. + * @namespace Tools/unroll + */ + +// function _from( src ) +// { +// if( _.unrollIs( src ) ) +// return src; +// return _.unroll._make( ... arguments ); +// } +// +// // +// +// function from( src ) +// { +// _.assert( arguments.length === 1 ); +// _.assert( src === null || _.number.is( src ) || _.countable.is( src ) ); +// return _.unroll._from( ... arguments ); +// } + +// + +function _as( src ) +{ + if( _.unrollIs( src ) ) + return src; + if( _.countable.is( src ) ) + return _.unroll._make( ... arguments ); + if( src === undefined ) + return _.unroll._make( [] ); + return _.unroll._make( [ src ] ); +} + +// + +function as( src ) +{ + _.assert( arguments.length === 1 ); + return _.unroll._as( ... arguments ); +} + +// + +/** + * The routine normalize() performs normalization of {-dstArray-}. + * Normalization is unrolling of Unrolls, which is elements of {-dstArray-}. + * + * If {-dstArray-} is unroll-array, routine normalize() returns unroll-array + * with normalized elements. + * If {-dstArray-} is array, routine normalize() returns array with unrolled elements. + * + * @param { Array|Unroll } dstArray - The Unroll to be unrolled (normalized). + * + * @example + * let unroll = _.unroll.from( [ 1, 2, _.unroll.make( [ 3, 'str' ] ) ] ); + * let result = _.unroll.normalize( unroll ) + * console.log( result ); + * // log [ 1, 2, 3, 'str' ] + * console.log( _.unrollIs( result ) ); + * // log true + * + * @example + * let unroll = _.unroll.from( [ 1,'str' ] ); + * let result = _.unroll.normalize( [ 1, unroll, [ unroll ] ] ); + * console.log( result ); + * // log [ 1, 1, 'str', [ 1, 'str' ] ] + * console.log( _.unrollIs( result ) ); + * // log false + * + * @returns { Array } If {-dstArray-} is array, routine returns an array with normalized elements. + * @returns { Unroll } If {-dstArray-} is Unroll, routine returns an Unroll with normalized elements. + * @function normalize + * @throws { Error } If ( arguments.length ) is not equal to one. + * @throws { Error } If argument ( dstArray ) is not arrayLike. + * @namespace Tools/unroll + */ + +function normalize( dstArray ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + + for( let a = 0 ; a < dstArray.length ; a++ ) + { + if( _.unrollIs( dstArray[ a ] ) ) + { + let args = [ a, 1 ]; + args.push.apply( args, dstArray[ a ] ); + dstArray.splice.apply( dstArray, args ); + a += args.length - 3; + /* no normalization of ready unrolls, them should be normal */ + } + else if( _.arrayIs( dstArray[ a ] ) ) + { + _.unroll.normalize( dstArray[ a ] ); + } + } + + return dstArray; +} + +// -- +// editor +// -- + +/** + * The routine prepend() returns an array with elements added to the begin of destination array {-dstArray-}. + * During the operation unrolling of Unrolls happens. + * + * If {-dstArray-} is unroll-array, routine prepend() returns unroll-array + * with normalized elements. + * If {-dstArray-} is array, routine prepend() returns array with unrolled elements. + * + * @param { Array|Unroll } dstArray - The destination array. + * @param { * } args - The elements to be added. + * + * @example + * let result = _.prepend( null, [ 1, 2, 'str' ] ); + * console.log( result ); + * // log [ [ 1, 2, 'str' ] ] + * console.log( _.unrollIs( result ) ); + * // log false + * + * @example + * let result = _.prepend( null, _.unroll.make( [ 1, 2, 'str' ] ) ); + * console.log( result ); + * // log [ 1, 2, 'str' ] + * console.log( _.unrollIs( result ) ); + * // log false + * + * @example + * let result = _.prepend( _.unroll.from( [ 1, 'str' ] ), [ 1, 2 ] ); + * console.log( result ); + * // log [ [ 1, 2 ], 1, 'str' ] + * console.log( _.unrollIs( result ) ); + * // log true + * + * @example + * let result = _.prepend( [ 1, 'str' ], _.unroll.from( [ 2, 3 ] ) ); + * console.log( result ); + * // log [ 2, 3, 1, 'str' ] + * console.log( _.unrollIs( result ) ); + * // log false + * + * @example + * let result = _.prepend( _.unroll.make( [ 1, 'str' ] ), _.unroll.from( [ 2, 3 ] ) ); + * console.log( result ); + * // log [ 2, 3, 1, 'str' ] + * console.log( _.unrollIs( result ) ); + * // log true + * + * @returns { Unroll } If {-dstArray-} is Unroll, routine returns updated Unroll + * with normalized elements that are added to the begin of {-dstArray-}. + * @returns { Array } If {-dstArray-} is array, routine returns updated array + * with normalized elements that are added to the begin of {-dstArray-}. + * If {-dstArray-} is null, routine returns empty array. + * @function prepend + * @throws { Error } An Error if {-dstArray-} is not an Array or not null. + * @throws { Error } An Error if ( arguments.length ) is less then one. + * @namespace Tools + */ + +function prepend( dstArray ) +{ + _.assert( arguments.length >= 1 ); + _.assert( _.longIs( dstArray ) || dstArray === null, 'Expects long or unroll' ); + + dstArray = dstArray || []; + + _prepend( dstArray, Array.prototype.slice.call( arguments, 1 ) ); + + return dstArray; + + function _prepend( dstArray, srcArray ) + { + + for( let a = srcArray.length - 1 ; a >= 0 ; a-- ) + { + if( _.unrollIs( srcArray[ a ] ) ) + { + _prepend( dstArray, srcArray[ a ] ); + } + else + { + if( _.arrayIs( srcArray[ a ] ) ) + _.unroll.normalize( srcArray[ a ] ) + dstArray.unshift( srcArray[ a ] ); + } + } + + return dstArray; + } + +} + +// + +/** + * The routine append() returns an array with elements added to the end of destination array {-dstArray-}. + * During the operation unrolling of Unrolls happens. + * + * If {-dstArray-} is unroll-array, routine append() returns unroll-array + * with normalized elements. + * If {-dstArray-} is array, routine append() returns array with unrolled elements. + * + * @param { Array|Unroll } dstArray - The destination array. + * @param { * } args - The elements to be added. + * + * @example + * let result = _.append( null, [ 1, 2, 'str' ] ); + * console.log( result ); + * // log [ [ 1, 2, 'str' ] ] + * console.log( _.unrollIs( result ) ); + * // log false + * + * @example + * let result = _.append( null, _.unroll.make( [ 1, 2, 'str' ] ) ); + * console.log( result ); + * // log [ 1, 2, str ] + * console.log( _.unrollIs( result ) ); + * // log false + * + * @example + * let result = _.append( _.unroll.from( [ 1, 'str' ] ), [ 1, 2 ] ); + * console.log( result ); + * // log [ 1, 'str', [ 1, 2 ] ] + * console.log( _.unrollIs( result ) ); + * // log true + * + * @example + * let result = _.append( [ 1, 'str' ], _.unroll.from( [ 2, 3 ] ) ); + * console.log( result ); + * // log [ 1, 'str', 2, 3 ] + * console.log( _.unrollIs( result ) ); + * // log false + * + * @example + * let result = _.append( _.unroll.make( [ 1, 'str' ] ), _.unroll.from( [ 2, 3 ] ) ); + * console.log( result ); + * // log [ 1, 'str', 2, 3 ] + * console.log( _.unrollIs( result ) ); + * // log true + * + * @returns { Unroll } If {-dstArray-} is Unroll, routine returns updated Unroll + * with normalized elements that are added to the end of {-dstArray-}. + * @returns { Array } If {-dstArray-} is array, routine returns updated array + * with normalized elements that are added to the end of {-dstArray-}. + * If {-dstArray-} is null, routine returns empty array. + * @function append + * @throws { Error } An Error if {-dstArray-} is not an Array or not null. + * @throws { Error } An Error if ( arguments.length ) is less then one. + * @namespace Tools + */ + +function append( dstArray ) +{ + _.assert( arguments.length >= 1 ); + _.assert( _.longIs( dstArray ) || dstArray === null, 'Expects long or unroll' ); + + dstArray = dstArray || []; + + _append( dstArray, Array.prototype.slice.call( arguments, 1 ) ); + + return dstArray; + + function _append( dstArray, srcArray ) + { + _.assert( arguments.length === 2 ); + + for( let a = 0, len = srcArray.length ; a < len; a++ ) + { + if( _.unrollIs( srcArray[ a ] ) ) + { + _append( dstArray, srcArray[ a ] ); + } + else + { + if( _.arrayIs( srcArray[ a ] ) ) + _.unroll.normalize( srcArray[ a ] ) + dstArray.push( srcArray[ a ] ); + } + } + + return dstArray; + } + +} + +// + +/** + * The routine remove() removes all matching elements in destination array {-dstArray-} + * and returns a modified {-dstArray-}. During the operation unrolling of Unrolls happens. + * + * @param { Array|Unroll } dstArray - The destination array. + * @param { * } args - The elements to be removed. + * + * @example + * let result = _.remove( null, [ 1, 2, 'str' ] ); + * console.log( result ); + * // log [] + * console.log( _.unrollIs( result ) ); + * // log false + * + * @example + * let result = _.remove( _.unroll.make( null ), [ 1, 2, 'str' ] ); + * console.log( result ); + * // log [] + * console.log( _.unrollIs( result ) ); + * // log true + * + * @example + * let result = _.remove( [ 1, 2, 1, 3, 'str' ], [ 1, 'str', 0, 5 ] ); + * console.log( result ); + * // log [ 1, 2, 1, 3, 'str' ] + * console.log( _.unrollIs( result ) ); + * // log false + * + * @example + * let result = _.remove( [ 1, 2, 1, 3, 'str' ], _.unroll.from( [ 1, 'str', 0, 5 ] ) ); + * console.log( result ); + * // log [ 2, 3 ] + * console.log( _.unrollIs( result ) ); + * // log false + * + * @example + * let result = _.remove( _.unroll.from( [ 1, 2, 1, 3, 'str' ] ), [ 1, 'str', 0, 5 ] ); + * console.log( result ); + * // log [ 1, 2, 1, 3, 'str' ] + * console.log( _.unrollIs( result ) ); + * // log true + * + * @example + * let dstArray = _.unroll.from( [ 1, 2, 1, 3, 'str' ] ); + * let ins = _.unroll.from( [ 1, 'str', 0, 5 ] ); + * let result = _.remove( dstArray, ins ); + * console.log( result ); + * // log [ 2, 3 ] + * console.log( _.unrollIs( result ) ); + * // log false + * + * @example + * let dstArray = _.unroll.from( [ 1, 2, 1, 3, 'str' ] ); + * let ins = _.unroll.from( [ 1, _.unroll.make( [ 'str', 0, 5 ] ) ] ); + * let result = _.remove( dstArray, ins ); + * console.log( result ); + * // log [ 2, 3 ] + * console.log( _.unrollIs( result ) ); + * // log false + * + * @returns { Unroll } If {-dstArray-} is Unroll, routine removes all matching elements + * and returns updated Unroll. + * @returns { Array } If {-dstArray-} is array, routine removes all matching elements + * and returns updated array. If {-dstArray-} is null, routine returns empty array. + * @function append + * @throws { Error } An Error if {-dstArray-} is not an Array or not null. + * @throws { Error } An Error if ( arguments.length ) is less then one. + * @namespace Tools + */ + +function remove( dstArray ) +{ + _.assert( arguments.length >= 2 ); + _.assert( _.longIs( dstArray ) || dstArray === null, 'Expects long or unroll' ); + + dstArray = dstArray || []; + + _remove( dstArray, Array.prototype.slice.call( arguments, 1 ) ); + + return dstArray; + + function _remove( dstArray, srcArray ) + { + _.assert( arguments.length === 2 ); + + for( let a = 0, len = srcArray.length ; a < len; a++ ) + { + if( _.unrollIs( srcArray[ a ] ) ) + { + _remove( dstArray, srcArray[ a ] ); + } + else + { + if( _.arrayIs( srcArray[ a ] ) ) + _.unroll.normalize( srcArray[ a ] ); + while( dstArray.indexOf( srcArray[ a ] ) >= 0 ) + dstArray.splice( dstArray.indexOf( srcArray[ a ] ), 1 ); + } + } + + return dstArray; + } + +} + +// -- +// declaration +// -- + +let unrollSymbol = Symbol.for( 'unroll' ); + +// -- +// declaration +// -- + +let ToolsExtension = +{ + + // dichotomy + + unrollIs : is.bind( _.unroll ), + unrollIsEmpty : isEmpty.bind( _.unroll ), + unrollIsPopulated : isPopulated.bind( _.unroll ), + unrollLike : like.bind( _.unroll ), + + // maker + + unrollMakeEmpty : _.argumentsArray.makeEmpty.bind( _.unroll ), + // unrollMakeEmpty : makeEmpty.bind( _.unroll ), + unrollMakeUndefined : _.argumentsArray.makeUndefined.bind( _.unroll ), + // unrollMakeUndefined : makeUndefined.bind( _.unroll ), + unrollMake : _.argumentsArray.make.bind( _.unroll ), + // unrollMake : make.bind( _.unroll ), + unrollCloneShallow : _.argumentsArray.cloneShallow.bind( _.unroll ), + // unrollCloneShallow : cloneShallow.bind( _.unroll ), + unrollFrom : _.argumentsArray.from.bind( _.unroll ), + // unrollFrom : from.bind( _.unroll ), + + // editor + + unrollPrepend : prepend.bind( _.unroll ), + unrollAppend : append.bind( _.unroll ), + unrollRemove : remove.bind( _.unroll ), + +} + +// + +Object.assign( _, ToolsExtension ); + +// + +/* qqq : for junior : make replacements */ + +let UnrollExtension = +{ + + // + + NamespaceName : 'unroll', + NamespaceNames : [ 'unroll' ], + NamespaceQname : 'wTools/unroll', + MoreGeneralNamespaceName : 'long', + MostGeneralNamespaceName : 'countable', + TypeName : 'Unroll', + TypeNames : [ 'Unroll' ], + // SecondTypeName : 'Unroll', + InstanceConstructor : null, + tools : _, + symbol : unrollSymbol, + + // dichotomy + + is, + isEmpty, + isPopulated, + like, + IsResizable, + + // maker + + _makeEmpty : _.argumentsArray._makeEmpty, + makeEmpty : _.argumentsArray.makeEmpty, /* qqq : for junior : cover */ + _makeUndefined : _.argumentsArray._makeUndefined, + makeUndefined : _.argumentsArray.makeUndefined, /* qqq : for junior : cover */ + _makeZeroed : _.argumentsArray._makeZeroed, + makeZeroed : _.argumentsArray.makeZeroed, /* qqq : for junior : cover */ + _makeFilling : _.argumentsArray._makeFilling, + makeFilling : _.argumentsArray.makeFilling, + _make, + make : _.argumentsArray.make, /* qqq : for junior : cover */ + // make, /* qqq : for junior : cover */ + _cloneShallow, + cloneShallow : _.argumentsArray.cloneShallow, /* qqq : for junior : cover */ + // _from, + from : _.argumentsArray.from, + _as, + as, + normalize, + + // editor + + prepend, + append, + remove, + + // meta + + namespaceOf : _.blank.namespaceOf, + namespaceWithDefaultOf : _.blank.namespaceWithDefaultOf, + _functor_functor : _.blank._functor_functor, + +} + +// + +Object.assign( _.unroll, UnrollExtension ); +_.long._namespaceRegister( _.unroll ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Unroll.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Unroll_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Unroll_s */ })(); + +/* */ /* begin of file Vector_s */ ( function Vector_s() { function Vector_s_naked() { ( function _l1_Vector_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.vector = _.vector || Object.create( null ); + +_.assert( !!_.long.make, 'Expects routine _.long.make' ); + +// -- +// implementation +// -- + +function is( src ) +{ + + if( _.arrayIs( src ) ) + return true; + if( _.primitive.is( src ) ) + return false; + + if( _.class.methodIteratorOf( src ) ) + if( _.number.is( src.length ) ) /* yyy */ + if( !_.mapIs( src ) ) + return true; + + return false; +} + +// + +function like( src ) +{ + return _.vector.is( src ); +} + +// + +function IsResizable() +{ + _.assert( arguments.length === 0 ); + return this.default.IsResizable(); +} + +// -- +// meta +// -- + +/* qqq : optimize */ +function namespaceOf( src ) +{ + if( !this.is( src ) ) + return null; + + let result = _.long.namespaceOf( src ); + if( result ) + return result; + + return this; +} + +// -- +// extension +// -- + +var ToolsExtension = +{ + + vectorIs : is.bind( _.vector ), + vectorLike : like.bind( _.vector ), + +} + +Object.assign( _, ToolsExtension ); + +// + +var VectorExtension = +{ + + // + + NamespaceName : 'vector', + NamespaceNames : [ 'vector' ], + NamespaceQname : 'wTools/vector', + MoreGeneralNamespaceName : 'countable', + MostGeneralNamespaceName : 'countable', + TypeName : 'Vector', + TypeNames : [ 'Vector' ], + // SecondTypeName : 'Vector', + InstanceConstructor : null, + tools : _, + + // dichotomy + + is, /* qqq : cover here and in the module::MathVector */ + like, /* qqq : cover here and in the module::MathVector */ + IsResizable, + + // maker + + _makeEmpty : _.countable._makeEmpty, + makeEmpty : _.countable.makeEmpty, /* qqq : for junior : cover */ + _makeUndefined : _.countable._makeUndefined, + makeUndefined : _.countable.makeUndefined, /* qqq : for junior : cover */ + _makeZeroed : _.countable._makeZeroed, + makeZeroed : _.countable.makeZeroed, /* qqq : for junior : cover */ + _make : _.countable._make, + make : _.countable.make, /* qqq : for junior : cover */ + _cloneShallow : _.countable._cloneShallow, + cloneShallow : _.countable.cloneShallow, /* qqq : for junior : cover */ + from : _.countable.from, /* qqq : for junior : cover */ + + // meta + + namespaceOf, + namespaceWithDefaultOf : _.props.namespaceWithDefaultOf, + _functor_functor : _.props._functor_functor, + +} + +Object.assign( _.vector, VectorExtension ); + +// + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Vector.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Vector_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Vector_s */ })(); + +/* */ /* begin of file Wrap_s */ ( function Wrap_s() { function Wrap_s_naked() { ( function _l1_Wrap_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.wrap = _.wrap || Object.create( null ); + +// -- +// implement +// -- + +// -- +// declare +// -- + +var Extension = +{ +} + +// + +Object.assign( _.wrap, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/Wrap.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Wrap_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Wrap_s */ })(); + +/* */ /* begin of file zErr_s */ ( function zErr_s() { function zErr_s_naked() { ( function _l1_1Err_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _global_.wTools; + +_.error = _.error || Object.create( null ); + +// -- +// dichotomy +// -- + +function is( src ) +{ + return src instanceof Error || Object.prototype.toString.call( src ) === '[object Error]'; +} + +// + +function isFormed( src ) +{ + if( !_.error.is( src ) ) + return false; + return src.originalMessage !== undefined; +} + +// + +function isAttended( src ) +{ + if( !_.error.is( src ) ) + return false; + return !!src.attended; +} + +// + +function isLogged( src ) +{ + if( _.error.is( src ) === false ) + return false; + return !!src.logged; +} + +// + +function isSuspended( src ) +{ + if( _.error.is( src ) === false ) + return false; + return !!src.suspended; +} + +// + +function isWary( src ) +{ + if( _.error.is( src ) === false ) + return false; + return !!src.wary; +} + +// + +function isBrief( src ) +{ + if( !_.error.is( src ) ) + return false; + return !!src.brief; +} + + +// -- +// generator +// -- + +function _sectionsJoin( o ) +{ + o.message = o.message || ''; + + // _.map.assertHasAll( o, _sectionsJoin.defaults ); + + if( Config.debug ) + for( let k in _sectionsJoin.defaults ) + { + if( o[ k ] === undefined ) + throw Error( `Expects defined option::${k}` ); + } + + for( let s in o.sections ) + { + let section = o.sections[ s ]; + let head = section.head || ''; + let body = strLinesIndentation( section.body, ' ' ); + if( !body.trim().length ) + continue; + o.message += ` = ${head}\n${body}\n\n`; + } + + return o.message; + + function strLinesIndentation( str, indentation ) + { + if( _.strLinesIndentation ) + return indentation + _.strLinesIndentation( str, indentation ); + else + return str; + } + +} + +_sectionsJoin.defaults = +{ + sections : null, + message : '', +} + +// + +function _messageForm( o ) +{ + + o.message = o.message || ''; + + if( !_.strIs( o.originalMessage ) ) + throw 'Expects string {- o.originalMessage -}'; + + // _.map.assertHasAll( o, _messageForm.defaults ); + + if( Config.debug ) + for( let k in _messageForm.defaults ) + { + if( o[ k ] === undefined ) + throw Error( `Expects defined option::${k}` ); + } + + if( o.brief ) + { + o.message += o.originalMessage; + } + else + { + o.message = _.error._sectionsJoin( o ); + } + + if( o.error ) + nonenumerable( 'message', o.message ); + + return o.message; + + /* */ + + function nonenumerable( propName, value ) + { + try + { + let o2 = + { + enumerable : false, + configurable : true, + writable : true, + value, + }; + Object.defineProperty( o.error, propName, o2 ); + } + catch( err2 ) + { + console.error( err2 ); + } + } + +} + +_messageForm.defaults = +{ + error : null, + sections : null, + brief : false, + message : '', +} + +// + +/* qqq : cover please */ +function sectionRemove( error, name ) +{ + + _.assert( arguments.length === 2 ); + _.assert( !!error ); + _.assert( _.strDefined( name ) ); + + if( !_.error.isFormed( error ) ) + error = _.err( error ); + + delete eror.sections[ name ]; + + let o2 = Object.create( null ); + o2.error = error; + o2.sections = error.sections; + o2.brief = error.brief; + o2.message = ''; + o2.originalMessage = error.originalMessage; + _.error._messageForm( o2 ); + + return error; +} + +// + +function sectionAdd( o ) +{ + + if( arguments.length === 2 ) + { + o = arguments[ 1 ]; + o.error = arguments[ 0 ]; + } + + _.routine.options( sectionAdd, o ); /* qqq : eliminate such routines here */ + if( o.head === null ) + o.head = o.name.substring( 0, 1 ).toUpperCase() + o.name.substring( 1 ); + + _.assert( _.strDefined( o.name ) ); /* qqq : eliminate such routines here */ + _.assert( _.strDefined( o.head ) ); + _.assert( _.strDefined( o.body ) ); + _.assert( !!o.error ); + + if( !_.error.isFormed( o.error ) ) + { + o.error = _._err({ args : [ o.error ], sections : { [ o.name ] : { head : o.head, body : o.body } } }); + return o.error; + } + + o.sections = o.error.sections; + _.error._sectionAdd( o ); + + o.brief = o.error.brief; + o.message = ''; + o.originalMessage = o.error.originalMessage; + _.error._messageForm( o ); + + return o.error; +} + +sectionAdd.defaults = +{ + error : null, + name : null, + head : null, + body : null, +} + +// + +function _sectionAdd( o ) +{ + + if( Config.debug ) + for( let k in _sectionAdd.defaults ) + { + if( o[ k ] === undefined ) + throw Error( `Expects defined option::${k}` ); + } + + let section = Object.create( null ); + section.name = o.name; + section.head = o.head; + section.body = o.body; + o.sections[ o.name ] = section; + return section; +} + +_sectionAdd.defaults = +{ + sections : null, + name : null, + head : null, + body : null, +} + +// + +function _sectionExposedAdd( o ) +{ + const exportString = _.entity.exportString ? _.entity.exportString.bind( _.entity ) : String; + + if( Config.debug ) + for( let k in _sectionExposedAdd.defaults ) + { + if( o[ k ] === undefined ) + throw Error( `Expects defined option::${k}` ); + } + + let i = 0; + let body = ''; + for( let k in o.exposed ) + { + if( i > 0 ) + body += `\n`; + body += `${k} : ${exportString( o.exposed[ k ] )}`; + i += 1; + } + + _.error._sectionAdd + ({ + sections : o.sections, + name : 'exposed', + head : 'Exposed', + body, + }); +} + +_sectionExposedAdd.defaults = +{ + sections : null, + exposed : null, +} + +// + +function exposedSet( args, props ) +{ + + _.assert( arguments.length === 2 ); + _.assert( _.mapIs( props ) ) + + if( !_.longIs( args ) ) + args = [ args ]; + + let err = args[ 0 ]; + + if( _.symbol.is( err ) ) + { + _.assert( args.length === 1 ); + return err; + } + + if( args.length !== 1 || !_.error.isFormed( err ) ) + err = _._err + ({ + args, + level : 2, + }); + + /* */ + + try + { + + for( let f in props ) + { + err[ f ] = props[ f ]; + } + + } + catch( err ) + { + if( Config.debug ) + console.error( `Cant assign "${f}" property to error\n${err.toString()}` ); + } + + /* */ + + return err; +} + +// + +function concealedSet( args, props ) +{ + + _.assert( arguments.length === 2 ); + _.assert( _.mapIs( props ) ) + + if( !_.longIs( args ) ) + args = [ args ]; + + let err = args[ 0 ]; + + if( _.symbol.is( err ) ) + { + _.assert( args.length === 1 ); + return err; + } + + if( args.length !== 1 || !_.error.isFormed( err ) ) + err = _._err + ({ + args, + level : 2, + }); + + /* */ + + try + { + + for( let f in props ) + { + let o = + { + enumerable : false, + configurable : true, + writable : true, + value : props[ f ], + }; + Object.defineProperty( err, f, o ); + } + + } + catch( err ) + { + if( Config.debug ) + console.error( `Cant assign "${f}" property to error\n${err.toString()}` ); + } + + /* */ + + return err; +} + +// + +function _inStr( errStr ) +{ + _.assert( _.strIs( errStr ) ); + + if( !_.strHas( errStr, /\=\s+Message of/m ) ) + return false; + + if( !_.strHas( errStr, /(^|\n)\s*=\s+Beautified calls stack/m ) ) + return false; + + return true; +} + +// -- +// introductor +// -- + +function _make( o ) +{ + const logger = _global_.logger || _global_.console; + + if( arguments.length !== 1 ) + throw Error( 'Expects single argument : options map' ); + + if( !_.mapIs( o ) ) + throw Error( 'Expects single argument : options map' ); + + for( let k in o ) + { + if( _make.defaults[ k ] === undefined ) + throw Error( `Unknown option::${k}` ); + } + + for( let k in _.error._make.defaults ) + { + if( o[ k ] === undefined ) + o[ k ] = _.error._make.defaults[ k ]; + } + + if( !_.error.is( o.error ) ) + throw Error( 'Expects option.error:Error' ); + + if( !_.strIs( o.originalMessage ) ) + throw Error( 'Expects option.originalMessage:String' ); + + if( !_.strIs( o.combinedStack ) ) + throw Error( 'Expects option.combinedStack:String' ); + + if( !_.strIs( o.throwCallsStack ) ) + throw Error( 'Expects option.throwCallsStack:String' ); + + if( !_.strIs( o.throwsStack ) ) + throw Error( 'Expects option.throwsStack:String' ); + + if( !o.throwLocation ) + throw Error( 'Expects option.throwLocation:Location' ); + + attributesForm(); + exposedForm(); + sectionsForm(); + _.error._messageForm( o ); + form(); + + return o.error; + + /* */ + + function attributesForm() + { + + if( o.attended === null || o.attended === undefined ) + o.attended = o.error.attended; + o.attended = !!o.attended; + + if( o.logged === null || o.logged === undefined ) + o.logged = o.error.logged; + o.logged = !!o.logged; + + if( o.brief === null || o.brief === undefined ) + o.brief = o.error.brief; + o.brief = !!o.brief; + + if( o.reason === null || o.reason === undefined ) + o.reason = o.error.reason; + + o.sections = o.sections || Object.create( null ); + if( o.error.section ) + _.props.supplement( o.sections, o.error.section ); + + o.id = o.error.id; + if( !o.id ) + { + _.error._errorCounter += 1; + o.id = _.error._errorCounter; + } + + } + + /* */ + + function exposedForm() + { + var has = false; + for( let k in o.error ) + { + has = true; + break; + } + if( has ) + { + if( o.exposed ) + { + for( let k in o.error ) + if( !Reflect.has( o.exposed, k ) ) + o.exposed[ k ] = o.error[ k ]; + } + else + { + o.exposed = Object.create( null ); + for( let k in o.error ) + o.exposed[ k ] = o.error[ k ]; + } + } + } + + /* */ + + function sectionsForm() + { + let result = ''; + + // sectionAdd( 'message', `Message of Error#${o.id}`, o.originalMessage ); + sectionAdd( 'message', `Message of ${o.error.name || 'error'}#${o.id}`, o.originalMessage ); + sectionAdd( 'combinedStack', o.stackCondensing ? 'Beautified calls stack' : 'Calls stack', o.combinedStack ); + sectionAdd( 'throwsStack', `Throws stack`, o.throwsStack ); + + /* xxx : postpone */ + if( o.sourceCode ) + if( _.strIs( o.sourceCode ) ) + sectionAdd( 'sourceCode', `Source code`, o.sourceCode ); + else if( _.routine.is( o.sourceCode.read ) ) + sectionAdd( 'sourceCode', `Source code from ${o.sourceCode.path}`, o.sourceCode.read ); + else if( _.strIs( o.sourceCode.code ) ) + sectionAdd( 'sourceCode', `Source code from ${o.sourceCode.path}`, o.sourceCode.code ); + else + console.error( 'Unknown format of {- o.sourceCode -}' ); + + if( o.exposed && Object.keys( o.exposed ).length > 0 ) + _.error._sectionExposedAdd( o ); + + for( let s in o.sections ) + { + let section = o.sections[ s ]; + if( !_.strIs( section.head ) ) + { + logger.error + ( + `Each section of an error should have head, but head of section::${s} is ${_.entity.strType(section.head)}` + ); + delete o.sections[ s ]; + } + if( !_.strIs( section.body ) ) + { + logger.error + ( + `Each section of an error should have body, but body of section::${s} is ${_.entity.strType(section.body)}` + ); + delete o.sections[ s ]; + } + } + + return result; + } + + /* */ + + function sectionAdd( name, head, body ) + { + _.error._sectionAdd({ name, head, body, sections : o.sections }); + } + + /* */ + + function form() + { + + nonenumerable( 'originalMessage', o.originalMessage ); + logging( 'stack' ); + nonenumerable( 'reason', o.reason ); + + nonenumerable( 'combinedStack', o.combinedStack ); + nonenumerable( 'throwCallsStack', o.throwCallsStack ); + nonenumerable( 'asyncCallsStack', o.asyncCallsStack ); + nonenumerable( 'throwsStack', o.throwsStack ); + nonenumerable( 'catchCounter', o.error.catchCounter ? o.error.catchCounter+1 : 1 ); + + nonenumerable( 'attended', o.attended ); + nonenumerable( 'logged', o.logged ); + nonenumerable( 'brief', o.brief ); + + if( o.throwLocation.line !== undefined ) + nonenumerable( 'lineNumber', o.throwLocation.line ); + if( o.error.throwLocation === undefined ) + nonenumerable( 'location', o.throwLocation ); + nonenumerable( 'sourceCode', o.sourceCode || null ); + nonenumerable( 'id', o.id ); + + nonenumerable( 'toString', function() { return this.stack } ); + nonenumerable( 'sections', o.sections ); + + getter( 'name', function() { return this.constructor.name } ); + + o.error[ Symbol.for( 'nodejs.util.inspect.custom' ) ] = o.error.toString; + + if( o.concealed ) + { + for( let k in o.concealed ) + nonenumerable( k, o.concealed[ k ] ); + } + + } + + /* */ + + function nonenumerable( propName, value ) + { + try + { + let o2 = + { + enumerable : false, + configurable : true, + writable : true, + value, + }; + Object.defineProperty( o.error, propName, o2 ); + } + catch( err2 ) + { + console.error( err2 ); + } + } + + /* */ + + function getter( propName, get ) + { + try + { + let o2 = + { + enumerable : false, + configurable : true, + get, + }; + Object.defineProperty( o.error, propName, o2 ); + } + catch( err2 ) + { + console.error( err2 ); + } + } + + /* */ + + function logging( propName ) + { + try + { + let o2 = + { + enumerable : false, + configurable : true, + get, + set, + }; + Object.defineProperty( o.error, propName, o2 ); + } + catch( err2 ) + { + console.error( err2 ); + } + function get() + { + /* + workaround to avoid Njs issue: Njs stingify inherited error + */ + /* zzz : qqq : find better solution */ + if( ( new Error().stack ).split( '\n' ).length !== 3 ) + { + _.error.logged( this ); + _.error.attend( this ); + } + return this.message; + } + function set( src ) + { + this.message = src; + return src; + } + } + +} + +_make.defaults = +{ + + error : null, + id : null, + throwLocation : null, + sections : null, /* qqq : cover please */ + concealed : null, /* qqq : cover please */ + exposed : null, + + attended : null, + logged : null, + brief : null, + stackCondensing : null, + + originalMessage : null, + combinedStack : '', + throwCallsStack : '', + throwsStack : '', + asyncCallsStack : '', + sourceCode : null, + reason : null, + +} + +// + +/** + * Creates Error object based on passed options. + * Result error contains in message detailed stack trace and error description. + * @param {Object} o Options for creating error. + * @param {String[]|Error[]} o.args array with messages or errors objects, from which will be created Error obj. + * @param {number} [o.level] using for specifying in error message on which level of stack trace was caught error. + * @returns {Error} Result Error. If in `o.args` passed Error object, result will be reference to it. + * @private + * @throws {Error} Expects single argument if pass les or more than one argument + * @throws {Error} o.args should be array like, if o.args is not array. + * @function _err + * @namespace Tools + */ + +function _err( o ) +{ + const exportString = _.entity.exportString ? _.entity.exportString.bind( _.entity ) : String; + let error; + + if( arguments.length !== 1 ) + throw Error( '_err : Expects single argument : options map' ); + + if( !_.mapIs( o ) ) + throw Error( '_err : Expects single argument : options map' ); + + if( !_.longIs( o.args ) ) + throw Error( '_err : Expects Long option::args' ); + + for( let e in o ) + { + if( _err.defaults[ e ] === undefined ) + { + debugger; + throw Error( `Unknown option::${e}` ); + } + } + + for( let e in _err.defaults ) + { + if( o[ e ] === undefined ) + o[ e ] = _err.defaults[ e ]; + } + + if( _.error._errorMaking ) + { + throw Error( 'Recursive dead lock because of error inside of routine _err()!' ); + } + _.error._errorMaking = true; + + if( o.level === undefined || o.level === null ) + o.level = null; + + /* let */ + + if( !o.message ) + o.message = ''; + let fallBackMessage = ''; + let errors = []; + let combinedStack = ''; + + /* algorithm */ + + try + { + + argumentsPreprocessArguments(); + argumentsPreprocessErrors(); + locationForm(); + stackAndErrorForm(); + attributesForm(); + catchesForm(); + sourceCodeForm(); + originalMessageForm(); + + error = _.error._make + ({ + error, + throwLocation : o.throwLocation, + sections : o.sections, + concealed : o.concealed, + exposed : o.exposed, + + attended : o.attended, + logged : o.logged, + brief : o.brief, + stackCondensing : o.stackCondensing, + + originalMessage : o.message, + combinedStack, + throwCallsStack : o.throwCallsStack, + throwsStack : o.throwsStack, + asyncCallsStack : o.asyncCallsStack, + sourceCode : o.sourceCode, + reason : o.reason, + }); + + } + catch( err2 ) + { + _.error._errorMaking = false; + console.log( err2.message ); + console.log( err2.stack ); + } + _.error._errorMaking = false; + + return error; + + /* */ + + function argumentsPreprocessArguments() + { + + for( let a = 0 ; a < o.args.length ; a++ ) + { + let arg = o.args[ a ]; + + if( !_.error.is( arg ) && _.routine.is( arg ) ) + { + if( arg.length === 0 ) + { + try + { + arg = o.args[ a ] = arg(); + } + catch( err ) + { + let original = arg; + arg = o.args[ a ] = 'Error throwen by callback for formatting of error string'; + console.error( String( err ) ); + if( _.strLinesSelect ) /* aaa : for Dmytro : make sure it works and cover */ /* Dmytro : works, covered. Test routine `_errWithArgsIncludedRoutine` */ + console.error( _.strLinesSelect + ({ + src : original.toString(), + line : 0, + nearestLines : 5, + numbering : 1, + })); + else + console.error( original.toString() ); + } + } + if( _.unrollIs( arg ) ) + { + debugger; + o.args = [ ... Array.prototype.slice.call( o.args, 0, a ), ... arg, ... Array.prototype.slice.call( o.args, a+1, o.args.length ) ]; + // o.args = _.longBut_( null, o.args, [ a, a ], arg ); + // o.args = _.longBut( o.args, [ a, a+1 ], arg ); + a -= 1; + continue; + } + } + + } + + } + + /* */ + + function argumentsPreprocessErrors() + { + + for( let a = 0 ; a < o.args.length ; a++ ) + { + let arg = o.args[ a ]; + + if( _.error.is( arg ) ) + { + + errProcess( arg ); + o.args[ a ] = _.error.originalMessage( arg ) + + } + else if( _.strIs( arg ) && _.error._inStr( arg ) ) + { + + let err = _.error.fromStr( arg ); + errProcess( err ); + o.args[ a ] = _.error.originalMessage( err ); + + } + + } + + } + + /* */ + + function errProcess( arg ) + { + + if( !error ) + { + error = arg; + if( !o.sourceCode ) + o.sourceCode = arg.sourceCode || null; + if( o.attended === null ) + o.attended = arg.attended || false; + if( o.logged === null ) + o.logged = arg.logged || false; + } + + if( arg.throwCallsStack ) + if( !o.throwCallsStack ) + o.throwCallsStack = arg.throwCallsStack; + + // if( arg.asyncCallsStack ) + // if( !o.asyncCallsStack ) + // o.asyncCallsStack = arg.asyncCallsStack; + + if( arg.throwsStack ) + if( o.throwsStack ) + o.throwsStack += '\n' + arg.throwsStack; + else + o.throwsStack = arg.throwsStack; + + if( arg.constructor ) + fallBackMessage = fallBackMessage || arg.constructor.name; + errors.push( arg ); + + } + + /* */ + + function locationForm() + { + + if( !error ) + for( let a = 0 ; a < o.args.length ; a++ ) + { + let arg = o.args[ a ]; + if( !_.primitive.is( arg ) && _.object.like( arg ) ) + try + { + o.throwLocation = _.introspector.location + ({ + error : arg, + location : o.throwLocation, + }); + } + catch( err2 ) + { + console.error( err2 ); + } + } + + o.throwLocation = o.throwLocation || Object.create( null ); + o.catchLocation = o.catchLocation || Object.create( null ); + + } + + /* */ + + function stackAndErrorForm() + { + + if( error ) + { + + /* qqq : cover each if-branch. ask how to. *difficult problem* */ + + if( !o.throwCallsStack ) + if( o.throwLocation ) + o.throwCallsStack = _.introspector.locationToStack( o.throwLocation ); + if( !o.throwCallsStack ) + o.throwCallsStack = _.error.originalStack( error ); + if( !o.throwCallsStack ) + o.throwCallsStack = _.introspector.stack([ ( o.level || 0 ) + 1, Infinity ]); + + if( !o.catchCallsStack && o.catchLocation ) + o.catchCallsStack = _.introspector.locationToStack( o.catchLocation ); + if( !o.catchCallsStack ) + o.catchCallsStack = _.introspector.stack( o.catchCallsStack, [ ( o.level || 0 ) + 1, Infinity ] ); + + if( !o.throwCallsStack && o.catchCallsStack ) + o.throwCallsStack = o.catchCallsStack; + if( !o.throwCallsStack ) + o.throwCallsStack = _.introspector.stack( error, [ ( o.level || 0 ) + 1, Infinity ] ); + + o.level = 0; + + } + else + { + + error = new Error( o.message + '\n' ); + if( o.throwCallsStack ) + { + error.stack = o.throwCallsStack; + o.catchCallsStack = _.introspector.stack( o.catchCallsStack, [ o.level + 1, Infinity ] ); + o.level = 0; + } + else + { + if( o.catchCallsStack ) + { + o.throwCallsStack = error.stack = o.catchCallsStack; + } + else + { + if( o.level === undefined || o.level === null ) + o.level = 1; + o.level += 1; + o.throwCallsStack = error.stack = _.introspector.stack( error.stack, [ o.level, Infinity ] ); + } + o.level = 0; + if( !o.catchCallsStack ) + o.catchCallsStack = o.throwCallsStack; + } + + } + + _.assert( o.level === 0 ); + + if( ( o.stackRemovingBeginIncluding || o.stackRemovingBeginExcluding ) && o.throwCallsStack ) + o.throwCallsStack = _.introspector.stackRemoveLeft + ( + o.throwCallsStack, o.stackRemovingBeginIncluding || null, o.stackRemovingBeginExcluding || null + ); + + if( !o.throwCallsStack ) + o.throwCallsStack = error.stack = o.fallBackStack; + + combinedStack = o.throwCallsStack; + + _.assert + ( + error.asyncCallsStack === undefined + || error.asyncCallsStack === null + || error.asyncCallsStack === '' + || _.arrayIs( error.asyncCallsStack ) + ); + if( error.asyncCallsStack && error.asyncCallsStack.length ) + { + o.asyncCallsStack = o.asyncCallsStack || []; + o.asyncCallsStack.push( ... error.asyncCallsStack ); + // _.arrayAppendArray( o.asyncCallsStack, error.asyncCallsStack ); + } + + if( o.asyncCallsStack === null || o.asyncCallsStack === undefined ) + if( _.Procedure && _.Procedure.ActiveProcedure ) + o.asyncCallsStack = [ _.Procedure.ActiveProcedure.stack() ]; + + _.assert( o.asyncCallsStack === null || _.arrayIs( o.asyncCallsStack ) ); + if( o.asyncCallsStack && o.asyncCallsStack.length ) + { + combinedStack += '\n\n' + o.asyncCallsStack.join( '\n\n' ); + } + + _.assert( _.strIs( combinedStack ) ); + if( o.stackCondensing ) + combinedStack = _.introspector.stackCondense( combinedStack ); + + } + + /* */ + + function attributesForm() + { + + try + { + o.catchLocation = _.introspector.location + ({ + stack : o.catchCallsStack, + location : o.catchLocation, + }); + } + catch( err2 ) + { + console.error( err2 ); + } + + try + { + o.throwLocation = _.introspector.location + ({ + error : error, + stack : o.throwCallsStack, + location : o.throwLocation, + }); + } + catch( err2 ) + { + console.error( err2 ); + } + + } + + /* */ + + function catchesForm() + { + + if( o.throws ) + { + _.assert( _.arrayIs( o.throws ) ); + o.throws.forEach( ( c ) => + { + c = _.introspector.locationFromStackFrame( c ).routineFilePathLineCol; + if( o.throwsStack ) + o.throwsStack += `\nthrown at ${c}`; + else + o.throwsStack = `thrown at ${c}`; + }); + } + + _.assert( _.number.is( o.catchLocation.abstraction ) ); + if( !o.catchLocation.abstraction || o.catchLocation.abstraction === 1 ) + { + if( o.throwsStack ) + o.throwsStack += `\nthrown at ${o.catchLocation.routineFilePathLineCol}`; + else + o.throwsStack = `thrown at ${o.catchLocation.routineFilePathLineCol}`; + } + + } + + /* */ + + function sourceCodeForm() + { + + if( !o.usingSourceCode ) + return; + + if( o.sourceCode ) + return; + + if( error.sourceCode === undefined ) + { + let c = _.introspector.code + ({ + location : o.throwLocation, + sourceCode : o.sourceCode, + asMap : 1, + }); + if( c && c.code && c.code.length < 400 ) + { + o.sourceCode = c; + } + } + + } + + /* */ + + function originalMessageForm() + { + let result = []; + + if( o.message ) + return; + + for( let a = 0 ; a < o.args.length ; a++ ) + { + let arg = o.args[ a ]; + let str; + + if( arg && !_.primitive.is( arg ) ) + { + + if( _.routine.is( arg.toStr ) ) + { + str = arg.toStr(); + } + else if( _.error.is( arg ) && _.strIs( arg.originalMessage ) ) + { + str = arg.originalMessage; + } + else if( _.error.is( arg ) ) + { + if( _.strIs( arg.message ) ) + str = arg.message; + else + str = exportString( arg ); + } + else + { + str = exportString( arg, { levels : 2 } ); + } + } + else if( arg === undefined ) + { + str = '\n' + String( arg ) + '\n'; + } + else + { + str = String( arg ); + } + + result[ a ] = str; + + } + + let o2 = + { + onToStr : eachMessageFormat, + onPairWithDelimeter : strConcatenateCounting + }; + o.message = _.strConcat( result, o2 ); + + /* + remove redundant spaces at the begin and the end of lines + */ + + o.message = o.message || fallBackMessage || 'UnknownError'; + o.message = o.message.replace( /^\s*/, '' ); + o.message = o.message.replace( /\x20*$/gm, '' ); + o.message = o.message.replace( /\s*$/, '' ); + + } + + /* */ + + function eachMessageFormat( str ) + { + let strBeginsWithRegular = _.strBegins( str, /\S/ ); + let strEndsWithRegular = _.strEnds( str, /\S/ ); + + if( !strBeginsWithRegular ) + { + let notSpaceLikeSymbol = /\S/.exec( str ); + + if( notSpaceLikeSymbol === null ) + { + str = str.replace( /\x20+/g, '' ); + strEndsWithRegular = true; + } + else + { + let before = str.substring( 0, notSpaceLikeSymbol.index ); + let spaces = /(?<=\n)\x20+$/.exec( before ); + before = before.replace( /\x20+/g, '' ); + before += spaces ? spaces[ 0 ] : ''; + + str = before + str.substring( notSpaceLikeSymbol.index ); + } + } + + if( str && !strEndsWithRegular ) + { + let notSpaceLikeSymbol = /\S\s*$/.exec( str ); + + let after = str.substring( notSpaceLikeSymbol.index + 1 ); + let spaces = /^\x20+(?=\n)/.exec( after ); + after = after.replace( /\x20+/g, '' ); + after += spaces ? spaces[ 0 ] : ''; + + str = str.substring( 0, notSpaceLikeSymbol.index + 1 ) + after; + } + + return str; + } + + /* */ + + function strConcatenateCounting( src1, src2 ) + { + let result; + if( _.strEnds( src1, '\n' ) && _.strBegins( src2, '\n' ) ) + { + let right = /\n+$/.exec( src1 ); + let left = /^\n+/.exec( src2 ); + + result = src1.substring( 0, right.index ); + result += right[ 0 ].length > left[ 0 ].length ? right[ 0 ] : left[ 0 ]; + result += src2.substring( left[ 0 ].length ); + } + else + { + result = src1 + src2; + } + return result; + } +} + +_err.defaults = +{ + + /**/ + + args : null, + sections : null, + concealed : null, + exposed : null, + level : 1, /* to make catch stack work properly level should be 1 by default */ + + /* String */ + + message : null, /* qqq : cover the option */ + reason : null, + sourceCode : null, + + /* Boolean */ + + stackRemovingBeginIncluding : 0, + stackRemovingBeginExcluding : 0, + usingSourceCode : 1, + stackCondensing : 1, + attended : null, + logged : null, + brief : null, + + /* Location */ + + throwLocation : null, + catchLocation : null, + + /* Stack */ + + asyncCallsStack : null, + throwCallsStack : null, + catchCallsStack : null, + fallBackStack : null, + throwsStack : '', + throws : null, + +} + +// + +/** + * Creates error object, with message created from passed `msg` parameters and contains error trace. + * If passed several strings (or mixed error and strings) as arguments, the result error message is created by + concatenating them. + * + * @example + * function divide( x, y ) + * { + * if( y == 0 ) + * throw _.err( 'divide by zero' ) + * return x / y; + * } + * divide( 3, 0 ); + * + * // log + * // Error: + * // caught at divide (:2:29) + * // divide by zero + * // Error + * // at _err (file:///.../wTools/staging/Base.s:1418:13) + * // at wTools.err (file:///.../wTools/staging/Base.s:1449:10) + * // at divide (:2:29) + * // at :1:1 + * + * @param {...String|Error} msg Accepts list of messeges/errors. + * @returns {Error} Created Error. If passed existing error as one of parameters, routine modified it and return + * reference. + * @function err + * @namespace Tools + */ + +function err() +{ + return _._err + ({ + args : arguments, + level : 2, + }); +} + +// + +/* qqq : optimize */ +function brief() +{ + return _._err + ({ + args : arguments, + level : 2, + brief : 1, + }); +} + +// + +function unbrief() +{ + return _._err + ({ + args : arguments, + level : 2, + brief : 0, + }); +} + +// + +function process( err ) +{ + + if( arguments.length !== 1 || !_.error.isFormed( err ) ) + err = _.err( ... arguments ); + + if( _.process && _.process.entryPointInfo ) + { + let body = _.process.entryPointInfo(); + if( body ) + _.error.sectionAdd( err, { name : 'process', body }); + } + + return err; +} + +// + +function unprocess() +{ + + if( arguments.length !== 1 || !_.error.isFormed( err ) ) + err = _.err( ... arguments ); + + _.error.sectionRemove( err, 'process' ); + + return err; +} + +// + +function fromStr( errStr ) +{ + + try + { + + errStr = _.str.lines.strip( errStr ); + + let sectionBeginRegexp = /[=]\s+(.*?)\s*\n/mg; + let splits = _.strSplitFast + ({ + src : errStr, + delimeter : sectionBeginRegexp, + }); + + let sectionName; + let throwCallsStack = ''; + let throwsStack = ''; + let stackCondensing = true; + let messages = []; + for( let s = 0 ; s < splits.length ; s++ ) + { + let split = splits[ s ]; + let sectionNameParsed = sectionBeginRegexp.exec( split + '\n' ); + if( sectionNameParsed ) + { + sectionName = sectionNameParsed[ 1 ]; + continue; + } + + if( !sectionName ) + messages.push( split ); + else if( !sectionName || _.strBegins( sectionName, 'Message of' ) ) + messages.push( split ); + else if( _.strBegins( sectionName, 'Beautified calls stack' ) ) + throwCallsStack = split; + else if( _.strBegins( sectionName, 'Throws stack' ) ) + throwsStack = split; + + } + + let error = new Error(); + + let throwLocation = _.introspector.locationFromStackFrame( throwCallsStack || error.stack ); + + let originalMessage = messages.join( '\n' ); + + let result = _.error._make + ({ + error, + throwLocation, + stackCondensing, + originalMessage, + combinedStack : throwCallsStack, + throwCallsStack, + throwsStack, + }); + + return result; + } + catch( err2 ) + { + console.error( err2 ); + return Error( errStr ); + } +} + +// -- +// stater +// -- + +function attend( err, value ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + if( value === undefined ) + value = Config.debug ? _.introspector.stack([ 0, Infinity ]) : true; + let result = _.error.concealedSet( err, { attended : value } ); + return result; +} + +// + +function logged( err, value ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + if( value === undefined ) + value = Config.debug ? _.introspector.stack([ 0, Infinity ]) : true; + // console.log( `logged ${value}` ); + return _.error.concealedSet( err, { logged : value } ); +} + +// + +function suspend( err, owner, value ) +{ + _.assert( arguments.length === 3 ); + _.assert( !!owner ); + + /* + cant suspend/resume suspended by another owner error + */ + + if( err.suspended && err.suspended !== owner ) + return _.error.concealedSet( err, {} ); + + let value2 = err.suspended; + if( value === undefined ) + value = true; + let result = _.error.concealedSet( err, { suspended : value ? owner : false } ); + + /* + resuming of suspended wary error object should resume _handleUncaughtAsync + */ + + if( value2 && !value && err.wary ) + { + _.error._handleUncaughtAsync( err ); + } + + return result +} + +// + +function wary( err, value ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + if( value === undefined ) + value = true; + return _.error.concealedSet( err, { wary : value } ); +} + +// + +/* zzz : standartize interface of similar routines */ +function reason( err, value ) +{ + + if( arguments.length === 1 ) + { + return err.reason; + } + else if( arguments.length === 2 ) + { + // nonenumerable( 'reason', value ); + _.error.concealedSet( err, { reason : value } ); + return err.reason; + } + + throw Error( 'Expects one or two argument' ); + + // /* */ + // + // function nonenumerable( propName, value ) + // { + // try + // { + // let o = + // { + // enumerable : false, + // configurable : true, + // writable : true, + // value, + // }; + // Object.defineProperty( err, propName, o ); + // } + // catch( err2 ) + // { + // console.error( err2 ); + // } + // } + +} + +// + +function restack( err, level ) +{ + + if( !( arguments.length === 1 || arguments.length === 2 ) ) + throw Error( 'Expects single argument or none' ); + + if( level === undefined ) + level = 1; + + if( !_.number.defined( level ) ) + throw Error( 'Expects defined number' ); + + let err2 = _._err + ({ + args : [], + level : level + 1, + }); + + return _.err( err2, err ); +} + +// + +function once( err ) +{ + + err = _._err + ({ + args : arguments, + level : 2, + }); + + if( err.logged ) + return undefined; + + _.error.attend( err ); + + return err; +} + +// + +function originalMessage( err ) +{ + + if( arguments.length !== 1 ) + throw Error( 'error.originalMessage : Expects single argument' ); + + if( _.strIs( err ) ) + return err; + + if( !err ) + return; + + if( err.originalMessage ) + return err.originalMessage; + + let message = err.message; + + if( !message && message !== '' ) + message = err.msg; + if( !message && message !== '' ) + message = err.name; + + return message; +} + +// + +function originalStack( err ) +{ + + if( arguments.length !== 1 ) + throw Error( 'error.originalStack : Expects single argument' ); + + if( !_.error.is( err ) ) + throw Error( 'error.originalStack : Expects error' ); + + if( err.throwCallsStack ) + return err.throwCallsStack; + + if( err.combinedStack ) + return err.combinedStack; + + if( err[ stackSymbol ] ) + return err[ stackSymbol ]; + + if( err.stack ) + return _.introspector.stack( err.stack ); + + /* should return null if nothing found */ + return null; +} + +// -- +// log +// -- + +function _log( err, logger ) +{ + logger = logger || _global.logger || _global.console; + + /* */ + + if( _.routine.is( err.toString ) ) + { + let str = err.toString(); + if( _.color && _.color.strFormat ) + str = _.color.strFormat( str, 'negative' ); + logger.error( str ) + } + else + { + logger.error( 'Error does not have toString' ); + logger.error( err ); + } + + /* */ + + _.error.logged( err ); + _.error.attend( err ); + + /* */ + + return err; +} + +// + +/** + * Creates error object, with message created from passed `msg` parameters and contains error trace. + * If passed several strings (or mixed error and strings) as arguments, the result error message is created by + concatenating them. Prints the created error. + * If _global_.logger defined, routine will use it to print error, else uses console + * + * @see {@link wTools.err See err} + * + * @example + * function divide( x, y ) + * { + * if( y == 0 ) + * throw _.error.log( 'divide by zero' ) + * return x / y; + * } + * divide( 3, 0 ); + * + * // log + * // Error: + * // caught at divide (:2:29) + * // divide by zero + * // Error + * // at _err (file:///.../wTools/staging/Base.s:1418:13) + * // at wTools.errLog (file:///.../wTools/staging/Base.s:1462:13) + * // at divide (:2:29) + * // at :1:1 + * + * @param {...String|Error} msg Accepts list of messeges/errors. + * @returns {Error} Created Error. If passed existing error as one of parameters, routine modified it and return + * @function errLog + * @namespace Tools + */ + +function log() +{ + + let err = _._err + ({ + args : arguments, + level : 2, + }); + + return _.error._log( err ); +} + +// + +function logOnce( err ) +{ + + err = _._err + ({ + args : arguments, + level : 2, + }); + + if( err.logged ) + return err; + + return _.error._log( err ); +} + +// + +function _Setup() +{ + + Error.stackTraceLimit = Infinity; +/* Error.stackTraceLimit = 99; */ + +} + +// -- +// namespace +// -- + +let stackSymbol = Symbol.for( 'stack' ); + +let ToolsExtension = +{ + + errIs : is, + + _errMake : _make, + _err, + err, + errBrief : brief, + errUnbrief : unbrief, + errProcess : process, + errUnprocess : unprocess, + errAttend : attend, + errLogged : logged, + errSuspend : suspend, + errWary : wary, + errRestack : restack, + errOnce : once, + + _errLog : _log, + errLog : log, + errLogOnce : logOnce, + +} + +Object.assign( _, ToolsExtension ); + +// + +/** + * @property {Object} error={} + * @property {Boolean} breakpointOnAssertEnabled=!!Config.debug + * @name ErrFields + * @namespace Tools + */ + +let ErrorExtension = +{ + + // dichotomy + + is, + isFormed, + isAttended, + isBrief, + isLogged, + isSuspended, + isWary, + + // generator + + _sectionsJoin, + _messageForm, + sectionRemove, + sectionAdd, + _sectionAdd, + _sectionExposedAdd, + + exposedSet, + concealedSet, + _inStr, + + // introductor + + _make, + _err, + err, + brief, + unbrief, + process, /* qqq : cover please */ + unprocess, /* qqq : cover please */ + fromStr, + + // stater + + attend, + logged, + suspend, /* qqq : cover, please. should work okay with symbols */ + wary, /* qqq : cover */ + reason, /* qqq : cover */ + restack, /* qqq : cover */ + once, /* qqq : cover */ + originalMessage, + originalStack, + + // log + + _log, + log, + logOnce, + + // meta + + _Setup, + + // fields + + breakpointOnDebugger : 0, + breakpointOnAssertEnabled : !!Config.debug, + _errorCounter : 0, + _errorMaking : false, + +} + +Object.assign( _.error, ErrorExtension ); +_.error._Setup(); + +/* zzz : improve formatting of stack with table */ +/* xxx : postpone reading files as late as possible */ +/* xxx : move unhandled error event to namespacer::error */ +/* xxx : add module files stack */ + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1/zErr.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, zErr_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file zErr_s */ })(); + +/* */ /* begin of file _1LogicNode_s */ ( function _1LogicNode_s() { function _1LogicNode_s_naked() { ( function _l3_1LogicNode_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implement +// -- + +function is( src ) +{ + if( !src ) + return false; + return src instanceof this.class; +} + +// + +function make( src ) +{ + if( arguments.length !== 1 ) + throw new Error( 'Expects exactly one argument' ); + return new this.class( src ); +} + +// + +function from( src ) +{ + if( arguments.length !== 1 ) + throw new Error( 'Expects exactly one argument' ); + if( this.is( src ) ) + return src; + return this.make( src ); +} + +// + +function cloneShallow() +{ + _.assert( !( this instanceof cloneShallow ) ); + return this; +} + +// + +function cloneDeep() +{ + debugger; + _.assert( !( this instanceof cloneDeep ) ); + return this; +} + +// + +function equalAre_functor( fo ) +{ + let cls = fo.class; + + return function equalAre( it ) + { + let self = this; + + _.assert( arguments.length === 1 ); + + if( !it.src ) + return it.stop( false ); + if( !it.src2 ) + return it.stop( false ); + + if( !( it.src instanceof cls ) ) + return it.stop( false ); + if( !( it.src2 instanceof cls ) ) + return it.stop( false ); + debugger; + if( !it.src.type !== it.src2.type ) + return it.stop( false ); + + if( it.src.elements.length !== it.src2.elements.length ) + return it.stop( false ); + + for( let i = 0 ; i < it.src.elements.length ; i++ ) + { + debugger; xxx + it.equal( it.src, it.src2 ); + } + + } + +} + +// + +function iterator() +{ + + let iterator = Object.create( null ); + iterator.next = next; + iterator.index = 0; + iterator.instance = this; + return iterator; + + function next() + { + let result = Object.create( null ); + let instance = this.instance; + result.done = this.index === instance.elements.length; + if( result.done ) + return result; + result.value = instance.elements[ this.index ]; + this.index += 1; + return result; + } + +} + +// + +function exportString() +{ + return `{- ${this.type} with ${String( this.elements.length )} elements -}`; +} + +// + +function exportStructure() +{ + +} + +// + +function lengthGet() +{ + return this.elements.length; +} + +// + +function exec( o ) +{ + o = _.routine.options( exec, arguments ); + o.onEach = o.onEach || defaultOnEach; + let r = this._exec( o ); + return r; + + function defaultOnEach( e, it ) + { + return e; + } + +} + +exec.defaults = +{ + onEach : null, +} + +// + +function _orExec( it ) +{ + let result = false; + this.elements.some( ( e ) => + { + if( _.logic.isNode( e ) ) + e = e._exec( it ); + e = it.onEach( e, it ); + if( e ) + { + result = e; + return true; + } + }); + return result; +} + +// + +function _andExec( it ) +{ + let result = true; + this.elements.every( ( e ) => + { + if( _.logic.isNode( e ) ) + e = e._exec( it ); + e = it.onEach( e, it ); + if( !e ) + { + result = e; + return false; + } + return true; + }); + return result; +} + +// + +function _xorExec( it ) +{ + let result = false; + this.elements.forEach( ( e ) => + { + if( _.logic.isNode( e ) ) + e = e._exec( it ); + e = it.onEach( e, it ); + if( e ) + result = !result; + }); + return result; +} + +// + +function _xandExec( it ) +{ + let result = true; + this.elements.forEach( ( e ) => + { + if( _.logic.isNode( e ) ) + e = e._exec( it ); + e = it.onEach( e, it ); + if( e ) + result = !result; + }); + return result; +} + +// + +function _ifExec( it ) +{ + + for( let i = 0, l = this.elements.length - 1 ; i < l ; i++ ) + { + let e = this.elements[ i ]; + if( _.logic.isNode( e ) ) + e = e._exec( it ); + e = it.onEach( e, it ); + if( !e ) + return true; + } + + if( this.elements.length > 0 ) + { + let e = this.elements[ this.elements.length-1 ]; + if( _.logic.isNode( e ) ) + e = e._exec( it ); + e = it.onEach( e, it ); + return e; + } + + return true; +} + +// + +function _firstExec( it ) +{ + let e = this.elements[ 0 ]; + if( _.logic.isNode( e ) ) + e = e._exec( it ); + e = it.onEach( e, it ); + return e; +} + +// + +function _secondExec( it ) +{ + let e = this.elements[ 1 ]; + if( _.logic.isNode( e ) ) + e = e._exec( it ); + e = it.onEach( e, it ); + return e; +} + +// + +function _notExec( it ) +{ + let e = this.elements[ 0 ]; + if( _.logic.isNode( e ) ) + e = e._exec( it ); + e = it.onEach( e, it ); + return !e; +} + +// -- +// meta +// -- + +function DeclareAbstract( fo ) +{ + + fo.class = function LogicAbstractNode( elements ) + { + if( arguments.length !== 1 ) + throw new Error( 'Expects exactly 1 argument' ); + this.elements = elements; + Object.freeze( this ); + return this; + } + + _.class.declareBasic + ({ + constructor : fo.class, + iterator, + equalAre : equalAre_functor( fo ), + exportString, + cloneShallow, /* xxx : implement */ + cloneDeep, /* xxx : implement */ + }); + + const prototype = fo.class.prototype; + prop( 'constructor', constructor ); + prop( 'type', 'abstract' ); + prop( 'exec', exec ); + prop( 'exportStructure', exportStructure ); + + Object.defineProperty( fo.class, 'length', + { + get : lengthGet, + enumerable : false, + configurable : false, + }); + + return fo; + + function prop( k, v ) + { + Object.defineProperty( prototype, k, + { + value : v, + enumerable : false, + configurable : false, + }); + } + +} + +DeclareAbstract.defaults = +{ +} + +// + +function Declare( fo ) +{ + fo.parent = fo.parent || _.logic.node.Abstract; + + const type = fo.type; + const parent = fo.parent; + + fo.class = { [ fo.name ] : function( val ) + { + return parent.apply( this, arguments ); + }}[ fo.name ]; + + const prototype = fo.class.prototype = Object.create( parent.prototype ); + prop( 'constructor', fo.class ); + prop( 'type', type ); + Object.setPrototypeOf( fo.class, parent ); + + _.props.extend( prototype, Methods[ type ] ); + + return fo; + + function prop( k, v ) + { + Object.defineProperty( prototype, k, + { + value : v, + enumerable : false, + configurable : false, + }); + } + +} + +Declare.defaults = +{ + name : null, + parent : null, +} + +// -- +// +// -- + +let Methods = +{ + + or : + { + _exec : _orExec, + }, + and : + { + _exec : _andExec, + }, + xor : + { + _exec : _xorExec, + }, + xand : + { + _exec : _xandExec, + }, + if : + { + _exec : _ifExec, + }, + + first : + { + _exec : _firstExec, + }, + second : + { + _exec : _secondExec, + }, + not : + { + _exec : _notExec, + }, + +} + +// -- +// +// -- + +var Extension = +{ + + DeclareAbstract, + Declare, + +} + +Object.assign( _.logic.node, Extension ); + +_.logic.node.Abstract = _.logic.node.DeclareAbstract({}).class; +_.logic.node.Or = _.logic.node.Declare({ type : 'or', name : 'LogicOr' }).class; +_.logic.node.And = _.logic.node.Declare({ type : 'and', name : 'LogicAnd' }).class; +_.logic.node.Xor = _.logic.node.Declare({ type : 'xor', name : 'LogicXor' }).class; +_.logic.node.Xand = _.logic.node.Declare({ type : 'xand', name : 'LogicXand' }).class; +_.logic.node.First = _.logic.node.Declare({ type : 'first', name : 'LogicFirst' }).class; +_.logic.node.Second = _.logic.node.Declare({ type : 'second', name : 'LogicSecond' }).class; +_.logic.node.Not = _.logic.node.Declare({ type : 'not', name : 'LogicNot' }).class; +_.logic.node.If = _.logic.node.Declare({ type : 'if', name : 'LogicIf' }).class; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/1LogicNode.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, _1LogicNode_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file _1LogicNode_s */ })(); + +/* */ /* begin of file _1Wrap_s */ ( function _1Wrap_s() { function _1Wrap_s_naked() { ( function _l3_1Wrap_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implement +// -- + +function is( src ) +{ + if( !src ) + return false; + return src instanceof this.class; +} + +// + +function make( src ) +{ + if( arguments.length !== 1 ) + throw new Error( 'Expects exactly one argument' ); + return new this.class( src ); +} + +// + +function from( src ) +{ + if( arguments.length !== 1 ) + throw new Error( 'Expects exactly one argument' ); + if( this.is( src ) ) + return src; + return this.make( src ); +} + +// + +function cloneShallow() +{ + _.assert( !( this instanceof cloneShallow ) ); + return this; +} + +// + +function cloneDeep() +{ + debugger; + _.assert( !( this instanceof cloneDeep ) ); + return this; +} + +// + +function equalAre_functor( fo ) +{ + let cls = fo.class; + + return function equalAre( it ) + { + let self = this; + + _.assert( arguments.length === 1 ); + + if( !it.src ) + return it.stop( false ); + if( !it.src2 ) + return it.stop( false ); + + if( !( it.src instanceof cls ) ) + return it.stop( false ); + if( !( it.src2 instanceof cls ) ) + return it.stop( false ); + + if( it.src.val === it.src2.val ) + return it.stop( true ); + + if( !( it.src.val instanceof cls ) ) + return it.stop( false ); + if( !( it.src2.val instanceof cls ) ) + return it.stop( false ); + } + +} + +// + +function iterator() +{ + + let iterator = Object.create( null ); + iterator.next = next; + iterator.index = 0; + iterator.instance = this; + return iterator; + + function next() + { + let result = Object.create( null ); + result.done = this.index === 1; + if( result.done ) + return result; + result.value = this.instance.val; + this.index += 1; + return result; + } + +} + +// + +function exportString() +{ + if( _.symbol.is( this.val ) ) + return `{- ${this.constructor.name} {- Symbol ${Symbol.keyFor( this.val )} -} -}`; + else + return `{- ${this.constructor.name} ${String( this.val )} -}`; +} + +// + +function declare( fo ) +{ + + fo.class = { [ fo.name ] : function( val ) + { + if( arguments.length !== 1 ) + throw new Error( 'Expects exactly 1 argument' ); + this.val = val; + Object.freeze( this ); + return this; + }}[ fo.name ]; + + _.class.declareBasic + ({ + constructor : fo.class, + iterator, + equalAre : equalAre_functor( fo ), + exportString, + cloneShallow, /* xxx : implement */ + cloneDeep, /* xxx : implement */ + }); + + _.assert( fo.namespace === undefined ); + _.assert( fo.class.name === fo.name ); + + fo.namespace = + { + is, + make, + from, + class : fo.class, + } + + return fo; +} + +declare.defaults = +{ + name : null, +} + +// + +var Extension = +{ + + declare, + +} + +// + +Object.assign( _.wrap, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/1Wrap.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, _1Wrap_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file _1Wrap_s */ })(); + +/* */ /* begin of file _2Props_s */ ( function _2Props_s() { function _2Props_s_naked() { ( function _l3_2Property_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const prototypeSymbol = Symbol.for( 'prototype' ); +const constructorSymbol = Symbol.for( 'constructor' ); + +// -- +// equaler +// -- + +function _identicalShallow( src1, src2 ) +{ + if( this.keys( src1 ).length !== this.keys( src2 ).length ) + return false; + + for( let s in src1 ) + { + if( src1[ s ] !== src2[ s ] ) + return false; + } + + return true; +} + +// + +function identicalShallow( src1, src2, o ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( !this.like( src1 ) ) + return false; + if( !this.like( src2 ) ) + return false; + + return this._identicalShallow( src1, src2 ); +} + +// + +function _equivalentShallow( src1, src2 ) +{ + if( this.keys( src1 ).length !== this.keys( src2 ).length ) + return false; + + for( let s in src1 ) + { + if( src1[ s ] !== src2[ s ] ) + return false; + } + + return true; +} + +// + +function equivalentShallow( src1, src2, o ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( !this.like( src1 ) ) + return false; + if( !this.like( src2 ) ) + return false; + + return this._equivalentShallow( src1, src2 ); +} + +// -- +// exporter +// -- + +function _exportStringDiagnosticShallow( src, o ) +{ + return `{- ${_.entity.strType( src )} with ${this._lengthOf( src )} elements -}`; +} + +// + +function exportStringDiagnosticShallow( src, o ) +{ + _.assert( this.like( src ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( o === undefined || _.object.isBasic( o ) ); + return this._exportStringDiagnosticShallow( ... arguments ); +} + +// -- +// properties +// -- + +function keyIsImplicit( key ) +{ + if( !_.props.implicit.is( key ) ) + return false; + if( key.val === prototypeSymbol ) + return true; + if( key.val === constructorSymbol ) /* xxx : try */ + return true; + return false; +} + +// + +function _onlyImplicitWithKey( src, key ) +{ + if( !_.props.implicit.is( key ) ) + return; + if( key.val === prototypeSymbol ) + { + if( src === undefined || src === null ) + return undefined; + return Object.getPrototypeOf( src ); + } + if( key.val === constructorSymbol ) /* xxx : try */ + { + if( src === undefined || src === null ) + return undefined; + let prototype = Object.getPrototypeOf( src ); + if( !prototype ) + return prototype; + return prototype.constructor; + } +} + +// + +function onlyImplicitWithKey( src, key ) +{ + _.assert( this === _.props ); + _.assert( arguments.length === 2 ); + return this._onlyImplicitWithKey( src, key ); +} + +// + +function _onlyImplicitWithKeyTuple( container, key ) +{ + let r = _.props._onlyImplicitWithKey( container, key ); + return [ r, key, r !== undefined ]; + // return [ r, key.val, r !== undefined ]; +} + +// + +function onlyImplicit( src ) +{ + let result = new HashMap(); + + _.assert( this === _.props ); + _.assert( arguments.length === 1 ); + + if( src === undefined || src === null ) + return result; + var prototype = Object.getPrototypeOf( src ); + if( prototype ) + result.set( _.props.implicit.prototype, prototype ); + + return result; +} + +// -- +// inspector +// -- + +function _lengthOf( src ) +{ + return this.keys( src ).length; +} + +// + +function lengthOf( src ) +{ + _.assert( arguments.length === 1 ); + _.assert( this.like( src ) ); + return this._lengthOf( src ); +} + +// + +function _hasKey( src, key ) +{ + if( _.primitive.is( src ) ) + return false; + if( !Reflect.has( src, key ) ) + return false; + return true; +} + +// + +function hasKey( src, key ) +{ + _.assert( this.like( src ) ); + return this._hasKey( src, key ); +} + +// + +function _hasCardinal( src, cardinal ) +{ + if( cardinal < 0 ) + return false; + let length = this._lengthOf( src ); + return cardinal < length; +} + +// + +function hasCardinal( src, cardinal ) +{ + _.assert( this.like( src ) ); + return this._hasCardinal( src, cardinal ); +} + +// + +function _keyWithCardinal( src, cardinal ) +{ + if( cardinal < 0 ) + return [ undefined, false ]; + let keys = this.keys( src ); + if( cardinal < keys.length ) + return [ keys[ cardinal ], true ]; + return [ undefined, false ]; +} + +// + +function keyWithCardinal( src, cardinal ) +{ + _.assert( this.like( src ) ); + return this._keyWithCardinal( src, cardinal ); +} + +// + +function _cardinalWithKey( src, key ) +{ + if( !( key in src ) ) + return -1; + let keys = this.keys( src ); + return keys.indexOf( key ); +} + +// + +function cardinalWithKey( src, key ) +{ + _.assert( this.like( src ) ); + return this._cardinalWithKey( src, key ); +} + +// -- +// elementor +// -- + +function _elementWithKey( src, key ) +{ + if( _.strIs( key ) ) + { + if( _.props.has( src, key ) ) + return [ src[ key ], key, true ]; + else + return [ undefined, key, false ]; + } + else + { + return [ undefined, key, false ]; + } +} + +// + +function elementWithKey( src, key ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + return this._elementWithKey( src, key ); +} + +// + +function _elementWithImplicit( src, key ) +{ + if( _.props.keyIsImplicit( key ) ) + return _.props._onlyImplicitWithKeyTuple( src, key ); + return this._elementWithKey( src, key ); +} + +// + +function elementWithImplicit( src, key ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + return this._elementWithImplicit( src, key ); +} + +// + +function _elementWithCardinal( src, cardinal ) +{ + if( !_.numberIs( cardinal ) || cardinal < 0 ) + return [ undefined, cardinal, false ]; + let keys = this.keys( src ); + let key2 = keys[ cardinal ]; + if( keys.length <= cardinal ) + return [ undefined, cardinal, false ]; + return [ src[ key2 ], key2, true ]; +} + +// + +function elementWithCardinal( src, cardinal ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + return this._elementWithCardinal( src, cardinal ); +} + +// + +function _elementWithKeySet( dst, key, val ) +{ + dst[ key ] = val; + return [ key, true ]; +} + +// + +function elementWithKeySet( dst, key, val ) +{ + _.assert( arguments.length === 3 ); + _.assert( this.is( dst ) ); + return this._elementWithKeySet( dst, key, val ); +} + +// + +function _elementWithCardinalSet( dst, cardinal, val ) +{ + let was = this._elementWithCardinal( dst, cardinal ); + if( was[ 2 ] === true ) + { + dst[ was[ 1 ] ] = val; + return [ was[ 1 ], true ]; + } + else + { + return [ cardinal, false ]; + } +} + +// + +function elementWithCardinalSet( dst, cardinal, val ) +{ + _.assert( arguments.length === 3 ); + _.assert( this.is( dst ) ); + return this._elementWithCardinalSet( dst, cardinal, val ); +} + +// + +function _elementWithKeyDel( dst, key ) +{ + if( !this._hasKey( dst, key ) ) + return false; + delete dst[ key ]; + return true; +} + +// + +function elementWithKeyDel( dst, key ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( dst ) ); + return this._elementWithKeyDel( dst, key ); +} + +// + +function _elementWithCardinalDel( dst, cardinal ) +{ + let has = this._keyWithCardinal( dst, cardinal ); + if( !has[ 1 ] ) + return false; + delete dst[ has[ 0 ] ]; + return true; +} + +// + +function elementWithCardinalDel( dst, cardinal ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( dst ) ); + // return this._elementWithCardinalDel( dst, cardinal, val ); + return this._elementWithCardinalDel( dst, cardinal ); +} + +// + +function _empty( dst ) +{ + for( let k in dst ) + delete dst[ k ]; + return dst; +} + +// + +function empty( dst ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( this.like( dst ) ); + return this._empty( dst ); +} + +// -- +// iterator +// -- + +function _eachLeft( src, onEach ) +{ + let c = 0; + for( let k in src ) + { + let val = src[ k ]; + onEach( val, k, c, src ); + c += 1; + } +} + +// + +function eachLeft( src, onEach ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + this._eachLeft( src, onEach ); +} + +// + +function _eachRight( src, onEach ) +{ + let keys = this.keys( src ); + for( let c = keys.length-1 ; c >= 0 ; c-- ) + { + let k = keys[ c ]; + let val = src[ k ]; + onEach( val, k, c, src ); + } +} + +// + +function eachRight( src, onEach ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + this._eachRight( src, onEach ); +} + +// + +function _whileLeft( src, onEach ) +{ + let c = 0; + let lastk; + for( let k in src ) + { + let val = src[ k ]; + let r = onEach( val, k, c, src ); + _.assert( r === true || r === false ); + if( r === false ) + return [ val, k, c, false ]; + lastk = k; + c += 1; + } + if( c === 0 ) + return [ undefined, undefined, -1, true ]; + return [ src[ lastk ], lastk, c-1, true ]; +} + +// + +function whileLeft( src, onEach ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + this._whileLeft( src, onEach ); +} + +// + +function _whileRight( src, onEach ) +{ + let keys = this.keys( src ); + if( keys.length === 0 ) + return [ undefined, undefined, -1, true ]; + for( let c = keys.length-1 ; c >= 0 ; c-- ) + { + let k = keys[ c ]; + let val = src[ k ]; + let r = onEach( val, k, c, src ); + _.assert( r === true || r === false ); + if( r === false ) + return [ val, k, c, false ]; + } + + var k = keys[ 0 ]; + return [ src[ k ], k, 0, true ]; +} + +// + +function whileRight( src, onEach ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + this._whileRight( src, onEach ); +} + +// + +function _aptLeft( src, onEach ) +{ + let result, result2; + + if( onEach ) + result2 = this._whileLeft( src, function( val, k, c, src2 ) + { + let r = onEach( ... arguments ); + if( r !== undefined ) + { + result = [ r, k, c, true ]; + return false; + } + return true; + }); + else + result2 = this._whileLeft( src, function( val, k, c, src2 ) + { + result = [ val, k, c, true ]; + return false; + }); + + if( result === undefined ) + { + result2[ 3 ] = false; + return result2; + } + + return result; +} + +// + +function aptLeft( src, onEach ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( this.is( src ) ); + return this._aptLeft( src, onEach ); +} + +// + +function _aptRight( src, onEach ) +{ + let result, result2; + + if( onEach ) + result2 = this._whileRight( src, function( val, k, c, src2 ) + { + let r = onEach( ... arguments ); + if( r !== undefined ) + { + result = [ r, k, c, true ]; + return false; + } + return true; + }); + else + result2 = this._whileRight( src, function( val, k, c, src2 ) + { + result = [ val, k, c, true ]; + return false; + }); + + if( result === undefined ) + { + result2[ 3 ] = false; + return result2; + } + + return result; +} + +// + +function aptRight( src, onEach ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( this.is( src ) ); + return this._aptRight( src, onEach ); +} + +// + +function _filterAct0() +{ + const self = this; + const dst = arguments[ 0 ]; + const src = arguments[ 1 ]; + const onEach = arguments[ 2 ]; + const each = arguments[ 3 ]; + const escape = arguments[ 4 ]; + + if( dst === src ) + each( src, function( val, k, c, src2 ) + { + let val2 = onEach( val, k, c, src2, dst ); + let val3 = escape( val2 ); + if( val2 === undefined ) + self._elementDel( dst, k ); + else if( val3 === val ) + return + else + self._elementSet( dst, k, val3 ); + }); + else + each( src, function( val, k, c, src2 ) + { + let val2 = onEach( val, k, c, src2, dst ); + let val3 = escape( val2 ); + if( val2 === undefined ) + return; + self._elementSet( dst, k, val3 ); + }); + + return dst; +} + +// + +function _filterAct() +{ + let self = this; + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + let onEach = arguments[ 2 ]; + let isLeft = arguments[ 3 ]; + let eachRoutineName = arguments[ 4 ]; + let escape = arguments[ 5 ]; + let general = this.tools[ this.MostGeneralNamespaceName ]; + + if( dst === null ) + dst = this.makeUndefined( src ); + else if( dst === _.self ) + dst = src; + + if( Config.debug ) + { + _.assert( arguments.length === 6, `Expects 3 arguments` ); + _.assert( this.is( dst ), () => `dst is not ${this.TypeName}` ); + _.assert( general.is( src ), () => `src is not ${general.TypeName}` ); + _.assert( _.routineIs( onEach ), () => 'onEach is not a routine' ) + } + + this._filterAct0( dst, src, onEach, general[ eachRoutineName ].bind( general ), escape ); + + return dst; +} + +// + +function filterWithoutEscapeLeft( dst, src, onEach ) +{ + return this._filterAct( ... arguments, true, 'eachLeft', ( val ) => val ); +} + +// + +function filterWithoutEscapeRight( dst, src, onEach ) +{ + return this._filterAct( ... arguments, false, 'eachRight', ( val ) => val ); +} + +// + +function filterWithEscapeLeft( dst, src, onEach ) +{ + return this._filterAct( ... arguments, true, 'eachLeft', ( val ) => _.escape.right( val ) ); +} + +// + +function filterWithEscapeRight( dst, src, onEach ) +{ + return this._filterAct( ... arguments, false, 'eachRight', ( val ) => _.escape.right( val ) ); +} + +// + +function _mapAct0() +{ + const self = this; + const dst = arguments[ 0 ]; + const src = arguments[ 1 ]; + const onEach = arguments[ 2 ]; + const each = arguments[ 3 ]; + const escape = arguments[ 4 ]; + + if( dst === src ) + each( src, function( val, k, c, src2 ) + { + let val2 = onEach( val, k, c, src2, dst ); + let val3 = escape( val2 ); + if( val3 === val || val2 === undefined ) + return; + self._elementSet( dst, k, val3 ); + }); + else + each( src, function( val, k, c, src2 ) + { + let val2 = onEach( val, k, c, src2, dst ); + let val3 = escape( val2 ); + if( val2 === undefined ) + self._elementSet( dst, k, val ); + else + self._elementSet( dst, k, val3 ); + }); + + return dst; +} + +// + +function _mapAct() +{ + let self = this; + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + let onEach = arguments[ 2 ]; + let isLeft = arguments[ 3 ]; + let eachRoutineName = arguments[ 4 ]; + let escape = arguments[ 5 ]; + let general = this.tools[ this.MostGeneralNamespaceName ]; + + if( dst === null ) + { + // dst = this.makeUndefined( src ); + let dstNamespace = self.namespaceOf( src ) || self.default || self; + dst = dstNamespace.makeUndefined( src ); + } + else if( dst === _.self ) + { + dst = src; + } + + if( Config.debug ) + { + _.assert( arguments.length === 6, `Expects 3 arguments` ); + _.assert( this.is( dst ), () => `dst is not ${this.TypeName}` ); + _.assert( general.is( src ), () => `src is not ${general.TypeName}` ); + _.assert( _.routineIs( onEach ), () => `onEach is not a routine` ); + } + + this._mapAct0( dst, src, onEach, general[ eachRoutineName ].bind( general ), escape ); + + return dst; +} + +// + +function mapWithoutEscapeLeft( dst, src, onEach ) +{ + return this._mapAct( ... arguments, true, 'eachLeft', ( val ) => val ); +} + +// + +function mapWithoutEscapeRight( dst, src, onEach ) +{ + return this._mapAct( ... arguments, false, 'eachRight', ( val ) => val ); +} + +// + +function mapWithEscapeLeft( dst, src, onEach ) +{ + return this._mapAct( ... arguments, true, 'eachLeft', ( val ) => _.escape.right( val ) ); +} + +// + +function mapWithEscapeRight( dst, src, onEach ) +{ + return this._mapAct( ... arguments, false, 'eachRight', ( val ) => _.escape.right( val ) ); +} + +// -- +// property implicit +// -- + +_.assert( _.props.implicit === undefined ); +_.assert( _.props.Implicit === undefined ); +_.props.implicit = _.wrap.declare({ name : 'Implicit' }).namespace; +_.props.Implicit = _.props.implicit.class; +_.assert( _.mapIs( _.props.implicit ) ); +_.assert( _.routineIs( _.props.Implicit ) ); + +_.props.implicit.prototype = new _.props.Implicit( prototypeSymbol ); +_.props.implicit.constructor = new _.props.Implicit( constructorSymbol ); + +// -- +// extension +// -- + +let Extension = +{ + + // equaler + + _identicalShallow, + identicalShallow, + identical : identicalShallow, + _equivalentShallow, + equivalentShallow, + equivalent : equivalentShallow, + + // exporter + + _exportStringDiagnosticShallow, + exportStringDiagnosticShallow, + _exportStringCodeShallow : _exportStringDiagnosticShallow, + exportStringCodeShallow : exportStringDiagnosticShallow, + exportString : exportStringDiagnosticShallow, + + // properties + + keyIsImplicit, /* qqq : cover */ + _onlyImplicitWithKey, + onlyImplicitWithKey, /* qqq : cover */ + _onlyImplicitWithKeyTuple, + onlyImplicit, + + // inspector + + _lengthOf, + lengthOf, /* qqq : cover */ + _hasKey, + hasKey, /* qqq : cover */ + _hasCardinal, + hasCardinal, /* qqq : cover */ + _keyWithCardinal, + keyWithCardinal, /* qqq : cover */ + _cardinalWithKey, + cardinalWithKey, /* qqq : cover */ + + // elementor + + _elementGet : _elementWithKey, + elementGet : elementWithKey, /* qqq : cover */ + _elementWithKey, + elementWithKey, /* qqq : cover */ + _elementWithImplicit, + elementWithImplicit, /* qqq : cover */ + _elementWithCardinal, + elementWithCardinal, /* qqq : cover */ + + _elementSet : _elementWithKeySet, + elementSet : elementWithKeySet, /* qqq : cover */ + _elementWithKeySet, + elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet, + elementWithCardinalSet, /* qqq : cover */ + + _elementDel : _elementWithKeyDel, + elementDel : elementWithKeyDel, /* qqq : cover */ + _elementWithKeyDel, + elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel, + elementWithCardinalDel, /* qqq : cover */ + _empty, + empty, /* qqq : for junior : cover */ + + // iterator + + _each : _eachLeft, + each : eachLeft, /* qqq : cover */ + _eachLeft, + eachLeft, /* qqq : cover */ + _eachRight, + eachRight, /* qqq : cover */ + + _while : _whileLeft, + while : whileLeft, /* qqq : cover */ + _whileLeft, + whileLeft, /* qqq : cover */ + _whileRight, + whileRight, /* qqq : cover */ + + _aptLeft, + aptLeft, /* qqq : cover */ + first : aptLeft, + _aptRight, /* qqq : cover */ + aptRight, + last : aptRight, /* qqq : cover */ + + _filterAct0, + _filterAct, + filterWithoutEscapeLeft, + filterWithoutEscapeRight, + filterWithoutEscape : filterWithoutEscapeLeft, + filterWithEscapeLeft, + filterWithEscapeRight, + filterWithEscape : filterWithEscapeLeft, + filter : filterWithoutEscapeLeft, + + _mapAct0, + _mapAct, + mapWithoutEscapeLeft, + mapWithoutEscapeRight, + mapWithoutEscape : mapWithoutEscapeLeft, + mapWithEscapeLeft, + mapWithEscapeRight, + mapWithEscape : mapWithEscapeLeft, + map : mapWithoutEscapeLeft, + +} + +// + +Object.assign( _.props, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/2Props.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, _2Props_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file _2Props_s */ })(); + +/* */ /* begin of file _3Blank_s */ ( function _3Blank_s() { function _3Blank_s_naked() { ( function _l1_3Blank_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.blank = _.blank || Object.create( null ); + +// -- +// equaler +// -- + +function _identicalShallow( src1, src2 ) +{ + return src1 === src2; +} + +// -- +// exporter +// -- + +function _exportStringDiagnosticShallow( src ) +{ + return `{- ${_.entity.strType( src )} -}`; +} + +// -- +// container interface +// -- + +function _lengthOf( src ) +{ + return 0; +} + +// + +function _hasKey( src, key ) +{ + return false; +} + +// + +function _hasCardinal( src, cardinal ) +{ + return false; +} + +// + +function _keyWithCardinal( src, cardinal ) +{ + return [ undefined, false ]; +} + +// + +function _cardinalWithKey( key ) +{ + return -1; +} + +// + +function _elementWithKey( src, key ) +{ + return [ undefined, key, false ]; +} + +// + +function _elementWithCardinal( src, cardinal ) +{ + return [ undefined, cardinal, false ]; +} + +// + +function _elementWithKeySet( dst, key, val ) +{ + return [ key, false ]; +} + +// + +function _elementWithCardinalSet( dst, cardinal, val ) +{ + return [ cardinal, false ]; +} + +// + +function _elementWithKeyDel( dst, key ) +{ + _.assert( 0, `Cant delete element of ${this.NamespaceName}` ); + return false; +} + +// + +function _elementWithCardinalDel( dst, cardinal ) +{ + _.assert( 0, `Cant delete element of ${this.NamespaceName}` ); + return false; +} + +// + +function _empty( dst ) +{ + _.assert( 0, `Cant empty ${this.NamespaceName}` ); + return dst; +} + +// + +function _eachLeft( src, onEach ) +{ +} + +// + +function _eachRight( src, onEach ) +{ +} + +// + +function _whileLeft( src, onEach ) +{ + return [ undefined, undefined, -1, true ]; +} + +// + +function _whileRight( src, onEach ) +{ + return [ undefined, undefined, -1, true ]; +} + +// -- +// extension +// -- + +let BlankExtension = +{ + + // equaler + + _identicalShallow, + identicalShallow : _.props.identicalShallow, + identical : _.props.identical, + _equivalentShallow : _identicalShallow, + equivalentShallow : _.props.equivalentShallow, + equivalent : _.props.equivalent, + + // exporter + + _exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.props.exportStringDiagnosticShallow, + _exportStringCodeShallow : _exportStringDiagnosticShallow, + exportStringCodeShallow : _.props.exportStringCodeShallow, + exportString : _.props.exportString, + + // inspector + + _lengthOf, + lengthOf : _.props.lengthOf, /* qqq : cover */ + _hasKey, + hasKey : _.props.hasKey, /* qqq : cover */ + _hasCardinal, + hasCardinal : _.props.hasCardinal, /* qqq : cover */ + _keyWithCardinal, + keyWithCardinal : _.props.keyWithCardinal, /* qqq : cover */ + _cardinalWithKey, + cardinalWithKey : _.props.cardinalWithKey, /* qqq : cover */ + + // elementor + + _elementGet : _elementWithKey, + elementGet : _.props.elementGet, /* qqq : cover */ + _elementWithKey, + elementWithKey : _.props.elementWithKey, /* qqq : cover */ + _elementWithImplicit : _.props._elementWithImplicit, + elementWithImplicit : _.props.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal, + elementWithCardinal : _.props.elementWithCardinal, /* qqq : cover */ + + _elementSet : _elementWithKeySet, + elementSet : _.props.elementSet, /* qqq : cover */ + _elementWithKeySet, + elementWithKeySet : _.props.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet, + elementWithCardinalSet : _.props.elementWithCardinalSet, /* qqq : cover */ + + _elementDel : _elementWithKeyDel, + elementDel : _.props.elementDel, /* qqq : cover */ + _elementWithKeyDel, + elementWithKeyDel : _.props.elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel, + elementWithCardinalDel : _.props.elementWithCardinalDel, /* qqq : cover */ + _empty, + empty : _.props.empty, /* qqq : for junior : cover */ + + // iterator + + _each : _eachLeft, + each : _.props.each, /* qqq : cover */ + _eachLeft, + eachLeft : _.props.eachLeft, /* qqq : cover */ + _eachRight, + eachRight : _.props.eachRight, /* qqq : cover */ + + _while : _whileLeft, + while : _.props.while, /* qqq : cover */ + _whileLeft, + whileLeft : _.props.whileLeft, /* qqq : cover */ + _whileRight, + whileRight : _.props.whileRight, /* qqq : cover */ + + _aptLeft : _.props._aptLeft, + aptLeft : _.props.aptLeft, /* qqq : cover */ + first : _.props.first, + _aptRight : _.props._aptRight, /* qqq : cover */ + aptRight : _.props.aptRight, + last : _.props.last, /* qqq : cover */ + + _filterAct0 : _.props._filterAct0, + _filterAct : _.props._filterAct, + filterWithoutEscapeLeft : _.props.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.props.filterWithoutEscapeRight, + filterWithoutEscape : _.props.filterWithoutEscape, + filterWithEscapeLeft : _.props.filterWithEscapeLeft, + filterWithEscapeRight : _.props.filterWithEscapeRight, + filterWithEscape : _.props.filterWithEscape, + filter : _.props.filter, + + _mapAct0 : _.props._mapAct0, + _mapAct : _.props._mapAct, + mapWithoutEscapeLeft : _.props.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.props.mapWithoutEscapeRight, + mapWithoutEscape : _.props.mapWithoutEscape, + mapWithEscapeLeft : _.props.mapWithEscapeLeft, + mapWithEscapeRight : _.props.mapWithEscapeRight, + mapWithEscape : _.props.mapWithEscape, + map : _.props.map, + +} + +Object.assign( _.blank, BlankExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/3Blank.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, _3Blank_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file _3Blank_s */ })(); + +/* */ /* begin of file _3Long_s */ ( function _3Long_s() { function _3Long_s_naked() { ( function _l3_Long_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const _functor_functor = _.container._functor_functor; + +_.long = _.long || Object.create( null ); + +// -- +// +// -- + +function appender( src ) +{ + _.assert( _.longLike( src ) ); + + if( 'append' in src && _.routine.is( src.append ) ) + return appendWithAppend; + else if( 'push' in src && _.routine.is( src.push ) ) + return appendWithPush; + else if( 'add' in src && _.routine.is( src.add ) ) + return appendWithAdd; + + function appendWithAppend( val ) + { + src.append( val ); + } + + function appendWithPush( val ) + { + src.push( val ); + } + + function appendWithAdd( val ) + { + src.add( val ); + } + +} + +// + +function prepender( src ) +{ + _.assert( _.longLike( src ) ); + + if( 'prepend' in src && _.routine.is( src.prepend ) ) + return prependWithAppend; + else if( 'push' in src && _.routine.is( src.push ) ) + return prependWithPush; + else if( 'add' in src && _.routine.is( src.add ) ) + return prependWithAdd; + + function prependWithAppend( val ) + { + src.prepend( val ); + } + + function prependWithPush( val ) + { + src.unshift( val ); + } + + function prependWithAdd( val ) + { + src.add( val ); + } + +} + +// + +function eacher( src ) +{ + + _.assert( _.longLike( src ) ); + + if( _.class.methodIteratorOf( src ) ) + return eachOf; + else + return eachLength; + + /* */ + + function eachOf( onEach ) + { + let k = 0; + for( let val of src ) + { + onEach( val, k, src ); + k += 1; + } + return k; + } + + /* */ + + function eachLength( onEach ) + { + let k = 0; + while( k < src.length ) + { + let val = src[ k ]; + args2[ 0 ] = val; + onEach( val, k, src ); + k += 1; + } + return k; + } + + /* */ + +} + +// -- +// equaler +// -- + +/** + * The long.identicalShallow() routine checks the equality of two arrays. + * + * @param { longLike } src1 - The first array. + * @param { longLike } src2 - The second array. + * + * @example + * _.long.identicalShallow( [ 1, 2, 3 ], [ 1, 2, 3 ] ); + * // returns true + * + * @returns { Boolean } - Returns true if all values of the two arrays are equal. Otherwise, returns false. + * @function long.identicalShallow + * @throws { Error } Will throw an Error if (arguments.length) is less or more than two. + * @namespace Tools + */ + +// + +function _identicalShallow( src1, src2 ) +{ + let result = true; + + if( src1.length !== src2.length ) + return false; + + for( let s = 0 ; s < src1.length ; s++ ) + { + result = src1[ s ] === src2[ s ]; + if( result === false ) + return false; + } + + return result; +} + +// -- +// exporter +// -- + +function _exportStringDiagnosticShallow( src ) +{ + if( _.unroll.is( src ) ) + return `{- ${_.entity.strType( src )}.unroll with ${this._lengthOf( src )} elements -}`; + return `{- ${_.entity.strType( src )} with ${this._lengthOf( src )} elements -}`; +} + +// -- +// inspector +// -- + +function _lengthOf( src ) +{ + return src.length; +} + +// + +function lengthOf( src ) +{ + _.assert( arguments.length === 1 ); + _.assert( this.like( src ) ); + return this._lengthOf( src ); +} + +// + +function _hasKey( src, key ) +{ + if( key < 0 ) + return false; + return key < src.length; +} + +// + +function hasKey( src, key ) +{ + _.assert( this.like( src ) ); + return this._hasKey( src, key ); +} + +// + +function _hasCardinal( src, cardinal ) +{ + if( cardinal < 0 ) + return false; + return cardinal < src.length; +} + +// + +function hasCardinal( src, cardinal ) +{ + _.assert( this.like( src ) ); + return this._hasCardinal( src, cardinal ); +} + +// + +function _keyWithCardinal( src, cardinal ) +{ + if( cardinal < 0 || src.length <= cardinal ) + return [ undefined, false ]; + return [ cardinal, true ] +} + +// + +function keyWithCardinal( src, cardinal ) +{ + _.assert( this.like( src ) ); + return this._keyWithCardinal( src, cardinal ); +} + +// + +function _cardinalWithKey( src, key ) +{ + if( key < 0 || src.length <= key ) + return -1; + return key; +} + +// + +function cardinalWithKey( src, key ) +{ + _.assert( this.like( src ) ); + return this._cardinalWithKey( src, key ); +} + +// -- +// elementor +// -- + +function _elementWithKey( src, key ) +{ + if( key < 0 || src.length <= key || !_.numberIs( key ) ) + return [ undefined, key, false ]; + else + return [ src[ key ], key, true ]; +} + +// + +function elementWithKey( src, key ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + return this._elementWithKey( src, key ); +} + +// + +function _elementWithImplicit( src, key ) +{ + if( _.props.keyIsImplicit( key ) ) + return _.props._onlyImplicitWithKeyTuple( src, key ); + return this._elementWithKey( src, key ); +} + +// + +function elementWithImplicit( src, key ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + return this._elementWithImplicit( src, key ); +} + +// + +function _elementWithCardinal( src, cardinal ) +{ + if( cardinal < 0 || src.length <= cardinal || !_.numberIs( cardinal ) ) + return [ undefined, cardinal, false ]; + else + return [ src[ cardinal ], cardinal, true ]; +} + +// + +function elementWithCardinal( src, cardinal ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + return this._elementWithCardinal( src, cardinal ); +} + +// + +function _elementWithKeySet( dst, key, val ) +{ + if( _.long.isResizable( dst ) ) + { + if( key < 0 || !_.numberIs( key ) ) + return [ key, false ]; + } + else + { + if( key < 0 || dst.length <= key || !_.numberIs( key ) ) + return [ key, false ]; + } + dst[ key ] = val; + return [ key, true ]; +} + +// + +function elementWithKeySet( dst, key, val ) +{ + _.assert( arguments.length === 3 ); + _.assert( this.is( dst ) ); + return this._elementWithKeySet( dst, key, val ); +} + +// + +function _elementWithCardinalSet( dst, cardinal, val ) +{ + if( cardinal < 0 || dst.length <= cardinal || !_.numberIs( cardinal ) ) + return [ cardinal, false ]; + dst[ cardinal ] = val; + return [ cardinal, true ]; +} + +// + +function elementWithCardinalSet( dst, cardinal, val ) +{ + _.assert( arguments.length === 3 ); + _.assert( this.is( dst ) ); + return this._elementWithCardinalSet( dst, cardinal, val ); +} + +// -- +// container interface +// -- + +function _elementAppend( dst, val ) +{ + dst.push( val ); + return dst.length-1; +} + +// + +function elementAppend( dst, val ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( dst ) ); + _.assert( this.isResizable( dst ) ); + return this._elementAppend( dst, val ); +} + +// + +function _elementPrepend( dst, val ) +{ + dst.unshift( val ); + return 0; +} + +// + +function elementPrepend( dst, val ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( dst ) ); + _.assert( this.isResizable( dst ) ); + return this._elementPrepend( dst, val ); +} + +// + +function _elementWithKeyDel( dst, key ) +{ + if( !this._hasKey( dst, key ) ) + return false; + dst.splice( key, 1 ); + return true; +} + +// + +function elementWithKeyDel( dst, key ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( dst ) ); + _.assert( this.isResizable( dst ) ); + return this._elementWithKeyDel( dst, key ); +} + +// + +function _elementWithCardinalDel( dst, cardinal ) +{ + if( !this._hasKey( dst, cardinal ) ) + return false; + dst.splice( cardinal, 1 ); + return true; +} + +// + +function elementWithCardinalDel( dst, cardinal ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( dst ) ); + _.assert( this.isResizable( dst ) ); + return this._elementWithCardinalDel( dst, cardinal, val ); +} + +// + +function _empty( dst ) +{ + dst.splice( 0, dst.length ); + return dst; +} + +// + +function empty( dst ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( this.like( dst ) ); + _.assert( this.isResizable( dst ) ); + return this._empty( dst ); +} + +// -- +// iterator +// -- + +function _eachLeft( src, onEach ) +{ + for( let k = 0 ; k < src.length ; k++ ) + { + onEach( src[ k ], k, k, src ); + } +} + +// + +function eachLeft( src, onEach ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + this._eachLeft( src, onEach ); +} + +// + +function _eachRight( src, onEach ) +{ + for( let k = src.length-1 ; k >= 0 ; k-- ) + { + onEach( src[ k ], k, k, src ); + } +} + +// + +function eachRight( src, onEach ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + this._eachRight( src, onEach ); +} + +// + +function _whileLeft( src, onEach ) +{ + for( let k = 0 ; k < src.length ; k++ ) + { + let r = onEach( src[ k ], k, k, src ); + _.assert( r === true || r === false ); + if( r === false ) + return [ src[ k ], k, k, false ]; + } + let k = src.length-1; + if( src.length > 0 ) + return [ src[ k ], k, k, true ]; + else + return [ undefined, k, k, true ]; +} + +// + +function whileLeft( src, onEach ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + this._whileLeft( src, onEach ); +} + +// + +function _whileRight( src, onEach ) +{ + for( let k = src.length-1 ; k >= 0 ; k-- ) + { + let r = onEach( src[ k ], k, k, src ); + _.assert( r === true || r === false ); + if( r === false ) + return [ src[ k ], k, k, false ]; + } + if( src.length > 0 ) + return [ src[ 0 ], 0, 0, true ]; + else + return [ undefined, -1, -1, true ]; +} + +// + +function whileRight( src, onEach ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + this._whileRight( src, onEach ); +} + +// + +function _filterAct( ... args ) +{ + const self = this; + let dst = arguments[ 0 ]; + const src = arguments[ 1 ]; + const onEach = arguments[ 2 ]; + const isLeft = arguments[ 3 ]; + const eachRoutineName = arguments[ 4 ]; + const escape = arguments[ 5 ]; + const srcNamesapce = this.tools[ this.MostGeneralNamespaceName ].namespaceOf( src ); + let dstNamespace; + const each = srcNamesapce[ eachRoutineName ]; + let isSelf; + let dstIsResizable; + let srcSample = null; + + if( dst === null ) + { + dstNamespace = self.namespaceOf( src ) || self.default || self; + isSelf = false; + if( dstNamespace.IsResizable() ) + { + if( dstNamespace.is( src ) && !_.countable.isResizable( src ) ) + { + srcSample = src; + dstIsResizable = false; + } + else + { + dst = dstNamespace.makeEmpty( src ); + dstIsResizable = true; + } + } + else + { + dstIsResizable = false; + } + } + else if( dst === _.self ) + { + isSelf = true; + dst = src; + dstNamespace = self.namespaceWithDefaultOf( dst ); + dstIsResizable = _.countable.isResizable( dst ); + } + else + { + dstNamespace = self.namespaceWithDefaultOf( dst ); + dstIsResizable = _.countable.isResizable( dst ); + isSelf = dst === src; + if( dstIsResizable ) + if( !isSelf ) + dstNamespace._empty( dst ); + } + + if( Config.debug ) + verify(); + + if( dstIsResizable ) + { + + if( isSelf ) + { + if( isLeft ) + resizableSelfLeft(); + else + resizableSelfRight(); + } + else + { + resizableNonEq(); + } + + } + else + { + + if( dst === null ) + nonResizableNull() + else + nonResizableNonNull(); + + } + + return dst; + + function resizableSelfLeft() + { + let l = dstNamespace._lengthOf( src ); + for( let k = 0 ; k < l ; k++ ) + { + let val = src[ k ]; + let val2 = onEach( val, k, k, src, dst ); + if( val2 === undefined ) + { + dstNamespace._elementDel( dst, k ); + k -= 1; + l -= 1; + continue; + } + let val3 = escape( val2 ); + if( val3 === val ) + continue; + dstNamespace._elementSet( dst, k, val3 ); + } + } + + function resizableSelfRight() + { + each.call( srcNamesapce, src, function( val, k, c, src2 ) + { + let val2 = onEach( val, k, c, src2, dst ); + let val3 = escape( val2 ); + if( val2 === undefined ) + dstNamespace._elementDel( dst, k ); + else if( val3 === val ) + return; + else + dstNamespace._elementSet( dst, k, val3 ); + }); + } + + function resizableNonEq() + { + const append = isLeft ? dstNamespace._elementAppend : dstNamespace._elementPrepend; + each.call( srcNamesapce, src, function( val, k, c, src2 ) + { + let val2 = onEach( val, k, c, src2, dst ); + let val3 = escape( val2 ); + if( val2 === undefined ) + return; + append.call( dstNamespace, dst, val3 ); + }); + } + + function nonResizableNull() + { + let dst2 = []; + if( isLeft ) + each.call( srcNamesapce, src, function( val, k, c, src2 ) + { + let val2 = onEach( val, k, c, src2, dst2 ); + let val3 = escape( val2 ); + if( val2 === undefined ) + return; + dst2.push( val3 ); + }); + else + each.call( srcNamesapce, src, function( val, k, c, src2 ) + { + let val2 = onEach( val, k, c, src2, dst2 ); + let val3 = escape( val2 ); + if( val2 === undefined ) + return; + dst2.unshift( val3 ); + }); + dst = dstNamespace.make( srcSample, dst2 ); + } + + function nonResizableNonNull() + { + each.call( srcNamesapce, src, function( val, k, c, src2 ) + { + let val2 = onEach( val, k, c, src2, dst ); + let val3 = escape( val2 ); + if( val2 === undefined ) + return; + dstNamespace._elementSet( dst, k, val3 ); + }); + } + + function verify() + { + _.assert( args.length === 6, `Expects 3 arguments` ); + _.assert( dst === null || self.is( dst ), () => `dst is not ${self.TypeName}` ); + _.assert( srcNamesapce.is( src ), () => `src is not ${srcNamesapce.TypeName}` ); + _.assert( _.routineIs( onEach ), () => `onEach is not a routine` ); + _.assert + ( + dst === null || _.countable.isResizable( dst ) || self._lengthOf( dst ) === srcNamesapce._lengthOf( src ) + , () => `dst is ${self.TypeName} and lengthOf( dst ) is ${self._lengthOf( dst )}, but lengthOf( src ) is ${self._lengthOf( src )}` + ); + } + +} + +// + +function _mapAct( ... args ) +{ + const self = this; + let dst = arguments[ 0 ]; + const src = arguments[ 1 ]; + const onEach = arguments[ 2 ]; + const isLeft = arguments[ 3 ]; + const eachRoutineName = arguments[ 4 ]; + const escape = arguments[ 5 ]; + const srcNamesapce = this.tools[ this.MostGeneralNamespaceName ].namespaceOf( src ); + const each = srcNamesapce[ eachRoutineName ]; + let isSelf; + let dstIsResizable; + let dstNamespace; + + if( dst === null ) + { + isSelf = false; + dstNamespace = self.namespaceOf( src ) || self.default || self; + dst = dstNamespace.makeUndefined( src ); + dstIsResizable = self.IsResizable(); + } + else if( dst === _.self ) + { + isSelf = true; + dst = src; + dstNamespace = self.namespaceWithDefaultOf( dst ); + dstIsResizable = _.countable.isResizable( dst ); + } + else + { + dstNamespace = self.namespaceWithDefaultOf( dst ); + dstIsResizable = _.countable.isResizable( dst ); + isSelf = dst === src; + if( dstIsResizable ) + if( !isSelf ) + dst.length = srcNamesapce._lengthOf( src ); + } + + // const dstNamespace = self.namespaceWithDefaultOf( dst ); + + if( Config.debug ) + verify(); + + if( dst === src ) + each.call( srcNamesapce, src, function( val, k, c, src2 ) + { + let val2 = onEach( val, k, c, src2, dst ); + let val3 = escape( val2 ); + if( val3 === val || val2 === undefined ) + return; + self._elementSet( dst, k, val3 ); + }); + else + each.call( srcNamesapce, src, function( val, k, c, src2 ) + { + let val2 = onEach( val, k, c, src2, dst ); + let val3 = escape( val2 ); + if( val2 === undefined ) + self._elementSet( dst, k, val ); + else + self._elementSet( dst, k, val3 ); + }); + + return dst; + + function verify() + { + _.assert( args.length === 6, `Expects 3 arguments` ); + _.assert( dst === null || self.is( dst ), () => `dst is not ${self.TypeName}` ); + _.assert( srcNamesapce.is( src ), () => `src is not ${srcNamesapce.TypeName}` ); + _.assert( _.routineIs( onEach ), () => `onEach is not a routine` ); + _.assert + ( + dst === null || _.countable.isResizable( dst ) || self._lengthOf( dst ) === srcNamesapce._lengthOf( src ) + , () => `dst is ${self.TypeName} and lengthOf( dst ) is ${self._lengthOf( dst )}, but lengthOf( src ) is ${self._lengthOf( src )}` + ); + } + +} + +// -- +// declare +// -- + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +// + +let LongExtension = +{ + + // er + + /* qqq : ask */ + /* xxx : evolve */ + appender, + prepender, + eacher, + + // equaler + + _identicalShallow, + identicalShallow : _.props.identicalShallow, + identical : _.props.identical, + _equivalentShallow : _identicalShallow, + equivalentShallow : _.props.equivalentShallow, + equivalent : _.props.equivalent, + + // exporter + + _exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.props.exportStringDiagnosticShallow, + _exportStringCodeShallow : _exportStringDiagnosticShallow, + exportStringCodeShallow : _.props.exportStringCodeShallow, + exportString : _.props.exportString, + + // inspector + + _lengthOf, + lengthOf, /* qqq : cover */ + _hasKey, + hasKey, /* qqq : cover */ + _hasCardinal, + hasCardinal, /* qqq : cover */ + _keyWithCardinal, + keyWithCardinal, /* qqq : cover */ + _cardinalWithKey, + cardinalWithKey, /* qqq : cover */ + + // elementor + + _elementGet : _elementWithKey, + elementGet : elementWithKey, /* qqq : cover */ + _elementWithKey, + elementWithKey, /* qqq : cover */ + _elementWithImplicit, + elementWithImplicit, /* qqq : cover */ + _elementWithCardinal, + elementWithCardinal, /* qqq : cover */ + + _elementSet : _elementWithKeySet, + elementSet : elementWithKeySet, /* qqq : cover */ + _elementWithKeySet, + elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet, + elementWithCardinalSet, /* qqq : cover */ + + _elementAppend, + elementAppend, /* qqq : cover */ + _elementPrepend, + elementPrepend, /* qqq : cover */ + + _elementWithKeyDel, + elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel, + elementWithCardinalDel, /* qqq : cover */ + _elementDel : _elementWithKeyDel, + elementDel : _elementWithKeyDel, /* qqq : cover */ + _empty, + empty, /* qqq : cover */ + + // iterator + + _each : _eachLeft, + each : eachLeft, /* qqq : cover */ + _eachLeft, + eachLeft, /* qqq : cover */ + _eachRight, + eachRight, /* qqq : cover */ + + _while : _whileLeft, + while : whileLeft, /* qqq : cover */ + _whileLeft, + whileLeft, /* qqq : cover */ + _whileRight, + whileRight, /* qqq : cover */ + + _aptLeft : _.props._aptLeft, + aptLeft : _.props.aptLeft, /* qqq : cover */ + first : _.props.first, + _aptRight : _.props._aptRight, /* qqq : cover */ + aptRight : _.props.aptRight, + last : _.props.last, /* qqq : cover */ + + _filterAct, + filterWithoutEscapeLeft : _.props.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.props.filterWithoutEscapeRight, + filterWithoutEscape : _.props.filterWithoutEscape, + filterWithEscapeLeft : _.props.filterWithEscapeLeft, + filterWithEscapeRight : _.props.filterWithEscapeRight, + filterWithEscape : _.props.filterWithEscape, + filter : _.props.filter, + + _mapAct, + mapWithoutEscapeLeft : _.props.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.props.mapWithoutEscapeRight, + mapWithoutEscape : _.props.mapWithoutEscape, + mapWithEscapeLeft : _.props.mapWithEscapeLeft, + mapWithEscapeRight : _.props.mapWithEscapeRight, + mapWithEscape : _.props.mapWithEscape, + map : _.props.map, + +} + +// + +Object.assign( _.long, LongExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/3Long.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, _3Long_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file _3Long_s */ })(); + +/* */ /* begin of file _3Path_s */ ( function _3Path_s() { function _3Path_s_naked() { ( function _l3_Path_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.path; + +// -- +// meta +// -- + +function Init() +{ + let self = this; + + _.assert( _.strIs( self.rootToken ) ); + _.assert( _.strIs( self.upToken ) ); + _.assert( _.strIs( self.hereToken ) ); + _.assert( _.strIs( self.downToken ) ); + + if( !self.downUpToken ) + self.downUpToken = self.downToken + self.upToken; /* ../ */ + if( !self.hereUpToken ) + self.hereUpToken = self.hereToken + self.upToken; /* ./ */ + + let root = _.regexpEscape( self.rootToken ); + let up = _.regexpEscape( self.upToken ); + let down = _.regexpEscape( self.downToken ); + let here = _.regexpEscape( self.hereToken ); + + let beginOrChar = '(?:.|^)'; + let butUp = `(?:(?!${up}).)+`; + let notDownUp = `(?!${down}(?:${up}|$))`; + let upOrBegin = `(?:^|${up})`; + let upOrEnd = `(?:${up}|$)`; + let splitOrUp = `(?:(?:${up}${up})|((${upOrBegin})${notDownUp}${butUp}${up}))`; /* split or / */ + + self._delDownRegexp = new RegExp( `(${beginOrChar})${splitOrUp}${down}(${upOrEnd})`, '' ); + self._delHereRegexp = new RegExp( up + here + '(' + up + '|$)' ); + self._delUpDupRegexp = /\/{2,}/g; + +} + +// + +function CloneExtending( o ) +{ + _.assert( arguments.length === 1 ); + let result = Object.create( this ) + _.props.extend( result, Parameters, o ); + result.Init(); + return result; +} + +// -- +// dichotomy +// -- + +function is( path ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + return _.strIs( path ); +} + +// + +/** + * Checks if string path is refined ( checks that the string doesn´t contain left( \\ ) or double slashes ( // ) ), and it also + * returns true when the path has slash ( / ) in the end . + * @param {String} filePath Source path for check + * @returns {boolean} + * @function isRefined + * @namespace Tools.path + */ + +function isRefined( path ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( path ), 'Expects string {-path-}, but got', _.entity.strType( path ) ); + + if( path[ 1 ] === ':' && path[ 2 ] === '\\' ) + return false; + + let leftSlash = /\\/g; + let doubleSlash = /\/\//g; + + if( leftSlash.test( path ) ) + return false; + + return true; +} + +// + +/** + * Checks if string path is normalized, and maybe trailed ( ends with a slash ( / ) ). + * @param {String} filePath Source path for check + * @returns {boolean} + * @function isNormalized + * @namespace Tools.path + */ + +function isNormalized( filePath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), 'Expects string' ); + let normalizedPath = this.normalize( filePath ) + let trailedPath = this.trail( normalizedPath ); + return normalizedPath === filePath || trailedPath === filePath; +} + +// + +function isAbsolute( filePath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), 'Expects string {-filePath-}, but got', _.entity.strType( filePath ) ); + filePath = this.refine( filePath ); + return _.strBegins( filePath, this.upToken ); +} + +// + +function isRelative( filePath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), 'Expects string {-filePath-}, but got', _.entity.strType( filePath ) ); + return !this.isAbsolute( filePath ); +} + +// + +function isGlobal( filePath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), 'Expects string' ); + return _.strHas( filePath, '://' ); +} + +// + +function isRoot( filePath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), 'Expects string {-filePath-}, but got', _.entity.strType( filePath ) ); + if( filePath === this.rootToken ) + return true; + if( this.isRelative( filePath ) ) + return false; + if( this.normalize( filePath ) === this.rootToken ) + return true; + return false; +} + +// + +function _isDotted( srcPath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + if( srcPath === this.hereToken ) + return true; + if( srcPath === this.downToken ) + return true; + if( _.strBegins( srcPath, this.hereToken + this.upToken ) ) + return true; + if( _.strBegins( srcPath, this.downToken + this.upToken ) ) + return true; + return false; +} + +// + +function isDotted( srcPath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + if( this._isDotted( srcPath ) ) + return true; + if( _.strBegins( srcPath, this.hereToken + '\\' ) ) + return true; + if( _.strBegins( srcPath, this.downToken + '\\' ) ) + return true; + return false; +} + +// + +function isTrailed( srcPath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + if( srcPath === this.rootToken ) + return false; + return _.strEnds( srcPath, this.upToken ); +} + +// + +function begins( srcPath, beginPath ) +{ + _.assert( arguments.length === 2, 'Expects two arguments' ); + _.assert( _.strIs( srcPath ), 'Expects string {-srcPath-}, but got', _.entity.strType( srcPath ) ); + _.assert( _.strIs( beginPath ), 'Expects string {-beginPath-}, but got', _.entity.strType( beginPath ) ); + if( srcPath === beginPath ) + return true; + return _.strBegins( srcPath, this.trail( beginPath ) ); +} + +// + +function ends( srcPath, endPath ) +{ + _.assert( arguments.length === 2, 'Expects two arguments' ); + endPath = this.undot( endPath ); + + if( !_.strEnds( srcPath, endPath ) ) + return false; + + let begin = _.strRemoveEnd( srcPath, endPath ); + if( begin === '' || _.strEnds( begin, this.upToken ) || _.strEnds( begin, this.hereToken ) ) + return true; + + return false; +} + +// -- +// reformer +// -- + +/** + * The routine refine() regularize a Windows paths to posix path format by replacing left slashes to slash ( \\ to / ). + * If the path has a disk label, the routine puts slash '/' before and after the disk label. + * If the path is an empty string, method returns ''. Otherwise, routine returns original path. + * + * @param {string} src - path for refinement. + * + * @example + * // returns '/foo//bar/../'; + * let path = '\\foo\\\\bar\\..\\'; + * path = wTools.refine( path ); + * + * @example + * // returns '/C/temp//foo/bar/../'; + * let path = 'C:\\temp\\\\foo\\bar\\..\\'; + * path = wTools.refine( path ); + * + * @example + * // returns ''; + * let path = ''; + * path = wTools.refine( path ); + * + * @example + * // returns '/foo/bar/'; + * let path = '/foo/bar/'; + * path = wTools.refine( path ); + * + * @returns {string} Returns refined path. + * @throws {Error} If {-arguments.length-} is less or more then one. + * @throws {Error} If passed argument is not a string. + * @function refine + * @namespace Tools.path + */ + +function refine( src ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ) ); + + let result = src; + + if( result[ 1 ] === ':' ) + { + if( result[ 2 ] === '\\' || result[ 2 ] === '/' ) + { + if( result.length > 3 ) + result = '/' + result[ 0 ] + '/' + result.substring( 3 ); + else + result = '/' + result[ 0 ] + } + else if( result.length === 2 ) + { + result = '/' + result[ 0 ]; + } + } + + result = result.replace( /\\/g, '/' ); + + return result; +} + +// + +function _normalize( o ) +{ + // let debug = 0; + // if( 0 ) + // debug = 1; + + _.routine.assertOptions( _normalize, arguments ); + _.assert( _.strIs( o.src ), 'Expects string' ); + + if( !o.src.length ) + return ''; + + let result = o.src; + + result = this.refine( result ); + + // if( debug ) + // console.log( 'normalize.refined : ' + result ); + + /* detrailing */ + + if( o.tolerant ) + { + /* remove "/" duplicates */ + result = result.replace( this._delUpDupRegexp, this.upToken ); + } + + let endsWithUp = false; + let beginsWithHere = false; + + /* remove right "/" */ + + if( result !== this.upToken && !_.strEnds( result, this.upToken + this.upToken ) && _.strEnds( result, this.upToken ) ) + { + endsWithUp = true; + result = _.strRemoveEnd( result, this.upToken ); + } + + /* undoting */ + + while( !_.strBegins( result, this.hereUpToken + this.upToken ) && _.strBegins( result, this.hereUpToken ) ) + { + beginsWithHere = true; + result = _.strRemoveBegin( result, this.hereUpToken ); + } + + /* remove second "." */ + + if( result.indexOf( this.hereToken ) !== -1 ) + { + + while( this._delHereRegexp.test( result ) ) + result = result.replace( this._delHereRegexp, function( match, postSlash ) + { + return postSlash || ''; + }); + if( result === '' ) + result = this.upToken; + + } + + /* remove .. */ + + if( result.indexOf( this.downToken ) !== -1 ) + { + + while( this._delDownRegexp.test( result ) ) + result = result.replace( this._delDownRegexp, function( /* match, notBegin, split, preSlash, postSlash */ ) + { + let match = arguments[ 0 ]; + let notBegin = arguments[ 1 ]; + let split = arguments[ 2 ]; + let preSlash = arguments[ 3 ]; + let postSlash = arguments[ 4 ]; + + if( preSlash === '' ) + return notBegin; + if( !notBegin ) + return notBegin + preSlash; + else + return notBegin + ( postSlash || '' ); + }); + + } + + /* nothing left */ + + if( !result.length ) + result = '.'; + + /* dot and trail */ + + if( o.detrailing ) + if( result !== this.upToken && !_.strEnds( result, this.upToken + this.upToken ) ) + result = _.strRemoveEnd( result, this.upToken ); + + if( !o.detrailing && endsWithUp ) + if( result !== this.rootToken ) + result = result + this.upToken; + + if( !o.undoting && beginsWithHere ) + result = this._dot( result ); + + // if( debug ) + // console.log( 'normalize.result : ' + result ); + + return result; +} + +_normalize.defaults = +{ + src : null, + tolerant : false, + detrailing : false, + undoting : false, +} + +// + +/** + * Regularize a path by collapsing redundant delimeters and resolving '..' and '.' segments,so A//B,A/./B and + A/foo/../B all become A/B. This string manipulation may change the meaning of a path that contains symbolic links. + On Windows,it converts forward slashes to backward slashes. If the path is an empty string,method returns '.' + representing the current working directory. + * @example + let path = '/foo/bar//baz1/baz2//some/..' + path = wTools.normalize( path ); // /foo/bar/baz1/baz2 + * @param {string} src path for normalization + * @returns {string} + * @function normalize + * @namespace Tools.path + */ + +function normalize( src ) +{ + let result = this._normalize({ src, tolerant : false, detrailing : false, undoting : false }); + + _.assert( _.strIs( src ), 'Expects string' ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( result.lastIndexOf( this.upToken + this.hereToken + this.upToken ) === -1 ); + _.assert( !_.strEnds( result, this.upToken + this.hereToken ) ); + + if( Config.debug ) + { + let i = result.lastIndexOf( this.upToken + this.downToken + this.upToken ); + _.assert( i === -1 || !/\w/.test( result.substring( 0, i ) ) ); + } + + return result; +} + +// + +function normalizeTolerant( src ) +{ + _.assert( _.strIs( src ), 'Expects string' ); + + let result = this._normalize({ src, tolerant : true, detrailing : false, undoting : false }); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( result === this.upToken || _.strEnds( result, this.upToken ) || !_.strEnds( result, this.upToken + this.upToken ) ); + _.assert( result.lastIndexOf( this.upToken + this.hereToken + this.upToken ) === -1 ); + _.assert( !_.strEnds( result, this.upToken + this.hereToken ) ); + + if( Config.debug ) + { + _.assert( !this._delUpDupRegexp.test( result ) ); + } + + return result; +} + +// + +function canonize( src ) +{ + let result = this._normalize({ src, tolerant : false, detrailing : true, undoting : true }); + + _.assert( _.strIs( src ), 'Expects string' ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( result === this.upToken || _.strEnds( result, this.upToken + this.upToken ) || !_.strEnds( result, this.upToken ) ); + _.assert( result.lastIndexOf( this.upToken + this.hereToken + this.upToken ) === -1 ); + _.assert( !_.strEnds( result, this.upToken + this.hereToken ) ); + + if( Config.debug ) + { + let i = result.lastIndexOf( this.upToken + this.downToken + this.upToken ); + _.assert( i === -1 || !/\w/.test( result.substring( 0, i ) ) ); + } + + return result; +} + +// + +function canonizeTolerant( src ) +{ + _.assert( _.strIs( src ), 'Expects string' ); + + let result = this._normalize({ src, tolerant : true, detrailing : true, undoting : true }); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( result === this.upToken || _.strEnds( result, this.upToken ) || !_.strEnds( result, this.upToken + this.upToken ) ); + _.assert( result.lastIndexOf( this.upToken + this.hereToken + this.upToken ) === -1 ); + _.assert( !_.strEnds( result, this.upToken + this.hereToken ) ); + + if( Config.debug ) + { + _.assert( !this._delUpDupRegexp.test( result ) ); + } + + return result; +} + +// + +function _nativizeMinimalWindows( filePath ) +{ + let self = this; + + let result = filePath; + + result = result.replace( /\//g, '\\' ); + + if( result[ 0 ] === '\\' ) + if( result.length === 2 || result[ 2 ] === ':' || result[ 2 ] === '\\' ) + result = result[ 1 ] + ':' + result.substring( 2 ); + + if( result.length === 2 && result[ 1 ] === ':' ) + result = result + '\\'; + + return result; +} + +// + +function _nativizeWindows( filePath ) +{ + let self = this; + _.assert( _.strIs( filePath ), 'Expects string' ) ; + + let result = filePath; + + _.assert( _.routine.is( self.unescape ) ); + result = self.unescape( result ); /* xxx : remove from here */ + + result = self._nativizeMinimalWindows( result ); + + return result; +} + +// + +function _nativizeMinimalPosix( filePath ) +{ + let self = this; + let result = filePath; + return result; +} + +// + +function _nativizePosix( filePath ) +{ + let self = this; + let result = filePath; + _.assert( _.strIs( filePath ), 'Expects string' ); + _.assert( _.routine.is( self.unescape ) ); + result = self.unescape( result ); /* xxx : remove from here */ + return result; +} + +// + +function _nativizeEscapingWindows( filePath ) +{ + let self = this; + let unescapeResult = self._unescape( filePath ) + + let result = self._nativizeMinimalWindows( unescapeResult.unescaped ); + + if( unescapeResult.wasEscaped ) + result = filePath.replace( unescapeResult.unescaped, result ); + + return result; +} + +// + +function _nativizeEscapingPosix( filePath ) +{ + let self = this; + let result = filePath; + _.assert( _.strIs( filePath ), 'Expects string' ); + return result; +} + +// + +function nativize() +{ + if( _global.process && _global.process.platform === 'win32' ) + this.nativize = this._nativizeWindows; + else + this.nativize = this._nativizePosix; + return this.nativize.apply( this, arguments ); +} + +// + +function nativizeMinimal() +{ + if( _global.process && _global.process.platform === 'win32' ) + this.nativizeMinimal = this._nativizeMinimalWindows; + else + this.nativizeMinimal = this._nativizeMinimalPosix; + return this.nativizeMinimal.apply( this, arguments ); +} + +// + +function nativizeEscaping() +{ + if( _global.process && _global.process.platform === 'win32' ) + this.nativizeEscaping = this._nativizeEscapingWindows; + else + this.nativizeEscaping = this._nativizeEscapingPosix; + return this.nativizeEscaping.apply( this, arguments ); +} + +// // +// +// function escape( filePath ) +// { +// let self = this; +// let splits = self.split( filePath ); +// +// splits = splits.map( ( split ) => +// { +// +// { +// let i = 0; +// while( split[ i ] === '"' ) +// i += 1; +// if( i > 0 ) +// split = split.substring( 0, i ) + split; +// } +// +// { +// let i = split.length-1; +// while( split[ i ] === '"' ) +// i -= 1; +// if( i < split.length-1 ) +// split = split + split.substring( i+1, split.length ); +// } +// +// let left = _.strLeft_( split, self.escapeTokens ) +// if( left.entry ) +// return `"${split}"`; +// return split; +// +// }); +// +// return splits.join( self.upToken ); +// } + +// + +function _unescape( filePath ) +{ + let self = this; + // let splits = self.split( filePath ); + /* + cant use routine self.split because it normalizes path + */ + let splits = filePath.split( self.upToken ); + + let result = Object.create( null ); + result.wasEscaped = false; + + splits = splits.map( ( split ) => + { + + { + let i = 0; + while( split[ i ] === '"' ) + i += 1; + if( i > 0 ) + { + let c = i; + if( c % 2 === 1 ) + result.wasEscaped = true; + let c2 = Math.floor( ( c + 1 ) / 2 ); + split = split.substring( c2, split.length ); + } + } + + { + let i = split.length-1; + while( split[ i ] === '"' ) + i -= 1; + if( i < split.length-1 ) + { + let c = split.length - i - 1; + if( c % 2 === 1 ) + result.wasEscaped = true; + let c2 = Math.floor( ( c + 1 ) / 2 ); + split = split.substring( 0, split.length - c2 ); + } + } + + return split; + }); + + result.unescaped = splits.join( self.upToken ); + return result; +} + +// + +function unescape( filePath ) +{ + let self = this; + return self._unescape( filePath ).unescaped; +} + +/* qqq2 : implement test routine _nativizeWindows */ +/* qqq2 : implement test routine _nativizePosix */ + +/* qqq2 : implement routine _.path.unescape to transform: + +`"'some path'"` -> `'some path'` +`"some path"` -> `some path` +`""some path""` -> `"some path"` +`'"some path"'` -> `'"some path"'` +`'some path'` -> `'some path'` + +`some"-"path/t.txt` -> `some"-"path/t.txt` +`"some"-"path"/'t.txt'` -> `some"-"path/'t.txt'` + +*/ + +/* qqq2 : implement routine _.path.escape + +`"'some path'"` -> `""'some path'""` +`"some path"` -> `""some path""` +`""some path""` -> `"""some path"""` +`'"some path"'` -> `'"some path"'` +`'some path'` -> `'some path'` + +`#some'` -> `"#some"` +`so#me'` -> `"so#me"` +`some#'` -> `"some#"` + +`@some'` -> `"@some"` +`so@me'` -> `"so@me"` +`some@'` -> `"some@"` + +`?some'` -> `"?some"` +`so?me'` -> `"so?me"` +`some?'` -> `"some?"` + += + +`"#` -> `"""#"` +`"!` -> `""!` + +`"#"` -> `"""#"""` +`"!"` -> `""!""` + +`""#""` -> `"""""#"""""` +`""!""` -> `""""!""""` + +*/ + +/* qqq2 : implement routines _.path.nativizeWindows_ _.path.nativizePosix_ using code from _.path.nativize and _.path.escape +*/ + +// -- +// transformer +// -- + +function _split( path ) +{ + return path.split( this.upToken ); +} + +// + +function split( path ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( path ), 'Expects string' ) + let result = this._split( this.refine( path ) ); + return result; +} + +// + +function _dot( filePath ) +{ + + if( !this._isDotted( filePath ) ) + { + _.assert( !_.strBegins( filePath, this.upToken ) ); + filePath = this.hereUpToken + filePath; + } + + return filePath; +} + +// + +function dot( filePath ) +{ + + /* + cant use isAbsolute + */ + + _.assert( !_.strBegins( filePath, this.upToken ) ); + _.assert( arguments.length === 1 ); + + /* + not . + not begins with ./ + not .. + not begins with ../ + */ + + // if( filePath !== this.hereToken && !_.strBegins( filePath, this.hereUpToken ) && filePath !== this.downToken && !_.strBegins( filePath, this.downUpToken ) ) + if( !this.isDotted( filePath ) ) + { + _.assert( !_.strBegins( filePath, this.upToken ) ); + filePath = this.hereUpToken + filePath; + } + + return filePath; +} + +// + +function undot( filePath ) +{ + if( filePath === this.hereUpToken ) + return filePath + return _.strRemoveBegin( filePath, this.hereUpToken ); +} + +// + +function absolute( filePath ) +{ + return this.join( this.rootToken, filePath ); +} + +// + +function unabsolute( filePath ) +{ + return _.strRemoveBegin( filePath, this.rootToken ); +} + +// + +function trail( srcPath ) +{ + _.assert( this.is( srcPath ) ); + _.assert( arguments.length === 1 ); + + if( !_.strEnds( srcPath, this.upToken ) ) + return srcPath + this.upToken; + + return srcPath; +} + +// + +function detrail( path ) +{ + _.assert( this.is( path ) ); + _.assert( arguments.length === 1 ); + + if( path !== this.rootToken ) + return _.strRemoveEnd( path, this.upToken ); + + return path; +} + +// + +/** + * Returns the directory name of `path`. + * @example + * let path = '/foo/bar/baz/text.txt' + * wTools.dir( path ); // '/foo/bar/baz' + * @param {string} path path string + * @returns {string} + * @throws {Error} If argument is not string + * @function dir + * @namespace Tools.path + */ + +function dir_head( routine, args ) +{ + let o = args[ 0 ]; + + if( _.strIs( o ) ) + { + if( args.length === 2 ) + o = { filePath : args[ 0 ], depth : args[ 1 ] }; + else + o = { filePath : args[ 0 ] }; + } + + _.routine.options( routine, o ); + _.assert( args.length === 1 || args.length === 2 ); + _.assert( arguments.length === 2 ); + _.assert( _.intIs( o.depth ) ); + _.assert( _.strDefined( o.filePath ), 'Expects not empty string {- o.filePath -}' ); + + return o; +} + +function dir_body( o ) +{ + let self = this; + let isTrailed = this.isTrailed( o.filePath ); + + _.routine.assertOptions( dir_body, arguments ); + + if( o.first ) + o.filePath = this.normalize( o.filePath ); + else + o.filePath = this.canonize( o.filePath ); + + if( o.depth === 0 ) + { + return o.filePath; + } + else if( o.depth > 1 ) + { + for( let i = o.depth - 1; i >= 0; i-- ) + { + if + ( + o.filePath === this.rootToken || o.filePath === this.hereToken || o.filePath === this.downToken + || o.filePath === this.hereToken + this.upToken || o.filePath === this.downToken + this.upToken + || ( o.filePath.match( /\W{3}$/ ) && o.filePath.match( /\W{3}$/ )[ 0 ] === '/..' ) + || ( o.filePath.match( /\W{4}$/ ) && o.filePath.match( /\W{4}$/ )[ 0 ] === '/../' ) + ) + { + if( o.filePath[ o.filePath.length - 1 ] === '/' ) + o.filePath = o.filePath + this.downToken + ( o.first ? this.upToken : '' ); + else + o.filePath = o.filePath + this.upToken + this.downToken + ( o.first ? this.upToken : '' ); + } + else + { + if( o.filePath[ o.filePath.length - 1 ] === '/' ) + { + o.filePath = o.filePath.substring( 0, o.filePath.length - 1 ); + o.filePath = o.filePath.substring( 0, o.filePath.lastIndexOf( '/' ) + ( o.first ? 1 : 0 ) ); + if( o.filePath.length === 0 ) + o.filePath = '.'; + } + else + { + let indexOfSubstr = o.filePath.lastIndexOf( '/' ) === 0 && !o.first ? 1 : o.filePath.lastIndexOf( '/' ); + o.filePath = o.filePath.substring( 0, indexOfSubstr + ( o.first ? 1 : 0 ) ); + if( o.filePath.length === 0 ) + o.filePath = '.'; + } + } + } + + if( !o.first ) + o.filePath = _.path.canonize( o.filePath ); + + return o.filePath; + } + else + { + _.assert( o.depth > 0 ); + } + + if( o.first ) + if( isTrailed ) + return o.filePath; + + if( o.filePath === this.rootToken ) + { + return o.filePath + this.downToken + ( o.first ? this.upToken : '' ); + } + + if( _.strEnds( o.filePath, this.upToken + this.downToken ) || o.filePath === this.downToken ) + { + return o.filePath + this.upToken + this.downToken + ( o.first ? this.upToken : '' ); + } + + let i = o.filePath.lastIndexOf( this.upToken ); + + if( i === 0 ) + { + return this.rootToken; + } + + if( i === -1 ) + { + if( o.first ) + { + if( o.filePath === this.hereToken ) + return this.downToken + this.upToken; + else + return this.hereToken + this.upToken; + } + else + { + if( o.filePath === this.hereToken ) + return this.downToken + ( isTrailed ? this.upToken : '' ); + else + return this.hereToken + ( isTrailed ? this.upToken : '' ); + } + } + + let result; + + if( o.first ) + result = o.filePath.substr( 0, i + self.upToken.length ); + else + result = o.filePath.substr( 0, i ); + + if( !o.first ) + if( isTrailed ) + result = _.strAppendOnce( result, self.upToken ); + + _.assert( !!result.length ) + + return result; +} + +dir_body.defaults = +{ + filePath : null, + first : 0, + depth : 1, +} + +let dir = _.routine.uniteCloning( dir_head, dir_body ); +dir.defaults.first = 0; + +let dirFirst = _.routine.uniteCloning( dir_head, dir_body ); +dirFirst.defaults.first = 1; + +_.assert( !dir.defaults.first ); + +// + +/** + * Returns path name (file name). + * @example + * wTools.name( '/foo/bar/baz.asdf' ); // 'baz' + * @param {string|object} path|o Path string, or options + * @param {boolean} o.full if this parameter set to true method return name with extension. + * @returns {string} + * @throws {Error} If passed argument is not string + * @function name + * @namespace Tools.path + */ + +function name_head( routine, args ) +{ + let o = args[ 0 ]; + if( _.strIs( o ) ) + o = { path : o }; + + _.routine.options_( routine, o ); + _.assert( args.length === 1 ); + _.assert( arguments.length === 2 ); + _.assert( _.strIs( o.path ), 'Expects string {-o.path-}' ); + + return o; +} + +function name_body( o ) +{ + + if( _.strIs( o ) ) + o = { path : o }; + + _.routine.assertOptions( name_body, arguments ); + + o.path = this.canonize( o.path ); + + let i = o.path.lastIndexOf( '/' ); + if( i !== -1 ) + o.path = o.path.substr( i+1 ); + + if( !o.full ) + { + let i = o.path.lastIndexOf( '.' ); + if( i !== -1 ) o.path = o.path.substr( 0, i ); + } + + return o.path; +} + +name_body.defaults = +{ + path : null, + full : 0, +} + +let name = _.routine.uniteCloning( name_head, name_body ); +name.defaults.full = 0; + +let fullName = _.routine.uniteCloning( name_head, name_body ); +fullName.defaults.full = 1; + +// -- +// extension +// -- + +let Parameters = +{ + + rootToken : '/', + upToken : '/', + hereToken : '.', + downToken : '..', + hereUpToken : null, /* ./ */ + downUpToken : null, /* ../ */ + escapeTokens : [ '@', '#', '!', '?' ], + + _delHereRegexp : null, + _delDownRegexp : null, + _delUpDupRegexp : null, + _pathIsGlobRegexp : null, + +} + +let Extension = +{ + + // meta + + Init, + CloneExtending, + + // dichotomy + + is, + + isRefined, + isNormalized, + isAbsolute, + isRelative, + isGlobal, + isRoot, + _isDotted, + isDotted, + isTrailed, + + begins, + ends, + + // reformer + + refine, + + _normalize, + normalize, + normalizeTolerant, + + canonize, + canonizeTolerant, + + _nativizeMinimalWindows, + _nativizeWindows, + _nativizeMinimalPosix, + _nativizePosix, + _nativizeEscapingWindows, + _nativizeEscapingPosix, + nativize, + nativizeMinimal, + nativizeEscaping, + + // escape, + _unescape, + unescape, + + // transformer + + _split, + split, + _dot, + dot, + undot, + absolute, /* qqq : cover */ + unabsolute, + trail, + detrail, + dir, + dirFirst, + name, + fullName, + + // fields + + Parameters, + + fileProvider : null, + path : Self, + single : Self, + s : null, + +} + +Object.assign( Self, Parameters ); +Object.assign( Self, Extension ); + +Self.Init(); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/3Path.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, _3Path_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file _3Path_s */ })(); + +/* */ /* begin of file ArgumentsArray_s */ ( function ArgumentsArray_s() { function ArgumentsArray_s_naked() { ( function _l3_ArgumentsArray_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( !!_.long._aptLeft, 'Expects routine props._aptLeft' ); +_.assert( !!_.long._elementWithKey, 'Expects routine long._elementWithKey' ); + +// -- +// elementor +// -- + +function _elementAppend( dst, val ) +{ + return -1; +} + +// + +function elementAppend( dst, val ) +{ + _.assert( 0, `${this.TypeName} has fixed length` ); +} + +// + +function _elementPrepend( dst, val ) +{ + return -1; +} + +// + +function elementPrepend( dst, val ) +{ + _.assert( 0, `${this.TypeName} has fixed length` ); +} + +// + +function _elementWithKeyDel( src, key ) +{ + _.assert( 0, `${this.TypeName} has fixed length` ); + return false; +} + +// + +function _elementWithCardinalDel( src, cardinal ) +{ + _.assert( 0, `${this.TypeName} has fixed length` ); + return false; +} + +// + +function _empty( dst ) +{ + _.assert( 0, `${this.TypeName} has fixed length` ); + return false; +} + +// -- +// extension +// -- + +var ArgumentsArrayExtension = +{ + + // equaler + + _identicalShallow : _.long._identicalShallow, + identicalShallow : _.long.identicalShallow, + identical : _.long.identical, + _equivalentShallow : _.long._equivalentShallow, + equivalentShallow : _.long.equivalentShallow, + equivalent : _.long.equivalent, + + // exporter + + _exportStringDiagnosticShallow : _.long._exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.long.exportStringDiagnosticShallow, + _exportStringCodeShallow : _.long._exportStringCodeShallow, + exportStringCodeShallow : _.long.exportStringCodeShallow, + exportString : _.long.exportString, + + // container interface + + _lengthOf : _.long._lengthOf, + lengthOf : _.long.lengthOf, /* qqq : cover */ + + _hasKey : _.long._hasKey, + hasKey : _.long._hasKey, /* qqq : cover */ + _hasCardinal : _.long._hasKey, + hasCardinal : _.long._hasKey, /* qqq : cover */ + _keyWithCardinal : _.long._hasKey, + keyWithCardinal : _.long._hasKey, /* qqq : cover */ + _cardinalWithKey : _.long._cardinalWithKey, + cardinalWithKey : _.long.cardinalWithKey, /* qqq : cover */ + + _elementGet : _.long._elementWithKey, + elementGet : _.long.elementWithKey, /* qqq : cover */ + _elementWithKey : _.long._elementWithKey, + elementWithKey : _.long.elementWithKey, /* qqq : cover */ + _elementWithImplicit : _.long._elementWithImplicit, + elementWithImplicit : _.long.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal : _.long._elementWithCardinal, + elementWithCardinal : _.long.elementWithCardinal, /* qqq : cover */ + + _elementSet : _.long._elementSet, + elementSet : _.long.elementSet, /* qqq : cover */ + _elementWithKeySet : _.long._elementWithKeySet, + elementWithKeySet : _.long.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet : _.long._elementWithCardinalSet, + elementWithCardinalSet : _.long.elementWithCardinalSet, /* qqq : cover */ + + _elementAppend, + elementAppend, /* qqq : cover */ + _elementPrepend, + elementPrepend, /* qqq : cover */ + + _elementDel : _elementWithKeyDel, + elementDel : _.long.elementDel, /* qqq : cover */ + _elementWithKeyDel, + elementWithKeyDel : _.long.elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel, + elementWithCardinalDel : _.long.elementWithCardinalDel, /* qqq : cover */ + _empty, + empty : _.long.empty, /* qqq : for junior : cover */ + + _each : _.long._each, + each : _.long.each, /* qqq : cover */ + _eachLeft : _.long._eachLeft, + eachLeft : _.long.eachLeft, /* qqq : cover */ + _eachRight : _.long._eachRight, + eachRight : _.long.eachRight, /* qqq : cover */ + + _while : _.long._while, + while : _.long.while, /* qqq : cover */ + _whileLeft : _.long._whileLeft, + whileLeft : _.long.whileLeft, /* qqq : cover */ + _whileRight : _.long._whileRight, + whileRight : _.long.whileRight, /* qqq : cover */ + + _aptLeft : _.long._aptLeft, + aptLeft : _.long.aptLeft, /* qqq : cover */ + first : _.long.first, + _aptRight : _.long._aptRight, /* qqq : cover */ + aptRight : _.long.aptRight, + last : _.long.last, /* qqq : cover */ + + _filterAct : _.long._filterAct, + filterWithoutEscapeLeft : _.long.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.long.filterWithoutEscapeRight, + filterWithoutEscape : _.long.filterWithoutEscape, + filterWithEscapeLeft : _.long.filterWithEscapeLeft, + filterWithEscapeRight : _.long.filterWithEscapeRight, + filterWithEscape : _.long.filterWithEscape, + filter : _.long.filter, + + _mapAct : _.long._mapAct, + mapWithoutEscapeLeft : _.long.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.long.mapWithoutEscapeRight, + mapWithoutEscape : _.long.mapWithoutEscape, + mapWithEscapeLeft : _.long.mapWithEscapeLeft, + mapWithEscapeRight : _.long.mapWithEscapeRight, + mapWithEscape : _.long.mapWithEscape, + map : _.long.map, + +} + +Object.assign( _.argumentsArray, ArgumentsArrayExtension ); + +// + +var ToolsExtension = +{ +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/ArgumentsArray.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ArgumentsArray_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ArgumentsArray_s */ })(); + +/* */ /* begin of file Array_s */ ( function Array_s() { function Array_s_naked() { ( function _l3_Array_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( !!_.long._elementWithKey, 'Expects routine argumentsArray._elementWithKey' ); +_.assert( !!_.long.exportString, 'Expects routine _.long.exportString' ); + +// -- +// editor +// -- + +/** + * The routine slice() returns a shallow copy of a portion of {-srcArray-} into a new array object. + * The copy makes from first index {-f-} to last index {-l-}. The original {-srcArray-} will not be modified. + * + * @param { Array|Unroll } srcArray - The Array or Unroll from which makes a shallow copy. + * @param { Number } f - Defines the start index of copying. + * Negative value of argument {-f-} indicates an offset from the end of the sequence. + * If {-f-} is undefined, slice begins from index 0. + * If {-f-} is greater than the length of the sequence, an empty array is returned. + * @param { Number } l - Defines last index of copying. An element with this index not included. + * Negative value of {-l-} indicates an offset from the end of the sequence. + * If {-l-} is omitted, slice extracts through the end of the sequence ( srcArray.length ). + * If {-l-} is greater than the length of the sequence, slice extracts through to the end of the sequence (arr.length). + * + * @example + * _.array.slice( [ 1, 2, 3, 4, '5' ] ); + * // returns [ 1, 2, 3, 4, '5' ] + * + * @example + * _.array.slice( [ 1, 2, 3, 4, '5' ], 1, 4 ); + * // returns [ 2, 3, 4 ] + * + * @example + * _.array.slice( [ 1, 2, 3, 4, '5' ], -2, 5 ); + * // returns [ 4, '5' ] + * + * @example + * _.array.slice( [ 1, 2, 3, 4, '5' ], 2, -1 ); + * // returns [ 3, 4 ] + * + * @example + * _.array.slice( [ 1, 2, 3, 4, '5' ], 6, 9 ); + * // returns [] + * + * @returns { Array } Returns a new Array containing the extracted elements. + * @function slice + * @throws { Error } If arguments.length is less then one or more then three. + * @throws { Error } If argument {-srcArray-} is not an array or unroll. + * @namespace Tools/array + */ + +function slice( srcArray, f, l ) +{ + _.assert( this.likeResizable( srcArray ) ); + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + return srcArray.slice( f, l ); +} + +// -- +// array prepend +// -- + +function arrayPrepend( dstArray, ins ) +{ + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + arrayPrepended.apply( this, arguments ); + return dstArray; +} + +// + +/** + * Method adds a value of argument( ins ) to the beginning of an array( dstArray ) + * if destination( dstArray ) doesn't have the value of ( ins ). + * Additionaly takes callback( onEqualize ) that checks if element from( dstArray ) is equal to( ins ). + * + * @param { Array } dstArray - The destination array. + * @param { * } ins - The value to add. + * @param { wTools~compareCallback } onEqualize - A callback function. By default, it checks the equality of two arguments. + * + * @example + * _.arrayPrependOnce( [ 1, 2, 3, 4 ], 5 ); + * // returns [ 5, 1, 2, 3, 4 ] + * + * @example + * _.arrayPrependOnce( [ 1, 2, 3, 4, 5 ], 5 ); + * // returns [ 1, 2, 3, 4, 5 ] + * + * @example + * _.arrayPrependOnce( [ 'Petre', 'Mikle', 'Oleg' ], 'Dmitry' ); + * // returns [ 'Dmitry', 'Petre', 'Mikle', 'Oleg' ] + * + * @example + * _.arrayPrependOnce( [ 'Petre', 'Mikle', 'Oleg', 'Dmitry' ], 'Dmitry' ); + * // returns [ 'Petre', 'Mikle', 'Oleg', 'Dmitry' ] + * + * @example + * function onEqualize( a, b ) + * { + * return a.value === b.value; + * }; + * _.arrayPrependOnce( [ { value : 1 }, { value : 2 } ], { value : 1 }, onEqualize ); + * // returns [ { value : 1 }, { value : 2 } ] + * + * @returns { Array } If an array ( dstArray ) doesn't have a value ( ins ) it returns the updated array ( dstArray ) with the new length, + * otherwise, it returns the original array ( dstArray ). + * @function arrayPrependOnce + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @throws { Error } An Error if ( onEqualize ) is not an Function. + * @throws { Error } An Error if ( arguments.length ) is not equal two or three. + * @namespace Tools + */ + +function arrayPrependOnce( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + arrayPrependedOnce.apply( this, arguments ); + return dstArray; +} + +// + +/** + * Method adds a value of argument( ins ) to the beginning of an array( dstArray ) + * if destination( dstArray ) doesn't have the value of ( ins ). + * Additionaly takes callback( onEqualize ) that checks if element from( dstArray ) is equal to( ins ). + * Returns updated array( dstArray ) if( ins ) was added, otherwise throws an Error. + * + * @param { Array } dstArray - The destination array. + * @param { * } ins - The value to add. + * @param { wTools~compareCallback } onEqualize - A callback function. By default, it checks the equality of two arguments. + * + * @example + * _.arrayPrependOnceStrictly( [ 1, 2, 3, 4 ], 5 ); + * // returns [ 5, 1, 2, 3, 4 ] + * + * @example + * _.arrayPrependOnceStrictly( [ 1, 2, 3, 4, 5 ], 5 ); + * // throws error + * + * @example + * _.arrayPrependOnceStrictly( [ 'Petre', 'Mikle', 'Oleg' ], 'Dmitry' ); + * // returns [ 'Dmitry', 'Petre', 'Mikle', 'Oleg' ] + * + * @example + * _.arrayPrependOnceStrictly( [ 'Petre', 'Mikle', 'Oleg', 'Dmitry' ], 'Dmitry' ); + * // throws error + * + * @example + * function onEqualize( a, b ) + * { + * return a.value === b.value; + * }; + * _.arrayPrependOnceStrictly( [ { value : 1 }, { value : 2 } ], { value : 0 }, onEqualize ); + * // returns [ { value : 0 }, { value : 1 }, { value : 2 } ] + * + * @returns { Array } If an array ( dstArray ) doesn't have a value ( ins ) it returns the updated array ( dstArray ) with the new length, + * otherwise, it throws an Error. + * @function arrayPrependOnceStrictly + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @throws { Error } An Error if ( onEqualize ) is not an Function. + * @throws { Error } An Error if ( arguments.length ) is not equal two or three. + * @throws { Error } An Error if ( ins ) already exists on( dstArray ). + * @namespace Tools + */ + +function arrayPrependOnceStrictly( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + let result; + if( Config.debug ) + { + result = arrayPrependedOnce.apply( this, arguments ); + _.assert( result >= 0, () => `Array should have only unique elements, but has several ${ _.entity.exportStringDiagnosticShallow( ins ) }` ); + } + else + { + result = arrayPrepended.apply( this, [ dstArray, ins ] ); + } + + return dstArray; +} + +// + +function arrayPrepended( dstArray, ins ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.array.is( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + + dstArray.unshift( ins ); + return 0; +} + +// + +/** + * Method adds a value of argument( ins ) to the beginning of an array( dstArray ) + * if destination( dstArray ) doesn't have the value of ( ins ). + * Additionally takes callback( onEqualize ) that checks if element from( dstArray ) is equal to( ins ). + * + * @param { Array } dstArray - The destination array. + * @param { * } ins - The value to add. + * @param { wTools~compareCallback } onEqualize - A callback function. By default, it checks the equality of two arguments. + * + * @example + * _.arrayPrependedOnce( [ 1, 2, 3, 4 ], 5 ); + * // returns 0 + * + * @example + * _.arrayPrependedOnce( [ 1, 2, 3, 4, 5 ], 5 ); + * // returns -1 + * + * @example + * _.arrayPrependedOnce( [ 'Petre', 'Mikle', 'Oleg' ], 'Dmitry' ); + * // returns 0 + * + * @example + * _.arrayPrependedOnce( [ 'Petre', 'Mikle', 'Oleg', 'Dmitry' ], 'Dmitry' ); + * // returns -1 + * + * @example + * function onEqualize( a, b ) + * { + * return a.value === b.value; + * }; + * _.arrayPrependedOnce( [ { value : 1 }, { value : 2 } ], { value : 1 }, onEqualize ); + * // returns -1 + * + * @returns { Array } Returns zero if elements was succesfully added, otherwise returns -1. + * + * @function arrayPrependedOnce + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @throws { Error } An Error if ( onEqualize ) is not an Function. + * @throws { Error } An Error if ( arguments.length ) is not equal two or three. + * @namespace Tools + */ + +function arrayPrependedOnce( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( _.array.is( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + + let i = _.longLeftIndex.apply( _, arguments ); + + if( i === -1 ) + { + dstArray.unshift( ins ); + return 0; + } + return -1; +} + +// + +function arrayPrependedOnceStrictly( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result; + if( Config.debug ) + { + result = arrayPrependedOnce.apply( this, arguments ); + _.assert( result >= 0, () => `Array should have only unique elements, but has several ${ _.entity.exportStringDiagnosticShallow( ins ) }` ); + } + else + { + result = arrayPrepended.apply( this, [ dstArray, ins ] ); + } + + return result; +} + +// + +/** + * Routine adds a value of argument( ins ) to the beginning of an array( dstArray ). + * + * @param { Array } dstArray - The destination array. + * @param { * } ins - The element to add. + * + * @example + * _.arrayPrependElement( [ 1, 2, 3, 4 ], 5 ); + * // returns [ 5, 1, 2, 3, 4 ] + * + * @example + * _.arrayPrependElement( [ 1, 2, 3, 4, 5 ], 5 ); + * // returns [ 5, 1, 2, 3, 4, 5 ] + * + * @returns { Array } Returns updated array, that contains new element( ins ). + * @function arrayPrependElement + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @throws { Error } An Error if ( arguments.length ) is less or more than two. + * @namespace Tools + */ + +function arrayPrependElement( dstArray, ins ) +{ + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + arrayPrependedElement.apply( this, arguments ); + return dstArray; +} + +// + +function arrayPrependElementOnce( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + arrayPrependedElementOnce.apply( this, arguments ); + return dstArray; +} + +// + +function arrayPrependElementOnceStrictly( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + let result; + if( Config.debug ) + { + result = arrayPrependedElementOnce.apply( this, arguments ); + _.assert( result !== undefined, 'Array should have only unique elements, but has several', ins ); + } + else + { + result = arrayPrependedElement.apply( this, [ dstArray, ins ] ); + } + + return dstArray; +} + +/* +function arrayPrependOnceStrictly( dstArray, ins, evaluator1, evaluator2 ) +{ + + let result = arrayPrependedOnce.apply( this, arguments ); + _.assert( result >= 0, () => `Array should have only unique elements, but has several ${ _.entity.exportStringDiagnosticShallow( ins ) }` ); + + return dstArray; +} +*/ + +// + +/** + * Method adds a value of argument( ins ) to the beginning of an array( dstArray ) + * and returns zero if value was succesfully added. + * + * @param { Array } dstArray - The destination array. + * @param { * } ins - The element to add. + * + * @example + * _.arrayPrependedElement( [ 1, 2, 3, 4 ], 5 ); + * // returns 0 + * + * @returns { Array } Returns updated array, that contains new element( ins ). + * @function arrayPrependedElement + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @throws { Error } An Error if ( arguments.length ) is not equal to two. + * @namespace Tools + */ + +function arrayPrependedElement( dstArray, ins ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.array.is( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + + dstArray.unshift( ins ); + + return ins; +} + +// + +function arrayPrependedElementOnce( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( _.array.is( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + + let i = _.longLeftIndex.apply( _, arguments ); + + if( i === -1 ) + { + dstArray.unshift( ins ); + return dstArray[ 0 ]; + } + return undefined; +} + +// + +function arrayPrependedElementOnceStrictly( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result; + if( Config.debug ) + { + debugger; + result = arrayPrependedElementOnce.apply( this, arguments ); + _.assert( result !== undefined, 'Array should have only unique elements, but has several', ins ); + } + else + { + result = arrayPrependedElement.apply( this, [ dstArray, ins ] ); + } + + return result; +} + +// + +/** + * Method adds all elements from array( insArray ) to the beginning of an array( dstArray ). + * + * @param { Array } dstArray - The destination array. + * @param { ArrayLike } insArray - The source array. + * + * @example + * _.arrayPrependArray( [ 1, 2, 3, 4 ], [ 5 ] ); + * // returns [ 5, 1, 2, 3, 4 ] + * + * @example + * _.arrayPrependArray( [ 1, 2, 3, 4, 5 ], [ 5 ] ); + * // returns [ 5, 1, 2, 3, 4, 5 ] + * + * @returns { Array } Returns updated array, that contains elements from( insArray ). + * @function arrayPrependArray + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @throws { Error } An Error if ( insArray ) is not an ArrayLike entity. + * @throws { Error } An Error if ( arguments.length ) is less or more than two. + * @namespace Tools + */ + +function arrayPrependArray( dstArray, insArray ) +{ + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + arrayPrependedArray.apply( this, arguments ); + return dstArray; +} + +// + +/** + * Method adds all unique elements from array( insArray ) to the beginning of an array( dstArray ) + * Additionaly takes callback( onEqualize ) that checks if element from( dstArray ) is equal to( ins ). + * + * @param { Array } dstArray - The destination array. + * @param { ArrayLike } insArray - The source array. + * @param { wTools~compareCallback } onEqualize - A callback function. By default, it checks the equality of two arguments. + * + * @example + * _.arrayPrependArrayOnce( [ 1, 2, 3, 4 ], [ 0, 1, 2, 3, 4 ] ); + * // returns [ 0, 1, 2, 3, 4 ] + * + * @example + * _.arrayPrependArrayOnce( [ 'Petre', 'Mikle', 'Oleg', 'Dmitry' ], [ 'Dmitry' ] ); + * // returns [ 'Petre', 'Mikle', 'Oleg', 'Dmitry' ] + * + * @example + * function onEqualize( a, b ) + * { + * return a.value === b.value; + * }; + * _.arrayPrependArrayOnce( [ { value : 1 }, { value : 2 } ], [ { value : 1 } ], onEqualize ); + * // returns [ { value : 1 }, { value : 2 } ] + * + * @returns { Array } Returns updated array( dstArray ) or original if nothing added. + * @function arrayPrependArrayOnce + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @throws { Error } An Error if ( insArray ) is not an ArrayLike entity. + * @throws { Error } An Error if ( onEqualize ) is not an Function. + * @throws { Error } An Error if ( arguments.length ) is not equal two or three. + * @namespace Tools + */ + +function arrayPrependArrayOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + arrayPrependedArrayOnce.apply( this, arguments ); + return dstArray; +} + +// + +/** + * Method adds all unique elements from array( insArray ) to the beginning of an array( dstArray ) + * Additionaly takes callback( onEqualize ) that checks if element from( dstArray ) is equal to( ins ). + * Returns updated array( dstArray ) if all elements from( insArray ) was added, otherwise throws error. + * Even error was thrown, elements that was prepended to( dstArray ) stays in the destination array. + * + * @param { Array } dstArray - The destination array. + * @param { ArrayLike } insArray - The source array. + * @param { wTools~compareCallback } onEqualize - A callback function. By default, it checks the equality of two arguments. + * + * @example + * _.arrayPrependArrayOnceStrictly( [ 1, 2, 3, 4 ], [ 0, 1, 2, 3, 4 ] ); + * // returns [ 0, 1, 2, 3, 4 ] + * + * @example + * function onEqualize( a, b ) + * { + * return a.value === b.value; + * }; + * _.arrayPrependArrayOnceStrictly( [ { value : 1 }, { value : 2 } ], { value : 1 }, onEqualize ); + * // returns [ { value : 1 }, { value : 2 } ] + * + * * @example + * let dst = [ 'Petre', 'Mikle', 'Oleg', 'Dmitry' ]; + * _.arrayPrependArrayOnceStrictly( dst, [ 'Antony', 'Dmitry' ] ); + * // throws error, but dstArray was updated by one element from insArray + * + * @returns { Array } Returns updated array( dstArray ) or throws an error if not all elements from source + * array( insArray ) was added. + * @function arrayPrependArrayOnceStrictly + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @throws { Error } An Error if ( insArray ) is not an ArrayLike entity. + * @throws { Error } An Error if ( onEqualize ) is not an Function. + * @throws { Error } An Error if ( arguments.length ) is not equal two or three. + * @namespace Tools + */ + +function arrayPrependArrayOnceStrictly( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + let result; + if( Config.debug ) + { + let insArrayLength = insArray.length + result = arrayPrependedArrayOnce.apply( this, arguments ); + _.assert( result === insArrayLength ); + } + else + { + result = arrayPrependedArray.apply( this, [ dstArray, insArray ] ); + } + + return dstArray; +} + +/* +function arrayPrependArrayOnceStrictly( dstArray, insArray, evaluator1, evaluator2 ) +{ + let result = arrayPrependedArrayOnce.apply( this, arguments ); + _.assert( result === insArray.length ); + return dstArray; +} +*/ + +// + +/** + * Method adds all elements from array( insArray ) to the beginning of an array( dstArray ). + * Returns count of added elements. + * + * @param { Array } dstArray - The destination array. + * @param { ArrayLike } insArray - The source array. + * + * @example + * let dst = [ 1, 2, 3, 4 ]; + * _.arrayPrependedArray( dst, [ 5, 6, 7 ] ); + * // returns 3 + * console.log( dst ); + * //log [ 5, 6, 7, 1, 2, 3, 4 ] + * + * @returns { Array } Returns count of added elements. + * @function arrayPrependedArray + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @throws { Error } An Error if ( insArray ) is not an ArrayLike entity. + * @throws { Error } An Error if ( arguments.length ) is less or more than two. + * @namespace Tools + */ + +function arrayPrependedArray( dstArray, insArray ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.array.is( dstArray ), 'arrayPrependedArray :', 'Expects array' ); + _.assert( _.longLike( insArray ), 'arrayPrependedArray :', 'Expects longLike' ); + + let result = insArray.length; + dstArray.unshift.apply( dstArray, insArray ); + return result; +} + +// + +/** + * Method adds all unique elements from array( insArray ) to the beginning of an array( dstArray ) + * Additionaly takes callback( onEqualize ) that checks if element from( dstArray ) is equal to( ins ). + * Returns count of added elements. + * + * @param { Array } dstArray - The destination array. + * @param { ArrayLike } insArray - The source array. + * @param { wTools~compareCallback } onEqualize - A callback function. By default, it checks the equality of two arguments. + * + * @example + * _.arrayPrependedArrayOnce( [ 1, 2, 3 ], [ 4, 5, 6] ); + * // returns 3 + * + * @example + * _.arrayPrependedArrayOnce( [ 0, 2, 3, 4 ], [ 1, 1, 1 ] ); + * // returns 1 + * + * @example + * _.arrayPrependedArrayOnce( [ 'Petre', 'Mikle', 'Oleg', 'Dmitry' ], [ 'Dmitry' ] ); + * // returns 0 + * + * @example + * function onEqualize( a, b ) + * { + * return a.value === b.value; + * }; + * _.arrayPrependedArrayOnce( [ { value : 1 }, { value : 2 } ], [ { value : 1 } ], onEqualize ); + * // returns 0 + * + * @returns { Array } Returns count of added elements. + * @function arrayPrependedArrayOnce + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @throws { Error } An Error if ( insArray ) is not an ArrayLike entity. + * @throws { Error } An Error if ( onEqualize ) is not an Function. + * @throws { Error } An Error if ( arguments.length ) is not equal two or three. + * @namespace Tools + */ + +function arrayPrependedArrayOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + _.assert( _.array.is( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + _.assert( _.longLike( insArray ) ); + + let result = 0; + + if( dstArray === insArray ) + if( arguments.length === 2 ) + return result; + + for( let i = insArray.length - 1; i >= 0; i-- ) + { + let index = i; + if( dstArray === insArray ) + index = i + result; + + if( _.longLeftIndex( dstArray, insArray[ index ], evaluator1, evaluator2 ) === -1 ) + { + dstArray.unshift( insArray[ index ] ); + result += 1; + } + } + + return result; +} + +// + +function arrayPrependedArrayOnceStrictly( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result; + if( Config.debug ) + { + let insArrayLength = insArray.length; + result = arrayPrependedArrayOnce.apply( this, arguments ); + _.assert( result === insArrayLength ); + } + else + { + result = arrayPrependedArray.apply( this, [ dstArray, insArray ] ); + } + + return result; +} + +// + +/** + * Method adds all elements from provided arrays to the beginning of an array( dstArray ) in same order + * that they are in( arguments ). + * If argument provided after( dstArray ) is not a ArrayLike entity it will be prepended to destination array as usual element. + * If argument is an ArrayLike entity and contains inner arrays, routine looks for elements only on first two levels. + * Example: _.arrayPrependArrays( [], [ [ 1 ], [ [ 2 ] ] ] ) -> [ 1, [ 2 ] ]; + * Throws an error if one of arguments is undefined. Even if error was thrown, elements that was prepended to( dstArray ) stays in the destination array. + * + * @param { Array } dstArray - The destination array. + * @param{ longLike | * } arguments[...] - Source arguments. + * + * @example + * _.arrayPrependArrays( [ 1, 2, 3, 4 ], [ 5 ], [ 6 ], 7 ); + * // returns [ 5, 6, 7, 1, 2, 3, 4 ] + * + * @example + * let dst = [ 1, 2, 3, 4 ]; + * _.arrayPrependArrays( dst, [ 5 ], [ 6 ], undefined ); + * // throws error, but dst becomes equal [ 5, 6, 1, 2, 3, 4 ] + * + * @returns { Array } Returns updated array( dstArray ). + * @function arrayPrependArrays + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @throws { Error } An Error if one of ( arguments ) is undefined. + * @namespace Tools + */ + +function arrayPrependArrays( dstArray, insArray ) +{ + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + arrayPrependedArrays.apply( this, arguments ); + return dstArray; +} + +// + +/** + * Method adds all unique elements from provided arrays to the beginning of an array( dstArray ) in same order + * that they are in( arguments ). + * If argument provided after( dstArray ) is not a ArrayLike entity it will be prepended to destination array as usual element. + * If argument is an ArrayLike entity and contains inner arrays, routine looks for elements only on first two levels. + * Example: _.arrayPrependArrays( [], [ [ 1 ], [ [ 2 ] ] ] ) -> [ 1, [ 2 ] ]; + * Throws an error if one of arguments is undefined. Even if error was thrown, elements that was prepended to( dstArray ) stays in the destination array. + + * @param { Array } dstArray - The destination array. + * @param{ longLike | * } arguments[...] - Source arguments. + * + * @example + * _.arrayPrependArraysOnce( [ 1, 2, 3, 4 ], [ 5 ], 5, [ 6 ], 6, 7, [ 7 ] ); + * // returns [ 5, 6, 7, 1, 2, 3, 4 ] + * + * @example + * let dst = [ 1, 2, 3, 4 ]; + * _.arrayPrependArraysOnce( dst, [ 5 ], 5, [ 6 ], 6, undefined ); + * // throws error, but dst becomes equal [ 5, 6, 1, 2, 3, 4 ] + * + * @returns { Array } Returns updated array( dstArray ). + * @function arrayPrependArraysOnce + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @throws { Error } An Error if one of ( arguments ) is undefined. + * @namespace Tools + */ + +function arrayPrependArraysOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + arrayPrependedArraysOnce.apply( this, arguments ); + return dstArray; +} + +// + +/** + * Method adds all unique elements from provided arrays to the beginning of an array( dstArray ) in same order + * that they are in( arguments ). + * Throws an error if one of arguments is undefined. + * If argument provided after( dstArray ) is not a ArrayLike entity it will be prepended to destination array as usual element. + * If argument is an ArrayLike entity and contains inner arrays, routine looks for elements only on first two levels. + * Example: _.arrayPrependArraysOnce( [], [ [ 1 ], [ [ 2 ] ] ] ) -> [ 1, [ 2 ] ]; + * After copying checks if all elements( from first two levels ) was copied, if true returns updated array( dstArray ), otherwise throws an error. + * Even if error was thrown, elements that was prepended to( dstArray ) stays in the destination array. + + * @param { Array } dstArray - The destination array. + * @param { longLike | * } arguments[...] - Source arguments. + * @param { wTools~compareCallback } onEqualize - A callback function that can be provided through routine`s context. By default, it checks the equality of two arguments. + * + * @example + * _.arrayPrependArraysOnceStrictly( [ 1, 2, 3, 4 ], 5, [ 6, [ 7 ] ], 8 ); + * // returns [ 5, 6, 7, 8, 1, 2, 3, 4 ] + * + * @example + * _.arrayPrependArraysOnceStrictly( [ 1, 2, 3, 4 ], [ 5 ], 5, [ 6 ], 6, 7, [ 7 ] ); + * // throws error + * + * @example + * function onEqualize( a, b ) + * { + * return a === b; + * }; + * let dst = []; + * let arguments = [ dst, [ 1, [ 2 ], [ [ 3 ] ] ], 4 ]; + * _.arrayPrependArraysOnceStrictly.apply( { onEqualize }, arguments ); + * // returns [ 1, 2, [ 3 ], 4 ] + * + * @returns { Array } Returns updated array( dstArray ). + * @function arrayPrependArraysOnceStrictly + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @throws { Error } An Error if one of ( arguments ) is undefined. + * @throws { Error } An Error if count of added elements is not equal to count of elements from( arguments )( only first two levels inside of array are counted ). + * @namespace Tools + */ + +function arrayPrependArraysOnceStrictly( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + let result; + if( Config.debug ) + { + let expected = 0; + let insIsDst = 0; + for( let i = insArray.length - 1; i >= 0; i-- ) + { + if( _.longLike( insArray[ i ] ) ) + { + expected += insArray[ i ].length + + if( insArray[ i ] === dstArray ) + { + insIsDst += 1; + if( insIsDst > 1 ) + expected += insArray[ i ].length + } + } + else + expected += 1; + } + result = arrayPrependedArraysOnce.apply( this, arguments ); + _.assert( result === expected, '{-dstArray-} should have none element from {-insArray-}' ); + } + else + { + result = arrayPrependedArrays.apply( this, [ dstArray, insArray ] ); + } + + return dstArray; +} + +/* +function arrayPrependArraysOnceStrictly( dstArray, insArray, evaluator1, evaluator2 ) +{ + let result = arrayPrependedArraysOnce.apply( this, arguments ); + let expected = 0; + + if( Config.debug ) + { + + for( let i = insArray.length - 1; i >= 0; i-- ) + { + if( _.longLike( insArray[ i ] ) ) + expected += insArray[ i ].length; + else + expected += 1; + } + + _.assert( result === expected, '{-dstArray-} should have none element from {-insArray-}' ); + + } + + return dstArray; +} +*/ + +// + +/** + * Method adds all elements from provided arrays to the beginning of an array( dstArray ) in same order + * that they are in( arguments ). + * If argument provided after( dstArray ) is not a ArrayLike entity it will be prepended to destination array as usual element. + * If argument is an ArrayLike entity and contains inner arrays, routine looks for elements only on first two levels. + * Example: _.arrayPrependArrays( [], [ [ 1 ], [ [ 2 ] ] ] ) -> [ 1, [ 2 ] ]; + * Throws an error if one of arguments is undefined. Even if error was thrown, elements that was prepended to( dstArray ) stays in the destination array. + * + * @param { Array } dstArray - The destination array. + * @param{ longLike | * } arguments[...] - Source arguments. + * + * @example + * _.arrayPrependedArrays( [ 1, 2, 3, 4 ], [ 5 ], [ 6 ], 7 ); + * // returns 3 + * + * @example + * let dst = [ 1, 2, 3, 4 ]; + * _.arrayPrependedArrays( dst, [ 5 ], [ 6 ], undefined ); + * // throws error, but dst becomes equal [ 5, 6, 1, 2, 3, 4 ] + * + * @returns { Array } Returns count of added elements. + * @function arrayPrependedArrays + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @namespace Tools + */ + +function arrayPrependedArrays( dstArray, insArray ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.array.is( dstArray ), 'arrayPrependedArrays :', 'Expects array' ); + _.assert( _.longLike( insArray ), 'arrayPrependedArrays :', 'Expects longLike entity' ); + + let result = 0; + + if( dstArray === insArray ) + { + result = insArray.length; + dstArray.unshift.apply( dstArray, insArray ); + return result; + } + + for( let a = 0, len = insArray.length ; a < len ; a++ ) + { + if( _.longLike( insArray[ a ] ) ) + { + result += insArray[ a ].length; + dstArray.unshift.apply( dstArray, insArray[ a ] ); + } + else + { + dstArray.unshift( insArray[ a ] ); + result += 1; + } + } + + return result; +} + +// + +/** + * Method adds all unique elements from provided arrays to the beginning of an array( dstArray ) in same order + * that they are in( arguments ). + * If argument provided after( dstArray ) is not a ArrayLike entity it will be prepended to destination array as usual element. + * If argument is an ArrayLike entity and contains inner arrays, routine looks for elements only on first two levels. + * Example: _.arrayPrependArrays( [], [ [ 1 ], [ [ 2 ] ] ] ) -> [ 1, [ 2 ] ]; + * Throws an error if one of arguments is undefined. Even if error was thrown, elements that was prepended to( dstArray ) stays in the destination array. + * + * @param { Array } dstArray - The destination array. + * @param{ longLike | * } arguments[...] - Source arguments. + * + * @example + * _.arrayPrependedArraysOnce( [ 1, 2, 3, 4, 5, 6, 7 ], [ 5 ], [ 6 ], 7 ); + * // returns 0 + * + * @example + * _.arrayPrependedArraysOnce( [ 1, 2, 3, 4 ], [ 5 ], 5, [ 6 ], 6, 7, [ 7 ] ); + * // returns 3 + * + * @example + * let dst = [ 1, 2, 3, 4 ]; + * _.arrayPrependedArraysOnce( dst, [ 5 ], [ 6 ], undefined ); + * // throws error, but dst becomes equal [ 5, 6, 1, 2, 3, 4 ] + * + * @returns { Array } Returns count of added elements. + * @function arrayPrependedArraysOnce + * @throws { Error } An Error if ( dstArray ) is not an Array. + * @namespace Tools + */ + +function arrayPrependedArraysOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + _.assert( _.array.is( dstArray ), 'arrayPrependedArraysOnce :', 'Expects array' ); + _.assert( _.longLike( insArray ), 'arrayPrependedArraysOnce :', 'Expects longLike entity' ); + + let result = 0; + + if( dstArray === insArray ) + if( arguments.length === 2 ) + return result; + + function _prependOnce( element ) + { + let index = _.longLeftIndex( dstArray, element, evaluator1, evaluator2 ); + if( index === -1 ) + { + dstArray.unshift( element ); + // dstArray.splice( result, 0, element ); + result += 1; + } + } + + // for( let ii = insArray.length - 1; ii >= 0; ii-- ) + for( let ii = 0, len = insArray.length; ii < len ; ii++ ) + { + if( _.longLike( insArray[ ii ] ) ) + { + let array = insArray[ ii ]; + if( array === dstArray ) + array = array.slice(); + // for( let a = array.length - 1; a >= 0; a-- ) + for( let a = array.length - 1; a >= 0 ; a-- ) + _prependOnce( array[ a ] ); + } + else + { + if( dstArray === insArray ) + _prependOnce( insArray[ ii + result ] ); + else + _prependOnce( insArray[ ii ] ); + } + } + + return result; +} + +// + +function arrayPrependedArraysOnceStrictly( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result; + if( Config.debug ) + { + let expected = 0; + let insIsDst = 0; + for( let i = insArray.length - 1; i >= 0; i-- ) + { + if( _.longLike( insArray[ i ] ) ) + { + expected += insArray[ i ].length + + if( insArray[ i ] === dstArray ) + { + insIsDst += 1; + if( insIsDst > 1 ) + expected += insArray[ i ].length + } + } + else + expected += 1; + } + + result = arrayPrependedArraysOnce.apply( this, arguments ); + + _.assert( result === expected, '{-dstArray-} should have none element from {-insArray-}' ); + } + else + { + result = arrayPrependedArrays.apply( this, [ dstArray, insArray ] ); + } + + return result; +} + +// -- +// array append +// -- + +// function arrayAppend_( dstArray ) +// { +// _.assert( arguments.length >= 1 ); +// _.assert( _.array.is( dstArray ) || dstArray === null, 'Expects array' ); +// +// dstArray = dstArray || []; +// +// for( let a = 1, len = arguments.length ; a < len; a++ ) +// { +// if( _.longLike( arguments[ a ] ) ) +// { +// dstArray.push.apply( dstArray, arguments[ a ] ); +// } +// else +// { +// dstArray.push( arguments[ a ] ); +// } +// } +// +// return dstArray; +// } + +// + +function arrayAppend( dstArray, ins ) +{ + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + _.arrayAppended.apply( this, arguments ); + return dstArray; +} + +// + +/** + * The arrayAppendOnce() routine adds at the end of an array (dst) a value {-srcMap-}, + * if the array (dst) doesn't have the value {-srcMap-}. + * + * @param { Array } dst - The source array. + * @param { * } src - The value to add. + * + * @example + * _.arrayAppendOnce( [ 1, 2, 3, 4 ], 5 ); + * // returns [ 1, 2, 3, 4, 5 ] + * + * @example + * _.arrayAppendOnce( [ 1, 2, 3, 4, 5 ], 5 ); + * // returns [ 1, 2, 3, 4, 5 ] + * + * @example + * _.arrayAppendOnce( [ 'Petre', 'Mikle', 'Oleg' ], 'Dmitry' ); + * // returns [ 'Petre', 'Mikle', 'Oleg', 'Dmitry' ] + * + * @example + * _.arrayAppendOnce( [ 'Petre', 'Mikle', 'Oleg', 'Dmitry' ], 'Dmitry' ); + * // returns [ 'Petre', 'Mikle', 'Oleg', 'Dmitry' ] + * + * @returns { Array } If an array (dst) doesn't have a value {-srcMap-} it returns the updated array (dst) with the new length, + * otherwise, it returns the original array (dst). + * @function arrayAppendOnce + * @throws { Error } Will throw an Error if (dst) is not an Array. + * @throws { Error } Will throw an Error if (arguments.length) is less or more than two. + * @namespace Tools + */ + +function arrayAppendOnce( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + _.arrayAppendedOnce.apply( this, arguments ); + return dstArray; +} + +// + +function arrayAppendOnceStrictly( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + let result; + if( Config.debug ) + { + result = _.arrayAppendedOnce.apply( this, arguments ); + _.assert( result >= 0, () => `Array should have only unique elements, but has several ${ _.entity.exportStringDiagnosticShallow( ins ) }` ); + } + else + { + result = _.arrayAppended.apply( this, [ dstArray, ins ] ); + } + return dstArray; +} + +// + +function arrayAppended( dstArray, ins ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.array.is( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + dstArray.push( ins ); + return dstArray.length - 1; +} + +// + +function arrayAppendedOnce( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let i = _.longLeftIndex.apply( _, arguments ); + + if( i === -1 ) + { + dstArray.push( ins ); + return dstArray.length - 1; + } + + return -1; +} + +// + +function arrayAppendedOnceStrictly( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result; + if( Config.debug ) + { + result = _.arrayAppendedOnce.apply( this, arguments ); + _.assert( result >= 0, () => `Array should have only unique elements, but has several ${ _.entity.exportStringDiagnosticShallow( ins ) }` ); + } + else + { + result = _.arrayAppended.apply( this, [ dstArray, ins ] ); + } + return result; +} + + +// + +function arrayAppendElement( dstArray, ins ) +{ + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + arrayAppendedElement.apply( this, arguments ); + return dstArray; +} + +// + +function arrayAppendElementOnce( dstArray, ins ) +{ + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + arrayAppendedElementOnce.apply( this, arguments ); + return dstArray; +} + +// + +function arrayAppendElementOnceStrictly( dstArray, ins ) +{ + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + let result; + if( Config.debug ) + { + result = arrayAppendedElementOnce.apply( this, arguments ); + _.assert( result !== false, 'Array should have only unique elements, but has several', ins ); + } + else + { + result = arrayAppendedElement.apply( this, [ dstArray, ins ] ); + } + return dstArray; +} + +// + +function arrayAppendedElement( dstArray, ins ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.array.is( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + dstArray.push( ins ); + return dstArray.length - 1; +} + +// + +function arrayAppendedElementOnce( dstArray, ins ) +{ + let i = _.longLeftIndex.apply( _, arguments ); + + if( i === -1 ) + { + dstArray.push( ins ); + return dstArray[ dstArray.length - 1 ]; + } + + return false; + // return -1; +} + +// + +function arrayAppendedElementOnceStrictly( dstArray, ins ) +{ + let result; + if( Config.debug ) + { + result = arrayAppendedElementOnce.apply( this, arguments ); + _.assert( result !== false, 'Array should have only unique elements, but has several', ins ); + } + else + { + result = arrayAppendedElement.apply( this, [ dstArray, ins ] ); + } + return result; +} + +// + +/** +* The arrayAppendArray() routine adds one or more elements to the end of the (dst) array +* and returns the new length of the array. +* +* It creates two variables the (result) - array and the (argument) - elements of array-like object (arguments[]), +* iterate over array-like object (arguments[]) and assigns to the (argument) each element, +* checks, if (argument) is equal to the 'undefined'. +* If true, it throws an Error. +* If (argument) is an array-like. +* If true, it merges the (argument) into the (result) array. +* Otherwise, it adds element to the result. +* +* @param { Array } dst - Initial array. +* @param {*} arguments[] - One or more argument(s) to add to the end of the (dst) array. +* +* @example +* _.arrayAppendArray( [ 1, 2 ], 'str', false, { a : 1 }, 42, [ 3, 7, 13 ] ); +* // returns [ 1, 2, 'str', false, { a : 1 }, 42, 3, 7, 13 ]; +* +* @returns { Array } - Returns an array (dst) with all of the following argument(s) that were added to the end of the (dst) array. +* @function arrayAppendArray +* @throws { Error } If the first argument is not an array. +* @throws { Error } If type of the argument is equal undefined. +* @namespace Tools +*/ + +function arrayAppendArray( dstArray, insArray ) +{ + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + _.arrayAppendedArray.apply( this, arguments ); + return dstArray; +} + +// + +/** + * The arrayAppendArrayOnce() routine returns an array of elements from (dst) + * and appending only unique following arguments to the end. + * + * It creates two variables the (result) - array and the (argument) - elements of array-like object (arguments[]), + * iterate over array-like object (arguments[]) and assigns to the (argument) each element, + * checks, if (argument) is equal to the 'undefined'. + * If true, it throws an Error. + * if (argument) is an array-like. + * If true, it iterate over array (argument) and checks if (result) has the same values as the (argument). + * If false, it adds elements of (argument) to the end of the (result) array. + * Otherwise, it checks if (result) has not the same values as the (argument). + * If true, it adds elements to the end of the (result) array. + * + * @param { Array } dst - Initial array. + * @param {*} arguments[] - One or more argument(s). + * + * @example + * _.arrayAppendArrayOnce( [ 1, 2 ], 'str', 2, {}, [ 'str', 5 ] ); + * // returns [ 1, 2, 'str', {}, 5 ] + * + * @returns { Array } - Returns an array (dst) with only unique following argument(s) that were added to the end of the (dst) array. + * @function arrayAppendArrayOnce + * @throws { Error } If the first argument is not array. + * @throws { Error } If type of the argument is equal undefined. + * @namespace Tools + */ + +function arrayAppendArrayOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + _.arrayAppendedArrayOnce.apply( this, arguments ) + return dstArray; +} + +// + +function arrayAppendArrayOnceStrictly( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + let result; + if( Config.debug ) + { + let insArrayLength = insArray.length + result = _.arrayAppendedArrayOnce.apply( this, arguments ) + _.assert( result === insArrayLength ); + } + else + { + result = arrayAppendedArray.apply( this, [ dstArray, insArray ] ) + } + return dstArray; +} + +/* +function arrayAppendArrayOnceStrictly( dstArray, insArray, evaluator1, evaluator2 ) +{ + let result = arrayAppendedArrayOnce.apply( this, arguments ) + _.assert( result === insArray.length ); + return dstArray; +} +*/ + +// + +function arrayAppendedArray( dstArray, insArray ) +{ + _.assert( arguments.length === 2 ) + _.assert( _.array.is( dstArray ), 'arrayPrependedArray :', 'Expects array' ); + _.assert( _.longLike( insArray ), 'arrayPrependedArray :', 'Expects longLike' ); + + let result = insArray.length; + dstArray.push.apply( dstArray, insArray ); + return result; +} + +// + +function arrayAppendedArrayOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( _.longLike( insArray ) ); + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + + let result = 0; + + if( dstArray === insArray ) + if( arguments.length === 2 ) + return result; + + for( let i = 0, len = insArray.length; i < len ; i++ ) + { + if( _.longLeftIndex( dstArray, insArray[ i ], evaluator1, evaluator2 ) === -1 ) + { + dstArray.push( insArray[ i ] ); + result += 1; + } + } + + return result; +} + +// + +function arrayAppendedArrayOnceStrictly( dstArray, ins ) +{ + let result; + if( Config.debug ) + { + let insArrayLength = ins.length; + result = _.arrayAppendedArrayOnce.apply( this, arguments ); + _.assert( result === insArrayLength, 'Array should have only unique elements, but has several', ins ); + } + else + { + result = arrayAppendedElement.apply( this, [ dstArray, ins ] ); + } + return result; +} + +// + +function arrayAppendArrays( dstArray, insArray ) +{ + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + if( dstArray === undefined ) + { + _.assert( arguments.length === 2 ); + return insArray; + } + + _.arrayAppendedArrays.apply( this, arguments ); + + return dstArray; +} + +// + +function arrayAppendArraysOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + else if( dstArray === undefined ) + { + if( _.array.is( insArray ) ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + else + { + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + return insArray; + } + } + + _.arrayAppendedArraysOnce.apply( this, arguments ); + + return dstArray; +} + +// + +function arrayAppendArraysOnceStrictly( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + let result; + if( Config.debug ) + { + let expected = 0; + let insIsDst = 0; + for( let i = insArray.length - 1; i >= 0; i-- ) + { + if( _.longLike( insArray[ i ] ) ) + { + expected += insArray[ i ].length + + if( insArray[ i ] === dstArray ) + { + insIsDst += 1; + if( insIsDst > 1 ) + expected += insArray[ i ].length + } + } + else + expected += 1; + } + + result = _.arrayAppendedArraysOnce.apply( this, arguments ); + + _.assert( result === expected, '{-dstArray-} should have none element from {-insArray-}' ); + } + else + { + result = arrayAppendedArrays.apply( this, [ dstArray, insArray ] ); + } + + return dstArray; +} + +// + +function arrayAppendedArrays( dstArray, insArray ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !_.longLike( insArray ) && insArray !== undefined ) + insArray = [ insArray ]; + + // if( !_.longLike( insArray ) ) + // { + // if( !_.array.is( dstArray ) ) + // return [ dstArray, insArray ]; + // else + // dstArray.push( insArray ); + // return 1; + // } + + // if( !_.array.is( insArray ) && insArray !== undefined ) + // insArray = [ insArray ]; + // if( !_.array.is( insArray ) && insArray !== undefined ) + // insArray = [ insArray ]; + + _.assert( _.array.is( dstArray ), 'Expects array' ); + _.assert( _.longLike( insArray ), 'Expects longLike entity' ); + + let result = 0; + + for( let a = 0, len = insArray.length; a < len; a++ ) + { + if( _.longLike( insArray[ a ] ) ) + { + dstArray.push.apply( dstArray, insArray[ a ] ); + result += insArray[ a ].length; + } + else + { + dstArray.push( insArray[ a ] ); + result += 1; + } + } + + return result; +} + +// + +function arrayAppendedArraysOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + + if( dstArray === undefined ) + return insArray; + + if( !_.array.is( insArray ) && insArray !== undefined ) + insArray = [ insArray ]; + + _.assert( _.array.is( dstArray ), 'Expects array' ); + _.assert( _.longLike( insArray ), 'Expects longLike entity' ); + + let result = 0; + + if( dstArray === insArray ) + if( arguments.length === 2 ) + return result; + + for( let a = 0, len = insArray.length; a < len; a++ ) + { + if( _.longLike( insArray[ a ] ) ) + { + let array = insArray[ a ]; + for( let i = 0, alen = array.length; i < alen; i++ ) + _appendOnce( array[ i ] ); + } + else + { + _appendOnce( insArray[ a ] ); + } + } + + return result; + + function _appendOnce( argument ) + { + let index = _.longLeftIndex( dstArray, argument, evaluator1, evaluator2 ); + if( index === -1 ) + { + dstArray.push( argument ); + result += 1; + } + } + +} + +// + +function arrayAppendedArraysOnceStrictly( dstArray, ins ) +{ + let result; + if( Config.debug ) + { + let expected = 0; + let insIsDst = 0; + for( let i = ins.length - 1; i >= 0; i-- ) + { + if( _.longLike( ins[ i ] ) ) + { + expected += ins[ i ].length + + if( ins[ i ] === dstArray ) + { + insIsDst += 1; + if( insIsDst > 1 ) + expected += ins[ i ].length + } + } + else + expected += 1; + } + result = _.arrayAppendedArraysOnce.apply( this, arguments ); + _.assert( result === expected, '{-dstArray-} should have none element from {-insArray-}' ); + } + else + { + result = arrayAppendedArrays.apply( this, [ dstArray, ins ] ); + } + + return result; +} + +// -- +// container interface +// -- + +function _elementAppend( dst, val ) +{ + dst.push( val ); + return dst.length-1; +} + +// + +function elementAppend( dst, val ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( dst ) ); + return this._elementAppend( dst, val ); +} + +// + +function _elementPrepend( dst, val ) +{ + dst.unshift( val ); + return 0; +} + +// + +function elementPrepend( dst, val ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( dst ) ); + return this._elementAppend( dst, val ); +} + +// + +function _elementWithKeyDel( src, key ) +{ + if( !this._hasKey( src, key ) ) + return false; + src.splice( key, 1 ); + return true; +} + +// + +function elementWithKeyDel( src, key ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + return this._elementWithKeyDel( src, key ); +} + +// + +function _elementWithCardinalDel( src, cardinal ) +{ + if( !this._hasKey( src, cardinal ) ) + return false; + src.splice( cardinal, 1 ); + return true; +} + +// + +function elementWithCardinalDel( src, cardinal ) +{ + _.assert( arguments.length === 2 ); + _.assert( this.is( src ) ); + return this._elementWithCardinalDel( src, cardinal, val ); +} + +// + +function _empty( dst ) +{ + dst.splice( 0, dst.length ); + return dst; +} + +// + +function empty( dst ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( this.like( dst ) ); + return this._empty( dst ); +} + +// -- +// declaration +// -- + +/* qqq2 : for junior : duplicate routines. ask */ +let ToolsExtension = +{ + + // array prepend + + arrayPrepend, + arrayPrependOnce, + arrayPrependOnceStrictly, + arrayPrepended, + arrayPrependedOnce, + arrayPrependedOnceStrictly, + + arrayPrependElement, + arrayPrependElementOnce, + arrayPrependElementOnceStrictly, + arrayPrependedElement, + arrayPrependedElementOnce, + arrayPrependedElementOnceStrictly, + + arrayPrependArray, + arrayPrependArrayOnce, + arrayPrependArrayOnceStrictly, + arrayPrependedArray, + arrayPrependedArrayOnce, + arrayPrependedArrayOnceStrictly, + + arrayPrependArrays, + arrayPrependArraysOnce, + arrayPrependArraysOnceStrictly, + arrayPrependedArrays, + arrayPrependedArraysOnce, + arrayPrependedArraysOnceStrictly, + + // array append + + arrayAppend, + arrayAppendOnce, + arrayAppendOnceStrictly, + arrayAppended, + arrayAppendedOnce, + arrayAppendedOnceStrictly, + + arrayAppendElement, + arrayAppendElementOnce, + arrayAppendElementOnceStrictly, + arrayAppendedElement, + arrayAppendedElementOnce, + arrayAppendedElementOnceStrictly, + + arrayAppendArray, + arrayAppendArrayOnce, + arrayAppendArrayOnceStrictly, + arrayAppendedArray, + arrayAppendedArrayOnce, + arrayAppendedArrayOnceStrictly, + + arrayAppendArrays, + arrayAppendArraysOnce, + arrayAppendArraysOnceStrictly, + arrayAppendedArrays, + arrayAppendedArraysOnce, + arrayAppendedArraysOnceStrictly, + + // fields + + accuracy : 1e-7, + accuracySqrt : 1e-4, + accuracySqr : 1e-14, + +} + +// + +Object.assign( _, ToolsExtension ); + +// + +let ArrayExtension = +{ + + // editor + + slice, + + // equaler + + _identicalShallow : _.long._identicalShallow, + identicalShallow : _.long.identicalShallow, + identical : _.long.identical, + _equivalentShallow : _.long._equivalentShallow, + equivalentShallow : _.long.equivalentShallow, + equivalent : _.long.equivalent, + + // exporter + + _exportStringDiagnosticShallow : _.long._exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.long.exportStringDiagnosticShallow, + _exportStringCodeShallow : _.long._exportStringCodeShallow, + exportStringCodeShallow : _.long.exportStringCodeShallow, + exportString : _.long.exportString, + + // container interface + + _lengthOf : _.long._lengthOf, + lengthOf : _.long.lengthOf, /* qqq : cover */ + + _hasKey : _.long._hasKey, + hasKey : _.long._hasKey, /* qqq : cover */ + _hasCardinal : _.long._hasKey, + hasCardinal : _.long._hasKey, /* qqq : cover */ + _keyWithCardinal : _.long._hasKey, + keyWithCardinal : _.long._hasKey, /* qqq : cover */ + _cardinalWithKey : _.long._cardinalWithKey, + cardinalWithKey : _.long.cardinalWithKey, /* qqq : cover */ + + _elementGet : _.long._elementWithKey, + elementGet : _.long.elementWithKey, /* qqq : cover */ + _elementWithKey : _.long._elementWithKey, + elementWithKey : _.long.elementWithKey, /* qqq : cover */ + _elementWithImplicit : _.long._elementWithImplicit, + elementWithImplicit : _.long.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal : _.long._elementWithCardinal, + elementWithCardinal : _.long.elementWithCardinal, /* qqq : cover */ + + _elementSet : _.long._elementSet, + elementSet : _.long.elementSet, /* qqq : cover */ + _elementWithKeySet : _.long._elementWithKeySet, + elementWithKeySet : _.long.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet : _.long._elementWithCardinalSet, + elementWithCardinalSet : _.long.elementWithCardinalSet, /* qqq : cover */ + + _elementAppend, + elementAppend, /* qqq : cover */ + _elementPrepend, + elementPrepend, /* qqq : cover */ + + _elementDel : _elementWithKeyDel, + elementDel : elementWithKeyDel, /* qqq : cover */ + _elementWithKeyDel, + elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel, + elementWithCardinalDel, /* qqq : cover */ + _empty, + empty, /* qqq : for junior : cover */ + + _each : _.long._each, + each : _.long.each, /* qqq : cover */ + _eachLeft : _.long._eachLeft, + eachLeft : _.long.eachLeft, /* qqq : cover */ + _eachRight : _.long._eachRight, + eachRight : _.long.eachRight, /* qqq : cover */ + + _while : _.long._while, + while : _.long.while, /* qqq : cover */ + _whileLeft : _.long._whileLeft, + whileLeft : _.long.whileLeft, /* qqq : cover */ + _whileRight : _.long._whileRight, + whileRight : _.long.whileRight, /* qqq : cover */ + + _aptLeft : _.long._aptLeft, + aptLeft : _.long.aptLeft, /* qqq : cover */ + first : _.long.first, + _aptRight : _.long._aptRight, /* qqq : cover */ + aptRight : _.long.aptRight, + last : _.long.last, /* qqq : cover */ + + _filterAct : _.long._filterAct, + filterWithoutEscapeLeft : _.long.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.long.filterWithoutEscapeRight, + filterWithoutEscape : _.long.filterWithoutEscape, + filterWithEscapeLeft : _.long.filterWithEscapeLeft, + filterWithEscapeRight : _.long.filterWithEscapeRight, + filterWithEscape : _.long.filterWithEscape, + filter : _.long.filter, + + _mapAct : _.long._mapAct, + mapWithoutEscapeLeft : _.long.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.long.mapWithoutEscapeRight, + mapWithoutEscape : _.long.mapWithoutEscape, + mapWithEscapeLeft : _.long.mapWithEscapeLeft, + mapWithEscapeRight : _.long.mapWithEscapeRight, + mapWithEscape : _.long.mapWithEscape, + map : _.long.map, + +} + +// + +Object.assign( _.array, ArrayExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Array.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Array_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Array_s */ })(); + +/* */ /* begin of file ArraySet_s */ ( function ArraySet_s() { function ArraySet_s_naked() { ( function _l3_ArraySet_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.arraySet = _.arraySet || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +// + +let Extension = +{ + +} + +Object.assign( _.arraySet, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/ArraySet.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ArraySet_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ArraySet_s */ })(); + +/* */ /* begin of file Auxiliary_s */ ( function Auxiliary_s() { function Auxiliary_s_naked() { ( function _l3_Auxiliary_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( !!_.props.exportString, 'Expects routine _.props.exportString' ); + +// -- +// equaler +// -- + +function _identicalShallow( src1, src2 ) +{ + + if( Object.keys( src1 ).length !== Object.keys( src2 ).length ) + return false; + + for( let s in src1 ) + { + if( src1[ s ] !== src2[ s ] ) + return false; + } + + return true; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +// + +var AuxiliaryExtension = +{ + + // equaler + + _identicalShallow, + identicalShallow : _.props.identicalShallow, + identical : _.props.identical, + _equivalentShallow : _identicalShallow, + equivalentShallow : _.props.equivalentShallow, + equivalent : _.props.equivalent, + + // exporter + + _exportStringDiagnosticShallow : _.props._exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.props.exportStringDiagnosticShallow, + _exportStringCodeShallow : _.props._exportStringCodeShallow, + exportStringCodeShallow : _.props.exportStringCodeShallow, + exportString : _.props.exportString, + + // container interface + + _lengthOf : _.props._lengthOf, + lengthOf : _.props.lengthOf, /* qqq : cover */ + + _hasKey : _.props._hasKey, + hasKey : _.props._hasKey, /* qqq : cover */ + _hasCardinal : _.props._hasKey, + hasCardinal : _.props._hasKey, /* qqq : cover */ + _keyWithCardinal : _.props._hasKey, + keyWithCardinal : _.props._hasKey, /* qqq : cover */ + _cardinalWithKey : _.props._cardinalWithKey, + cardinalWithKey : _.props.cardinalWithKey, /* qqq : cover */ + + _elementGet : _.props._elementWithKey, + elementGet : _.props.elementWithKey, /* qqq : cover */ + _elementWithKey : _.props._elementWithKey, + elementWithKey : _.props.elementWithKey, /* qqq : cover */ + _elementWithImplicit : _.props._elementWithImplicit, + elementWithImplicit : _.props.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal : _.props._elementWithCardinal, + elementWithCardinal : _.props.elementWithCardinal, /* qqq : cover */ + + _elementSet : _.props._elementSet, + elementSet : _.props.elementSet, /* qqq : cover */ + _elementWithKeySet : _.props._elementWithKeySet, + elementWithKeySet : _.props.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet : _.props._elementWithCardinalSet, + elementWithCardinalSet : _.props.elementWithCardinalSet, /* qqq : cover */ + _empty : _.props._empty, + empty : _.props.empty, /* qqq : for junior : cover */ + + _elementDel : _.props._elementDel, + elementDel : _.props.elementDel, /* qqq : cover */ + _elementWithKeyDel : _.props._elementWithKeyDel, + elementWithKeyDel : _.props.elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel : _.props._elementWithCardinalDel, + elementWithCardinalDel : _.props.elementWithCardinalDel, /* qqq : cover */ + + _each : _.props._each, + each : _.props.each, /* qqq : cover */ + _eachLeft : _.props._eachLeft, + eachLeft : _.props.eachLeft, /* qqq : cover */ + _eachRight : _.props._eachRight, + eachRight : _.props.eachRight, /* qqq : cover */ + + _while : _.props._while, + while : _.props.while, /* qqq : cover */ + _whileLeft : _.props._whileLeft, + whileLeft : _.props.whileLeft, /* qqq : cover */ + _whileRight : _.props._whileRight, + whileRight : _.props.whileRight, /* qqq : cover */ + + _aptLeft : _.props._aptLeft, + aptLeft : _.props.aptLeft, /* qqq : cover */ + first : _.props.first, + _aptRight : _.props._aptRight, /* qqq : cover */ + aptRight : _.props.aptRight, + last : _.props.last, /* qqq : cover */ + + _filterAct0 : _.props._filterAct0, + _filterAct : _.props._filterAct, + filterWithoutEscapeLeft : _.props.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.props.filterWithoutEscapeRight, + filterWithoutEscape : _.props.filterWithoutEscape, + filterWithEscapeLeft : _.props.filterWithEscapeLeft, + filterWithEscapeRight : _.props.filterWithEscapeRight, + filterWithEscape : _.props.filterWithEscape, + filter : _.props.filter, + + _mapAct0 : _.props._mapAct0, + _mapAct : _.props._mapAct, + mapWithoutEscapeLeft : _.props.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.props.mapWithoutEscapeRight, + mapWithoutEscape : _.props.mapWithoutEscape, + mapWithEscapeLeft : _.props.mapWithEscapeLeft, + mapWithEscapeRight : _.props.mapWithEscapeRight, + mapWithEscape : _.props.mapWithEscape, + map : _.props.map, + +} + +Object.assign( _.aux, AuxiliaryExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Auxiliary.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Auxiliary_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Auxiliary_s */ })(); + +/* */ /* begin of file Bool_s */ ( function Bool_s() { function Bool_s_naked() { ( function _l3_Bool_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// bool +// -- + +/** + * @summary Returns copy of array( src ) with only boolean elements. + * @description + * Returns false if ( src ) is not ArrayLike object. + * @function boolsAre + * @param {Array} src - array of entities + * @throws {Error} If more or less than one argument is provided. + * @namespace Tools + */ + +function are( src ) +{ + _.assert( arguments.length === 1 ); + if( !_.argumentsArray.like( src ) ) + return false; + return src.filter( ( e ) => _.bool.is( e ) ); +} + +// + +/** + * @summary Checks if all elements of array( src ) are booleans. + * @description + * * If ( src ) is not an array, routine checks if ( src ) is a boolean. + * @function boolsAllAre + * @param {Array} src - array of entities + * @throws {Error} If more or less than one argument is provided. + * @namespace Tools + */ + +function allAre( src ) +{ + _.assert( arguments.length === 1 ); + if( !_.arrayIs( src ) ) + return _.bool.is( src ); + return _.all( src.filter( ( e ) => _.bool.is( e ) ) ); +} + +// + +/** + * @summary Checks if at least one element from array( src ) is a boolean. + * @description + * * If ( src ) is not an array, routine checks if ( src ) is a boolean. + * @function boolsAnyAre + * @param {Array} src - array of entities + * @throws {Error} If more or less than one argument is provided. + * @namespace Tools + */ + +function anyAre( src ) +{ + _.assert( arguments.length === 1 ); + if( !_.arrayIs( src ) ) + return _.bool.is( src ); + return !!_.any( src.filter( ( e ) => _.bool.is( e ) ) ); +} + +// + +/** + * @summary Checks if array( src ) doesn't have booleans. + * @description + * * If ( src ) is not an array, routine checks if ( src ) is not a boolean. + * @function boolsAnyAre + * @param {Array} src - array of entities + * @throws {Error} If more or less than one argument is provided. + * @namespace Tools + */ + +function noneAre( src ) +{ + _.assert( arguments.length === 1 ); + if( !_.arrayIs( src ) ) + return _.bool.is( src ); + return _.none( src.filter( ( e ) => _.bool.is( e ) ) ); +} + +// // +// +// function areEquivalentShallow( src1, src2 ) +// { +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// _.assert( _.bool.like( src1 ) ); +// _.assert( _.bool.like( src2 ) ); +// +// if +// ( +// ( _.bool.likeTrue( src1 ) && _.bool.likeTrue( src2 ) ) +// || ( ( _.bool.likeFalse( src1 ) && _.bool.likeFalse( src2 ) ) ) +// ) +// return true; +// +// return false; +// } + +// + +function _identicalShallow( src1, src2 ) +{ + if( src1 === src2 ) + return true; + return false; +} + +// + +function identicalShallow( src1, src2, o ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( !this.like( src1 ) ) + return false; + if( !this.like( src2 ) ) + return false; + return this._identicalShallow( src1, src2 ); +} + +// + +function _equivalentShallow( src1, src2 ) +{ + if + ( + ( _.bool.likeTrue( src1 ) && _.bool.likeTrue( src2 ) ) + || ( ( _.bool.likeFalse( src1 ) && _.bool.likeFalse( src2 ) ) ) + ) + return true; + return false; +} + +// + +function equivalentShallow( src1, src2, o ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( !this.like( src1 ) ) + return false; + if( !this.like( src2 ) ) + return false; + return this._equivalentShallow( src1, src2 ); +} + +// -- +// bool extension +// -- + +let BoolExtension = +{ + + // equaler + + _identicalShallow, + identicalShallow, + identical : identicalShallow, + _equivalentShallow, + equivalentShallow, + equivalent : equivalentShallow, + +} + +Object.assign( _.bool, BoolExtension ); + +// -- +// bools +// -- + +let BoolsExtension = +{ + + are, + allAre, + anyAre, + noneAre, + +} + +Object.assign( _.bools, BoolsExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + boolsAre : are, + boolsAllAre : allAre, + boolsAnyAre : anyAre, + boolsNoneAre : noneAre, + +} + +Object.assign( _, ToolsExtension ); + +// + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Bool.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Bool_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Bool_s */ })(); + +/* */ /* begin of file Buffer_s */ ( function Buffer_s() { function Buffer_s_naked() { ( function _l3_Buffer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// dichotomy +// -- + +function constructorIsBuffer( src ) +{ + if( !src ) + return false; + if( !_.number.is( src.BYTES_PER_ELEMENT ) ) + return false; + if( !_.strIs( src.name ) ) + return false; + return src.name.indexOf( 'Array' ) !== -1; +} + +// -- +// maker +// -- + +function bufferCoerceFrom( o ) +{ + let result; + + _.assert( arguments.length === 1 ); + _.assert( _.routine.is( o.bufferConstructor ), 'Expects bufferConstructor' ); + // _.map.assertHasOnly( o, bufferCoerceFrom.defaults ); + + if( Config.debug ) + { + for( let k in bufferCoerceFrom.defaults ) + { + if( o[ k ] === undefined ) + throw Error( `Expects defined option::${k}` ); + } + for( let k in o ) + { + if( bufferCoerceFrom.defaults[ k ] === undefined ) + throw Error( `Unknown option::${k}` ); + } + } + + if( o.src === null || _.number.is( o.src ) ) + { + if( o.bufferConstructor.name === 'Buffer' ) + return o.bufferConstructor.alloc( o.src ? o.src : 0 ); + else if( o.bufferConstructor.name === 'DataView' ) + return new o.bufferConstructor( new U8x( o.src ).buffer ) + return new o.bufferConstructor( o.src ); + } + + _.assert( _.bufferAnyIs( o.src ) || _.long.is( o.src ) || _.strIs( o.src ) ); + + if( _.strIs( o.src ) ) + o.src = _.bufferBytesFrom( o.src ); + + /* */ + + if( o.src.constructor === o.bufferConstructor ) + return o.src; + + /* */ + + if( _.bufferViewIs( o.src ) ) + o.src = o.src.buffer.slice( o.src.byteOffset, o.src.byteLength ); + + if( _.constructorIsBuffer( o.bufferConstructor ) ) + return new o.bufferConstructor( o.src ); + + if( o.bufferConstructor.name === 'Buffer' ) + return o.bufferConstructor.from( o.src ); + + if( o.bufferConstructor.name === 'DataView' ) + return new o.bufferConstructor( new U8x( o.src ).buffer ); + + if( o.bufferConstructor.name === 'ArrayBuffer' ) + return new U8x( o.src ).buffer; + + if( o.bufferConstructor.name === 'SharedArrayBuffer' ) + { + let srcTyped = _.bufferRawIs( o.src ) ? new U8x( o.src ) : o.src; + let result = new BufferRawShared( srcTyped.length ); + let resultTyped = new U8x( result ); + for( let i = 0; i < srcTyped.length; i++ ) + resultTyped[ i ] = srcTyped[ i ]; + return result; + } +} + +bufferCoerceFrom.defaults = +{ + src : null, + bufferConstructor : null, +} + +// -- +// equaler +// -- + +// /* qqq : extend test */ +// function identicalShallow( src1, src2, o ) +// { +// _.assert( arguments.length === 2 || arguments.length === 3 ); +// +// if( !this.like( src1 ) ) +// return false; +// if( !this.like( src2 ) ) +// return false; +// +// return this._identicalShallow( src1, src2 ); +// } +// +// // +// +// function _identicalShallow( src1, src2 ) +// { +// let result = true; +// +// if( src1.length !== src2.length ) +// return false; +// +// for( let s = 0 ; s < src1.length ; s++ ) +// { +// result = src1[ s ] === src2[ s ]; +// if( result === false ) +// return false; +// } +// +// return result; +// } + +function buffersTypedAreEquivalent( src1, src2, accuracy ) +{ + + if( !_.long.is( src1 ) ) + return false; + if( !_.long.is( src2 ) ) + return false; + + if( src1.length !== src2.length ) + return false; + + if( accuracy === null || accuracy === undefined ) + accuracy = _.accuracy; + + for( let i = 0 ; i < src1.length ; i++ ) + if( Math.abs( src1[ i ] - src2[ i ] ) > accuracy ) + return false; + + return true; +} + +// + +function buffersTypedAreIdentical( src1, src2 ) +{ + + if( !_.bufferTypedIs( src1 ) ) + return false; + if( !_.bufferTypedIs( src2 ) ) + return false; + + let t1 = Object.prototype.toString.call( src1 ); + let t2 = Object.prototype.toString.call( src2 ); + if( t1 !== t2 ) + return false; + + if( src1.length !== src2.length ) + return false; + + for( let i = 0 ; i < src1.length ; i++ ) + if( !Object.is( src1[ i ], src2[ i ] ) ) + return false; + + return true; +} + +// + +function buffersRawAreIdentical( src1, src2 ) +{ + + if( !_.bufferRawIs( src1 ) ) + return false; + if( !_.bufferRawIs( src2 ) ) + return false; + + if( src1.byteLength !== src2.byteLength ) + return false; + + src1 = new U8x( src1 ); + src2 = new U8x( src2 ); + + for( let i = 0 ; i < src1.length ; i++ ) + if( src1[ i ] !== src2[ i ] ) + return false; + + return true; +} + +// + +function buffersViewAreIdentical( src1, src2 ) +{ + + if( !_.bufferViewIs( src1 ) ) + return false; + if( !_.bufferViewIs( src2 ) ) + return false; + + if( src1.byteLength !== src2.byteLength ) + return false; + + for( let i = 0 ; i < src1.byteLength ; i++ ) + if( src1.getUint8( i ) !== src2.getUint8( i ) ) + return false; + + return true; +} + +// + +function buffersNodeAreIdentical( src1, src2 ) +{ + + if( !_.bufferNodeIs( src1 ) ) + return false; + if( !_.bufferNodeIs( src2 ) ) + return false; + + return src1.equals( src2 ); +} + +// + +function _equivalentShallow( src1, src2, accuracy ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + if( _.bufferTypedIs( src1 ) ) + return _.buffersTypedAreEquivalent( src1, src2, accuracy ); + else if( _.bufferRawIs( src1 ) ) + return _.buffersRawAreIdentical( src1, src2 ); + else if( _.bufferViewIs( src1 ) ) + return _.buffersViewAreIdentical( src1, src2 ); + else if( _.bufferNodeIs( src1 ) ) + return _.buffersNodeAreIdentical( src1, src2 ); + else return false; + +} + +// + +function equivalentShallow( src1, src2, o ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( !_.buffer.like( src1 ) ) + return false; + if( !_.buffer.like( src2 ) ) + return false; + + return _.buffer._equivalentShallow( src1, src2 ); +} + +// + +function _identicalShallow( src1, src2 ) +{ + + let t1 = Object.prototype.toString.call( src1 ); + let t2 = Object.prototype.toString.call( src2 ); + if( t1 !== t2 ) + return false; + + if( _.bufferTypedIs( src1 ) ) + return _.buffersTypedAreIdentical( src1, src2 ); + else if( _.bufferRawIs( src1 ) ) + return _.buffersRawAreIdentical( src1, src2 ); + else if( _.bufferViewIs( src1 ) ) + return _.buffersViewAreIdentical( src1, src2 ); + else if( _.bufferNodeIs( src1 ) ) + return _.buffersNodeAreIdentical( src1, src2 ); + else return false; + +} + +// + +function identicalShallow( src1, src2, o ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( !_.buffer.like( src1 ) ) + return false; + if( !_.buffer.like( src2 ) ) + return false; + + return _.buffer._identicalShallow( src1, src2 ); +} + +// -- +// exporter +// -- + +function _exportStringDiagnosticShallow( src ) +{ + if( _.long.is( src ) ) + return _.long._exportStringDiagnosticShallow( src ); + return _.object._exportStringDiagnosticShallow( src ); +} + +// + +function _exportStringCodeShallow( src ) +{ + if( _.long.is( src ) ) + return _.long._exportStringCodeShallow( src ); + return _.object._exportStringCodeShallow( src ); +} + +// -- +// inspector +// -- + +function _lengthOf( src ) +{ + if( _.long.is( src ) || _.bufferNode.is( src ) ) + return src.length; + return _.itself._lengthOf( ... arguments ); +} + +// + +function _hasKey( src, key ) +{ + if( _.long.is( src ) || _.bufferNode.is( src ) ) + return _.long._hasKey( ... arguments ); + return _.itself._hasKey( ... arguments ); +} + +// + +function _hasCardinal( src, cardinal ) +{ + if( _.long.is( src ) || _.bufferNode.is( src ) ) + return _.long._hasCardinal( ... arguments ); + return _.itself._hasCardinal( ... arguments ); +} + +// + +function _keyWithCardinal( src, cardinal ) +{ + if( _.long.is( src ) || _.bufferNode.is( src ) ) + return _.long._keyWithCardinal( ... arguments ); + return _.itself._keyWithCardinal( ... arguments ); +} + +// -- +// editor +// -- + +function _empty( dst ) +{ + throw _.err( `${this.TypeName} has fixed length` ); + return false; +} + +// -- +// elementor +// -- + +function _elementWithKey( src, key ) +{ + if( _.long.is( src ) || _.bufferNode.is( src ) ) + return _.long._elementWithKey( ... arguments ); + return _.itself._elementWithKey( ... arguments ); +} + +// + +function _elementWithImplicit( src, key ) +{ + if( _.props.keyIsImplicit( key ) ) + return _.props._onlyImplicitWithKeyTuple( src, key ); + return this._elementWithKey( src, key ); +} + +// + +function _elementWithCardinal( src, cardinal ) +{ + if( _.long.is( src ) || _.bufferNode.is( src ) ) + return _.long._elementWithCardinal( ... arguments ); + return _.itself._elementWithCardinal( ... arguments ); +} + +// + +function _elementWithKeySet( dst, key, val ) +{ + if( _.long.is( dst ) || _.bufferNode.is( dst ) ) + return _.long._elementWithKeySet( ... arguments ); + return _.itself._elementWithKeySet( ... arguments ); +} + +// + +function _elementWithCardinalSet( dst, cardinal, val ) +{ + if( _.long.is( dst ) || _.bufferNode.is( dst ) ) + return _.long._elementWithCardinalSet( ... arguments ); + return _.itself._elementWithCardinalSet( ... arguments ); +} + +// + +function _elementWithKeyDel( dst, key ) +{ + throw _.err( `${this.TypeName} has fixed length` ); + return false; +} + +// + +function _elementWithCardinalDel( dst, cardinal ) +{ + throw _.err( `${this.TypeName} has fixed length` ); + return false; +} + +// -- +// declaration +// -- + +let BufferExtension = +{ + + /* qqq : implement routines _.long has. discuss first */ + + // equaler + + _identicalShallow, + identicalShallow, + identical : identicalShallow, + _equivalentShallow, + equivalentShallow, + equivalent : equivalentShallow, + + // exporter + + _exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.props.exportStringDiagnosticShallow, + _exportStringCodeShallow, + exportStringCodeShallow : _.props.exportStringCodeShallow, + exportString : _.props.exportString, + + // inspector + + _lengthOf, + lengthOf : _.props.lengthOf, /* qqq : cover */ + _hasKey, + hasKey : _.props.hasKey, /* qqq : cover */ + _hasCardinal, + hasCardinal : _.props.hasCardinal, /* qqq : cover */ + _keyWithCardinal, + keyWithCardinal : _.props.keyWithCardinal, /* qqq : cover */ + + // editor + + _empty, + empty : _.props.elementWithKeyDel, /* qqq : for junior : cover */ + + // elementor + + _elementGet : _elementWithKey, + elementGet : _.props.elementGet, /* qqq : cover */ + _elementWithKey, + elementWithKey : _.props.elementWithKey, /* qqq : cover */ + _elementWithImplicit, + elementWithImplicit : _.props.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal, + elementWithCardinal : _.props.elementWithCardinal, /* qqq : cover */ + + _elementSet : _elementWithKeySet, + elementSet : _.props.elementSet, /* qqq : cover */ + _elementWithKeySet, + elementWithKeySet : _.props.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet, + elementWithCardinalSet : _.props.elementWithCardinalSet, /* qqq : cover */ + + _elementDel : _elementWithKeyDel, + elementDel : _.props.elementDel, /* qqq : cover */ + _elementWithKeyDel, + elementWithKeyDel : _.props.elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel, + elementWithCardinalDel : _.props.elementWithCardinalDel, /* qqq : cover */ + +} + +Object.assign( _.buffer, BufferExtension ); + +// + +let ToolsExtension = +{ + + // dichotomy + + constructorIsBuffer, + + // maker + + bufferCoerceFrom, /* qqq : cover. seems broken */ + + // equaler + + buffersTypedAreEquivalent, /* qqq : cover pelase */ + buffersTypedAreIdentical, /* qqq : cover pelase */ + buffersRawAreIdentical, + buffersViewAreIdentical, + buffersNodeAreIdentical, + buffersAreIdentical : identicalShallow, + buffersIdenticalShallow : identicalShallow, + buffersAreEquivalent : equivalentShallow, + buffersEquivalentShallow : equivalentShallow, + +} + +/* qqq : split namespace of buffers. ask */ +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Buffer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Buffer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Buffer_s */ })(); + +/* */ /* begin of file BuffersTyped_s */ ( function BuffersTyped_s() { function BuffersTyped_s_naked() { ( function _l1_BuffersTyped_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +function _functor( namespace ) +{ + + // -- + // declare + // -- + + let ToolsExtension = + { + } + + Object.assign( _, ToolsExtension ); + + // + + let BufferTypedExtension = + { + + // equaler + + _identicalShallow : _.long._identicalShallow, + identicalShallow : _.long.identicalShallow, + identical : _.long.identical, + _equivalentShallow : _.long._equivalentShallow, + equivalentShallow : _.long.equivalentShallow, + equivalent : _.long.equivalent, + + // exporter + + _exportStringDiagnosticShallow : _.long._exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.long.exportStringDiagnosticShallow, + _exportStringCodeShallow : _.long._exportStringCodeShallow, + exportStringCodeShallow : _.long.exportStringCodeShallow, + exportString : _.long.exportString, + + // container interface + + _lengthOf : _.long._lengthOf, + lengthOf : _.long.lengthOf, /* qqq : cover */ + + _hasKey : _.long._hasKey, + hasKey : _.long._hasKey, /* qqq : cover */ + _hasCardinal : _.long._hasKey, + hasCardinal : _.long._hasKey, /* qqq : cover */ + _keyWithCardinal : _.long._hasKey, + keyWithCardinal : _.long._hasKey, /* qqq : cover */ + _cardinalWithKey : _.long._cardinalWithKey, + cardinalWithKey : _.long.cardinalWithKey, /* qqq : cover */ + + _elementGet : _.long._elementWithKey, + elementGet : _.long.elementWithKey, /* qqq : cover */ + _elementWithKey : _.long._elementWithKey, + elementWithKey : _.long.elementWithKey, /* qqq : cover */ + _elementWithImplicit : _.long._elementWithImplicit, + elementWithImplicit : _.long.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal : _.long._elementWithCardinal, + elementWithCardinal : _.long.elementWithCardinal, /* qqq : cover */ + + _elementSet : _.long._elementSet, + elementSet : _.long.elementSet, /* qqq : cover */ + _elementWithKeySet : _.long._elementWithKeySet, + elementWithKeySet : _.long.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet : _.long._elementWithCardinalSet, + elementWithCardinalSet : _.long.elementWithCardinalSet, /* qqq : cover */ + + _elementAppend : _.argumentsArray._elementAppend, + elementAppend : _.argumentsArray.elementAppend, /* qqq : cover */ + _elementPrepend : _.argumentsArray._elementPrepend, + elementPrepend : _.argumentsArray.elementPrepend, /* qqq : cover */ + + _elementDel : _.argumentsArray._elementDel, + elementDel : _.argumentsArray.elementDel, /* qqq : cover */ + _elementWithKeyDel : _.argumentsArray._elementWithKeyDel, + elementWithKeyDel : _.argumentsArray.elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel : _.argumentsArray._elementWithCardinalDel, + elementWithCardinalDel : _.argumentsArray.elementWithCardinalDel, /* qqq : cover */ + _empty : _.argumentsArray._empty, + empty : _.argumentsArray.empty, /* qqq : for junior : cover */ + + _each : _.long._each, + each : _.long.each, /* qqq : cover */ + _eachLeft : _.long._eachLeft, + eachLeft : _.long.eachLeft, /* qqq : cover */ + _eachRight : _.long._eachRight, + eachRight : _.long.eachRight, /* qqq : cover */ + + _while : _.long._while, + while : _.long.while, /* qqq : cover */ + _whileLeft : _.long._whileLeft, + whileLeft : _.long.whileLeft, /* qqq : cover */ + _whileRight : _.long._whileRight, + whileRight : _.long.whileRight, /* qqq : cover */ + + _aptLeft : _.long._aptLeft, + aptLeft : _.long.aptLeft, /* qqq : cover */ + first : _.long.first, + _aptRight : _.long._aptRight, /* qqq : cover */ + aptRight : _.long.aptRight, + last : _.long.last, /* qqq : cover */ + + _filterAct : _.long._filterAct, + filterWithoutEscapeLeft : _.long.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.long.filterWithoutEscapeRight, + filterWithoutEscape : _.long.filterWithoutEscape, + filterWithEscapeLeft : _.long.filterWithEscapeLeft, + filterWithEscapeRight : _.long.filterWithEscapeRight, + filterWithEscape : _.long.filterWithEscape, + filter : _.long.filter, + + _mapAct : _.long._mapAct, + mapWithoutEscapeLeft : _.long.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.long.mapWithoutEscapeRight, + mapWithoutEscape : _.long.mapWithoutEscape, + mapWithEscapeLeft : _.long.mapWithEscapeLeft, + mapWithEscapeRight : _.long.mapWithEscapeRight, + mapWithEscape : _.long.mapWithEscape, + map : _.long.map, + + } + + // + + Object.assign( namespace, BufferTypedExtension ); + +} + +_.assert( !!_.fx ); +_.assert( !_.fx.filter ); +_.assert( !_.fx.map ); + +for( let name in _.long.namespaces ) +{ + let namespace = _.long.namespaces[ name ]; + if( namespace.IsTyped ) + _functor( namespace ); +} + +_.assert( !!_.fx.filter ); +_.assert( !!_.fx.map ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/BuffersTyped.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, BuffersTyped_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file BuffersTyped_s */ })(); + +/* */ /* begin of file BufferTyped_s */ ( function BufferTyped_s() { function BufferTyped_s_naked() { ( function _l3_BufferTyped_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( !!_.long._aptLeft, 'Expects routine props._aptLeft' ); +_.assert( !!_.long._elementWithKey, 'Expects routine long._elementWithKey' ); + +// -- +// extension +// -- + +var BufferTypedExtension = +{ + + // equaler + + _identicalShallow : _.long._identicalShallow, + identicalShallow : _.long.identicalShallow, + identical : _.long.identical, + _equivalentShallow : _.long._equivalentShallow, + equivalentShallow : _.long.equivalentShallow, + equivalent : _.long.equivalent, + + // exporter + + _exportStringDiagnosticShallow : _.long._exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.long.exportStringDiagnosticShallow, + _exportStringCodeShallow : _.long._exportStringCodeShallow, + exportStringCodeShallow : _.long.exportStringCodeShallow, + exportString : _.long.exportString, + + // container interface + + _lengthOf : _.long._lengthOf, + lengthOf : _.long.lengthOf, /* qqq : cover */ + + _hasKey : _.long._hasKey, + hasKey : _.long._hasKey, /* qqq : cover */ + _hasCardinal : _.long._hasKey, + hasCardinal : _.long._hasKey, /* qqq : cover */ + _keyWithCardinal : _.long._hasKey, + keyWithCardinal : _.long._hasKey, /* qqq : cover */ + _cardinalWithKey : _.long._cardinalWithKey, + cardinalWithKey : _.long.cardinalWithKey, /* qqq : cover */ + + _elementGet : _.long._elementWithKey, + elementGet : _.long.elementWithKey, /* qqq : cover */ + _elementWithKey : _.long._elementWithKey, + elementWithKey : _.long.elementWithKey, /* qqq : cover */ + _elementWithImplicit : _.long._elementWithImplicit, + elementWithImplicit : _.long.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal : _.long._elementWithCardinal, + elementWithCardinal : _.long.elementWithCardinal, /* qqq : cover */ + + _elementSet : _.long._elementSet, + elementSet : _.long.elementSet, /* qqq : cover */ + _elementWithKeySet : _.long._elementWithKeySet, + elementWithKeySet : _.long.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet : _.long._elementWithCardinalSet, + elementWithCardinalSet : _.long.elementWithCardinalSet, /* qqq : cover */ + + _elementAppend : _.argumentsArray._elementAppend, + elementAppend : _.argumentsArray.elementAppend, /* qqq : cover */ + _elementPrepend : _.argumentsArray._elementPrepend, + elementPrepend : _.argumentsArray.elementPrepend, /* qqq : cover */ + + _elementDel : _.argumentsArray._elementDel, + elementDel : _.argumentsArray.elementDel, /* qqq : cover */ + _elementWithKeyDel : _.argumentsArray._elementWithKeyDel, + elementWithKeyDel : _.argumentsArray.elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel : _.argumentsArray._elementWithCardinalDel, + elementWithCardinalDel : _.argumentsArray.elementWithCardinalDel, /* qqq : cover */ + _empty : _.argumentsArray._empty, + empty : _.argumentsArray.empty, /* qqq : for junior : cover */ + + _each : _.long._each, + each : _.long.each, /* qqq : cover */ + _eachLeft : _.long._eachLeft, + eachLeft : _.long.eachLeft, /* qqq : cover */ + _eachRight : _.long._eachRight, + eachRight : _.long.eachRight, /* qqq : cover */ + + _while : _.long._while, + while : _.long.while, /* qqq : cover */ + _whileLeft : _.long._whileLeft, + whileLeft : _.long.whileLeft, /* qqq : cover */ + _whileRight : _.long._whileRight, + whileRight : _.long.whileRight, /* qqq : cover */ + + _aptLeft : _.long._aptLeft, + aptLeft : _.long.aptLeft, /* qqq : cover */ + first : _.long.first, + _aptRight : _.long._aptRight, /* qqq : cover */ + aptRight : _.long.aptRight, + last : _.long.last, /* qqq : cover */ + + _filterAct : _.long._filterAct, + filterWithoutEscapeLeft : _.long.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.long.filterWithoutEscapeRight, + filterWithoutEscape : _.long.filterWithoutEscape, + filterWithEscapeLeft : _.long.filterWithEscapeLeft, + filterWithEscapeRight : _.long.filterWithEscapeRight, + filterWithEscape : _.long.filterWithEscape, + filter : _.long.filter, + + _mapAct : _.long._mapAct, + mapWithoutEscapeLeft : _.long.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.long.mapWithoutEscapeRight, + mapWithoutEscape : _.long.mapWithoutEscape, + mapWithEscapeLeft : _.long.mapWithEscapeLeft, + mapWithEscapeRight : _.long.mapWithEscapeRight, + mapWithEscape : _.long.mapWithEscape, + map : _.long.map, + +} + +Object.assign( _.bufferTyped, BufferTypedExtension ); + +// + +var ToolsExtension = +{ +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/BufferTyped.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, BufferTyped_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file BufferTyped_s */ })(); + +/* */ /* begin of file Container_s */ ( function Container_s() { function Container_s_naked() { ( function _l3_Container_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const _functor_functor = _.container._functor_functor; + +// -- +// exporter +// -- + +function _exportStringDiagnosticShallow( src, o ) +{ + let result; + let namespace = this.namespaceForExporting( src ); + + if( namespace ) + result = namespace.exportStringDiagnosticShallow( src ); + else + result = _.strShort_( String( src ) ).result; + + return result; +} + +// + +function exportStringDiagnosticShallow( src, o ) +{ + let result; + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects 1 or 2 arguments' ); + _.assert( this.like( src ) ); + return this._exportStringDiagnosticShallow( ... arguments ); +} + +// -- +// properties +// -- + +function keys( src ) +{ + _.assert( arguments.length === 1 ); + return keys.functor.call( this, src )(); +} + +keys.functor = _functor_functor( 'keys' ); + +// + +function vals( src ) +{ + _.assert( arguments.length === 1 ); + return vals.functor.call( this, src )(); +} + +vals.functor = _functor_functor( 'vals' ); + +// + +function pairs( src ) +{ + _.assert( arguments.length === 1 ); + return pairs.functor.call( this, src )(); +} + +pairs.functor = _functor_functor( 'pairs' ); + +// -- +// inspector +// -- + +function lengthOf( src ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 1 ); + return lengthOf.functor.call( this, src )(); +} + +lengthOf.functor = _functor_functor( 'lengthOf' ); + +// + +function hasKey( src, ... args ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 2 ); + return hasKey.functor.call( this, src )( ... args ); +} + +hasKey.functor = _functor_functor( 'hasKey' ); + +// + +function hasCardinal( src, ... args ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 2 ); + return hasCardinal.functor.call( this, src )( ... args ); +} + +hasCardinal.functor = _functor_functor( 'hasCardinal' ); + +// + +function keyWithCardinal( src, ... args ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 2 ); + return keyWithCardinal.functor.call( this, src )( ... args ); +} + +keyWithCardinal.functor = _functor_functor( 'keyWithCardinal' ); + +// + +function cardinalWithKey( src, ... args ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 2 ); + return cardinalWithKey.functor.call( this, src )( ... args ); +} + +cardinalWithKey.functor = _functor_functor( 'cardinalWithKey' ); + +// -- +// editor +// -- + +// function empty( src ) /* qqq for junior : cover please */ +// { +// _.assert( arguments.length === 1 ); +// return empty.functor.call( this, src )(); +// } +// +// empty.functor = _functor_functor( 'empty' ); + +// + +/** + * The routine elementWithCardinal() searches for value under a certain index {-key-} in a src {-src-} + * and returns array with value, key, booLike. + * + * @param { Long|Set|HashMap|Aux } src - input src. + * @param { Number } key - index to be looked in a src. + * + * @example + * var src = { a : 1, b : 2 }; + * var got = _.src.elementWithCardinal( src, 0 ); + * console.log( got ); + * // log : [ 1, 'a', true ] + * + * @example + * var src = [ 1, 2, 3 ]; + * var got = _.src.elementWithCardinal( src, 2 ); + * console.log( got ); + * // log : [ 3, 2, true ] + * + * @example + * var src = new HashMap([ [ 'a', 1 ], [ true, false ], [ objRef, { a : 2 } ] ]); + * var got = _.src.elementWithCardinal( src, 1 ); + * console.log( got ) + * // log : [ false, true, true ] ); + * + * @example + * var src = [ 1, 2, 3 ]; + * var got = _.src.elementWithCardinal( src, 5 ); + * console.log( got ); + * // log : [ undefined, 5, false ] + * + * @returns { Long } - with 3 elements : value ( undefined if index {-key-} is more or less than src's length ), key, boolLike ( true if index {-key-} is within src's length, false otherwise ). + * @function elementWithCardinal + * @throws { Error } If arguments.length is not equal to 2. + * @throws { Error } If {-key-} is not Number. + * @namespace Tools + */ + +function elementWithCardinal( src, key ) /* qqq for junior : cover please | aaa : Done. */ +{ + _.assert( arguments.length === 2 ); + _.assert( _.numberIs( key ) ); + if( !_.numberIs( key ) || key < 0 ) + return [ undefined, key, false ]; + return elementWithCardinal.functor.call( this, src )( key ); +} + +elementWithCardinal.functor = _functor_functor( 'elementWithCardinal' ); + +// + +/** + * The routine elementWithKey() searches for value under a certain {-key-} in a src {-src-} + * and returns array with value, key, booLike. + * + * @param { Long|Set|HashMap|Aux } src - input src. + * @param { * } key - key to be looked in a src. + * + * @example + * var src = { a : 1, b : 2 }; + * var got = _.src.elementWithKey( src, 'a' ); + * console.log( got ); + * // log : [ 1, 'a', true ] + * + * @example + * var src = [ 1, 2, 3 ]; + * var got = _.src.elementWithKey( src, 2 ); + * console.log( got ); + * // log : [ 3, 2, true ] + * + * @example + * var src = new HashMap([ [ 'a', 1 ], [ true, false ], [ objRef, { a : 2 } ] ]); + * var got = _.src.elementWithKey( src, true ); + * console.log( got ) + * // log : [ false, true, true ] ); + * + * @example + * var src = [ 1, 2, 3 ]; + * var got = _.src.elementWithKey( src, 5 ); + * console.log( got ); + * // log : [ undefined, 5, false ] + * + * @returns { Long } - with 3 elements : value ( undefined if key is absent ), key, boolLike ( true if key exists, false otherwise ). + * @function elementWithKey + * @throws { Error } If arguments.length is not equal to 2. + * @namespace Tools + */ + +function elementWithKey( src, key ) +{ + _.assert( arguments.length === 2 ); + return elementWithKey.functor.call( this, src )( key ); +} + +elementWithKey.functor = _functor_functor( 'elementWithKey' ); + +// + +function elementWithImplicit( src, key ) +{ + _.assert( arguments.length === 2 ); + return elementWithImplicit.functor.call( this, src )( key ); +} + +elementWithImplicit.functor = _functor_functor( 'elementWithImplicit' ); + +// + +function elementWithCardinalSet( src, key, val ) +{ + _.assert( arguments.length === 3 ); + _.assert( _.numberIs( key ) ); + return elementWithCardinalSet.functor.call( this, src )( key, val ); +} + +elementWithCardinalSet.functor = _functor_functor( 'elementWithCardinalSet' ); + +// + +function elementSet( src, key, val ) +{ + _.assert( arguments.length === 3 ); + return elementSet.functor.call( this, src )( key, val ); +} + +elementSet.functor = _functor_functor( 'elementSet' ); + +// -- +// +// -- + +function elementDel( src, key ) +{ + _.assert( arguments.length === 2 ); + return elementDel.functor.call( this, src )( key ); +} + +elementDel.functor = _functor_functor( 'elementDel' ); + +// + +function elementWithKeyDel( src, key ) +{ + _.assert( arguments.length === 2 ); + return elementWithKeyDel.functor.call( this, src )( key ); +} + +elementWithKeyDel.functor = _functor_functor( 'elementWithKeyDel' ); + +// + +function elementWithCardinalDel( src, key ) +{ + _.assert( arguments.length === 2 ); + return elementWithCardinalDel.functor.call( this, src )( key ); +} + +elementWithCardinalDel.functor = _functor_functor( 'elementWithCardinalDel' ); + +// + +/** + * The routine empty() clears provided container {-dstContainer-}. + * + * @param { Long|Set|HashMap|Aux } dstContainer - Container to be cleared. {-dstContainer-} should be resizable. + * + * @example + * let dst = []; + * let got = _.src.empty( dst ); + * console.log( got ); + * // log [] + * console.log( got === dst ); + * log true + * + * @example + * let dst = [ 1, 'str', { a : 2 } ]; + * let got = _.src.empty( dst ); + * console.log( got ); + * // log [] + * console.log( got === dst ); + * // log true + * + * @example + * let dst = _.unroll.make( [ 1, 'str', { a : 2 } ] ); + * let got = _.src.empty( dst ); + * console.log( got ); + * // log [] + * console.log( got === dst ); + * // log true + * + * @example + * let dst = new Set( [ 1, 'str', { a : 2 } ] ); + * let got = _.src.empty( dst ); + * console.log( got ); + * // log Set {} + * console.log( got === dst ); + * // log true + * + * @example + * let dst = new HashMap( [ [ 1, 'str' ], [ 'a', null ] ] ); + * let got = _.src.empty( dst ); + * console.log( got ); + * // log Map {} + * console.log( got === dst ); + * // log true + * + * @returns { Long|Set|HashMap|Aux } - Returns a empty {-dstContainer-}. + * @function empty + * @throws { Error } If arguments.length is less than one. + * @throws { Error } If {-dstContainer-} is not a Long, not a Set, not a HashMap, not a Aux. + * @throws { Error } If {-dstContainer-} is not a resizable Long, or if it is a WeakSet or WeakMap. + * @namespace Tools + */ + +function empty( src ) +{ + _.assert( arguments.length === 1 ); + return empty.functor.call( this, src )(); +} + +empty.functor = _functor_functor( 'empty' ); + + // elementDel, /* qqq : cover */ + // elementWithKeyDel, /* qqq : cover */ + // elementWithCardinalDel, /* qqq : cover */ + // empty, /* qqq : for junior : cover */ + +// -- +// iterator +// -- + +function eachLeft( src, onEach ) +{ + _.assert( arguments.length === 2 ); + return eachLeft.functor.call( this, src )( onEach ); +} + +eachLeft.functor = _functor_functor( 'eachLeft' ); + +// + +function eachRight( src, onEach ) +{ + _.assert( arguments.length === 2 ); + return eachRight.functor.call( this, src )( onEach ); +} + +eachRight.functor = _functor_functor( 'eachRight' ); + +// + +function whileLeft( src, onEach ) +{ + _.assert( arguments.length === 2 ); + return whileLeft.functor.call( this, src )( onEach ); +} + +whileLeft.functor = _functor_functor( 'whileLeft' ); + +// + +function whileRight( src, onEach ) +{ + _.assert( arguments.length === 2 ); + return whileRight.functor.call( this, src )( onEach ); +} + +whileRight.functor = _functor_functor( 'whileRight' ); + +// + +function aptLeft( src, onEach ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + return aptLeft.functor.call( this, src )( onEach ); +} + +aptLeft.functor = _functor_functor( 'aptLeft' ); + +// + +function aptRight( src, onEach ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + return aptRight.functor.call( this, src )( onEach ); +} + +aptRight.functor = _functor_functor( 'aptRight' ); + +// + +function filterWithoutEscapeLeft( dst, src, ... args ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + return filterWithoutEscapeLeft.functor.call( this, src )( dst, ... args ); +} + +filterWithoutEscapeLeft.functor = _functor_functor( 'filterWithoutEscapeLeft', null, 1 ); + +// + +function filterWithoutEscapeRight( dst, src, ... args ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + return filterWithoutEscapeRight.functor.call( this, src )( dst, ... args ); +} + +filterWithoutEscapeRight.functor = _functor_functor( 'filterWithoutEscapeRight', null, 1 ); + +// + +function filterWithEscapeLeft( dst, src, ... args ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + return filterWithEscapeLeft.functor.call( this, src )( dst, ... args ); +} + +filterWithEscapeLeft.functor = _functor_functor( 'filterWithEscapeLeft', null, 1 ); + +// + +function filterWithEscapeRight( dst, src, ... args ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + return filterWithEscapeRight.functor.call( this, src )( dst, ... args ); +} + +filterWithEscapeRight.functor = _functor_functor( 'filterWithEscapeRight', null, 1 ); + +// + +function mapWithoutEscapeLeft( dst, src, ... args ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + return mapWithoutEscapeLeft.functor.call( this, src )( dst, ... args ); +} + +mapWithoutEscapeLeft.functor = _functor_functor( 'mapWithoutEscapeLeft', null, 1 ); + +// + +function mapWithoutEscapeRight( dst, src, ... args ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + return mapWithoutEscapeRight.functor.call( this, src )( dst, ... args ); +} + +mapWithoutEscapeRight.functor = _functor_functor( 'mapWithoutEscapeRight', null, 1 ); + +// + +function mapWithEscapeLeft( dst, src, ... args ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + return mapWithEscapeLeft.functor.call( this, src )( dst, ... args ); +} + +mapWithEscapeLeft.functor = _functor_functor( 'mapWithEscapeLeft', null, 1 ); + +// + +function mapWithEscapeRight( dst, src, ... args ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + return mapWithEscapeRight.functor.call( this, src )( dst, ... args ); +} + +mapWithEscapeRight.functor = _functor_functor( 'mapWithEscapeRight', null, 1 ); + +// -- +// extension +// -- + +let ContainerExtension = +{ + + // exporter + + _exportStringDiagnosticShallow, + exportStringDiagnosticShallow, + _exportStringCodeShallow : _exportStringDiagnosticShallow, + exportStringCodeShallow : exportStringDiagnosticShallow, + exportString : exportStringDiagnosticShallow, + + // properties + + /* xxx : review */ + keys, + vals, + pairs, + + // inspector + + lengthOf, /* qqq : cover */ + hasKey, /* qqq : cover */ + hasCardinal, /* qqq : cover */ + keyWithCardinal, /* qqq : cover */ + cardinalWithKey, /* qqq : cover */ + + // editor + + // empty, /* qqq : cover */ + + // elementor + + elementWithCardinal, /* qqq : cover */ + elementWithKey, /* qqq : cover */ + elementWithImplicit, /* qqq : cover */ + elementWithCardinalSet, /* qqq : cover */ + elementSet, /* qqq : cover */ + + elementDel, /* qqq : cover */ + elementWithKeyDel, /* qqq : cover */ + elementWithCardinalDel, /* qqq : cover */ + empty, /* qqq : for junior : cover */ + + // iterator + + each : eachLeft, /* qqq : cover */ + eachLeft, /* qqq : cover */ + eachRight, /* qqq : cover */ + + while : whileLeft, /* qqq : cover */ + whileLeft, /* qqq : cover */ + whileRight, /* qqq : cover */ + + aptLeft, /* qqq : cover */ + first : aptLeft, /* qqq : cover */ + aptRight, /* qqq : cover */ + last : aptRight, /* qqq : cover */ + + filterWithoutEscapeLeft, + filterWithoutEscapeRight, + filterWithoutEscape : filterWithoutEscapeLeft, + filterWithEscapeLeft, + filterWithEscapeRight, + filterWithEscape : filterWithEscapeLeft, + filter : filterWithoutEscapeLeft, + + mapWithoutEscapeLeft, + mapWithoutEscapeRight, + mapWithoutEscape : mapWithoutEscapeLeft, + mapWithEscapeLeft, + mapWithEscapeRight, + mapWithEscape : mapWithEscapeLeft, + map : mapWithoutEscapeLeft, + + // map, + // filter, + +} + +Object.assign( _.container, ContainerExtension ); + +// + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +// + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Container.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Container_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Container_s */ })(); + +/* */ /* begin of file ContainerAdapter_s */ ( function ContainerAdapter_s() { function ContainerAdapter_s_naked() { ( function _l3_ContainerAdapter_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// exporter +// -- + + + +// -- +// container adapter extension +// -- + +let ContainerAdapterExtension = +{ + +} + +Object.assign( _.containerAdapter, ContainerAdapterExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/ContainerAdapter.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ContainerAdapter_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ContainerAdapter_s */ })(); + +/* */ /* begin of file Countable_s */ ( function Countable_s() { function Countable_s_naked() { ( function _l3_Countable_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// +// -- + +function _identicalShallow( src1, src2 ) +{ + + if( Object.prototype.toString.call( src1 ) !== Object.prototype.toString.call( src2 ) ) + return false; + if( !_.countable.is( src1 ) ) + return false; + if( !_.countable.is( src2 ) ) + return false; + + if( _.longIs( src1 ) ) + { + return _.long.identicalShallow( src1, src2 ); + } + else + { + /* + entity with method iterator, + entity with method iterator and length + */ + + let array1 = [ ... src1 ]; + for( let val of src2 ) + if( array1.indexOf( val ) === -1 ) + return false + + return true; + } + +} + +// + +function _equivalentShallow( src1, src2 ) +{ + let result = true; + + if( _.longIs( src1 ) && _.longIs( src2 ) ) + { + return _.long.equivalentShallow( src1, src2 ); + } + else + { + /* + entity with method iterator, + entity with method iterator and length + */ + + /* don't create new array if one of arguments is array */ + if( _.argumentsArray.like( src1 ) ) + { + result = check( src2, src1 ); + } + else if( _.argumentsArray.like( src2 ) ) + { + result = check( src1, src2 ); + } + else + { + let array1 = [ ... src1 ]; + result = check( src2, array1 ); + } + + return result; + } + + /* - */ + + function check( arrayLoop, arrayCheck ) + { + for( let val of arrayLoop ) + if( Array.prototype.indexOf.call( arrayCheck, val ) === -1 ) + return false + return true; + } +} + +// -- +// exporter +// -- + +function _exportStringDiagnosticShallow( src, o ) +{ + if( _.unroll.is( src ) ) + return `{- ${_.entity.strType( src )}.unroll with ${this._lengthOf( src )} elements -}`; + return `{- ${_.entity.strType( src )} with ${this._lengthOf( src )} elements -}`; +} + +// -- +// container interface +// -- + +function _lengthOf( src ) +{ + if( _.vector.is( src ) ) + return src.length; + return [ ... src ].length; +} + +// + +function _hasKey( src, key ) +{ + if( key < 0 ) + return false; + return key < this._lengthOf( src ); +} + +// + +function _hasCardinal( src, cardinal ) +{ + if( cardinal < 0 ) + return false; + return cardinal < this._lengthOf( src ); +} + +// + +function _keyWithCardinal( src, cardinal ) +{ + if( cardinal < 0 || this._lengthOf( src ) <= cardinal ) + return [ undefined, false ]; + return [ cardinal, true ]; +} + +// + +function _cardinalWithKey( src, key ) +{ + if( key < 0 || this._lengthOf( src ) <= key ) + return -1; + return key; +} + +// + +function _elementWithKey( src, key ) +{ + + if( _.long.is( src ) ) + return _.long._elementWithKey( ... arguments ); + + if( _.number.is( key ) ) + { + if( key < 0 ) + return [ undefined, key, false ]; + debugger; + const src2 = [ ... src ]; + if( src2.length <= key ) + return [ undefined, key, false ]; + else + return [ src2[ key ], key, true ]; + } + else + { + return [ undefined, key, false ]; + } +} + +// + +function _elementWithCardinal( src, cardinal ) +{ + + if( _.long.is( src ) ) + return _.long._elementWithCardinal( ... arguments ); + + if( !_.number.is( cardinal ) || cardinal < 0 ) + return [ undefined, cardinal, false ]; + const src2 = [ ... src ]; + if( src2.length <= cardinal ) + return [ undefined, cardinal, false ]; + else + return [ src2[ cardinal ], cardinal, true ]; +} + +// + +function _elementWithKeySet( dst, key, val ) +{ + + if( _.long.is( dst ) ) + return _.long._elementWithKeySet( ... arguments ); + + if( !_.number.is( key ) || key < 0 ) + return [ key, false ]; + // const dst2 = [ ... dst ]; + // if( dst2.length <= key ) + // return [ key, false ]; + const length = this._lengthOf( dst ); + if( length <= key ) + return [ key, false ]; + + let elementWithKeySet = _.class.methodElementWithKeySetOf( dst ); + if( elementWithKeySet ) + return elementWithKeySet.call( dst, key, val ); + + let elementSet = _.class.methodElementSetOf( dst ); + if( elementSet ) + return [ elementSet.call( dst, key, val ), key, true ]; + + _.assert( 0, 'Countable does not have implemented neither method "elementWithKeySet" nor method "eSet"' ); +} + +// + +function _elementWithCardinalSet( dst, cardinal, val ) +{ + + if( _.long.is( dst ) ) + return _.long._elementWithCardinalSet( ... arguments ); + + if( !_.number.is( cardinal ) || cardinal < 0 ) + return [ cardinal, false ]; + // const dst2 = [ ... dst ]; + // if( dst2.length <= cardinal ) + const length = this._lengthOf( dst ); + if( length <= cardinal ) + return [ cardinal, false ]; + + let was = this._elementWithCardinal( dst, cardinal ); + if( was[ 2 ] ) + this._elementWithKeySet( dst, was[ 1 ], val ); + return [ cardinal, false ]; +} + +// + +function _elementWithKeyDel( dst, key ) +{ + if( _.array.is( dst ) ) + return _.array._elementWithKeyDel( dst, key ); + _.assert( 0, 'Countable does not have implemented method "_elementWithKeyDel"' ); +} + +// + +function _elementWithCardinalDel( dst, cardinal ) +{ + if( _.array.is( dst ) ) + return _.array._elementWithCardinalDel( dst, cardinal ); + _.assert( 0, 'Countable does not have implemented method "_elementWithCardinalDel"' ); +} + +// + +function _empty( dst ) +{ + if( _.array.is( dst ) ) + return _.array._empty( dst ); + _.assert( 0, 'Countable does not have implemented method "_empty"' ); +} + +// + +function _elementAppend( dst, val ) +{ + if( _.array.is( dst ) ) + { + dst.push( val ); + return dst.length-1; + } + _.assert( 0, 'Countable does not have implemented method "_elementAppend"' ); +} + +// + +function _elementPrepend( dst, val ) +{ + if( _.array.is( dst ) ) + { + dst.unshift( val ); + return 0; + } + _.assert( 0, 'Countable does not have implemented method "_elementPrepend"' ); +} + +// + +function _eachLeft( src, onEach ) +{ + let k = 0; + for( let val of src ) + { + onEach( val, k, k, src ); + k += 1; + } +} + +// + +function _eachRight( src, onEach ) +{ + let src2 = [ ... src ]; + for( let k = src2.length-1 ; k >= 0 ; k-- ) + { + let val = src2[ k ]; + onEach( val, k, k, src ); + } +} + +// + +function _whileLeft( src, onEach ) +{ + let k = 0; + let laste; + for( let val of src ) + { + let r = onEach( val, k, k, src ); + _.assert( r === true || r === false ); + if( r === false ) + return [ val, k, false ]; + laste = val; + k += 1; + } + if( k > 0 ) + return [ laste, k-1, k-1, true ]; + else + return [ undefined, k-1, k-1, true ]; +} + +// + +function _whileRight( src, onEach ) +{ + let src2 = [ ... src ]; + for( let k = src2.length-1 ; k >= 0 ; k-- ) + { + let val = src2[ k ]; + let r = onEach( val, k, k, src ); + _.assert( r === true || r === false ); + if( r === false ) + return [ val, k, k, false ]; + } + if( src2.length > 0 ) + return [ src2[ 0 ], 0, 0, true ]; + else + return [ undefined, -1, -1, true ]; +} + +// + +function _filterAct() +{ + let self = this; + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + + if( _.longIs( src ) ) + return _.long._filterAct( ... arguments ); + return _.props._filterAct.call( self, ... arguments ); +} + +// + +function _mapAct() +{ + let self = this; + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + + if( _.longIs( src ) ) + return _.long._mapAct( ... arguments ); + return _.props._mapAct.call( self, ... arguments ); +} + +// -- +// extension +// -- + +var ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +// + +var CountableExtension = +{ + + // equaler + + _identicalShallow, + identicalShallow : _.props.identicalShallow, + identical : _.props.identical, + _equivalentShallow, + equivalentShallow : _.props.equivalentShallow, + equivalent : _.props.equivalent, + + // exporter + + _exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.props.exportStringDiagnosticShallow, + _exportStringCodeShallow : _exportStringDiagnosticShallow, + exportStringCodeShallow : _.props.exportStringCodeShallow, + exportString : _.props.exportString, + + // inspector + + _lengthOf, + lengthOf : _.props.lengthOf, /* qqq : cover */ + _hasKey, + hasKey : _.props.hasKey, /* qqq : cover */ + _hasCardinal, + hasCardinal : _.props.hasCardinal, /* qqq : cover */ + _keyWithCardinal, + keyWithCardinal : _.props.keyWithCardinal, /* qqq : cover */ + _cardinalWithKey, + cardinalWithKey : _.props.cardinalWithKey, /* qqq : cover */ + + // elementor + + _elementGet : _elementWithKey, + elementGet : _.props.elementGet, /* qqq : cover */ + _elementWithKey, + elementWithKey : _.props.elementWithKey, /* qqq : cover */ + _elementWithImplicit : _.props._elementWithImplicit, + elementWithImplicit : _.props.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal, + elementWithCardinal : _.props.elementWithCardinal, /* qqq : cover */ + + _elementSet : _elementWithKeySet, + elementSet : _.props.elementSet, /* qqq : cover */ + _elementWithKeySet, + elementWithKeySet : _.props.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet, + elementWithCardinalSet : _.props.elementWithCardinalSet, /* qqq : cover */ + + _elementDel : _elementWithKeyDel, + elementDel : _.props.elementDel, /* qqq : cover */ + _elementWithKeyDel, + elementWithKeyDel : _.props.elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel, + elementWithCardinalDel : _.props.elementWithCardinalDel, /* qqq : cover */ + _empty, + empty : _.props.empty, /* qqq : for junior : cover */ + + _elementAppend, + elementAppend : _.long.elementAppend, /* qqq : cover */ + _elementPrepend, + elementPrepend : _.long.elementPrepend, /* qqq : cover */ + + // iterator + + _each : _eachLeft, + each : _.props.each, /* qqq : cover */ + _eachLeft, + eachLeft : _.props.eachLeft, /* qqq : cover */ + _eachRight, + eachRight : _.props.eachRight, /* qqq : cover */ + + _while : _whileLeft, + while : _.props.while, /* qqq : cover */ + _whileLeft, + whileLeft : _.props.whileLeft, /* qqq : cover */ + _whileRight, + whileRight : _.props.whileRight, /* qqq : cover */ + + _aptLeft : _.props._aptLeft, + aptLeft : _.props.aptLeft, /* qqq : cover */ + first : _.props.first, + _aptRight : _.props._aptRight, /* qqq : cover */ + aptRight : _.props.aptRight, + last : _.props.last, /* qqq : cover */ + + _filterAct : _.long._filterAct, + filterWithoutEscapeLeft : _.long.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.long.filterWithoutEscapeRight, + filterWithoutEscape : _.long.filterWithoutEscape, + filterWithEscapeLeft : _.long.filterWithEscapeLeft, + filterWithEscapeRight : _.long.filterWithEscapeRight, + filterWithEscape : _.long.filterWithEscape, + filter : _.long.filter, + + _mapAct : _.long._mapAct, + mapWithoutEscapeLeft : _.long.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.long.mapWithoutEscapeRight, + mapWithoutEscape : _.long.mapWithoutEscape, + mapWithEscapeLeft : _.long.mapWithEscapeLeft, + mapWithEscapeRight : _.long.mapWithEscapeRight, + mapWithEscape : _.long.mapWithEscape, + map : _.long.map, + + // _filterAct0 : _.props._filterAct0, + // _filterAct, + // filterWithoutEscapeLeft : _.props.filterWithoutEscapeLeft, + // filterWithoutEscapeRight : _.props.filterWithoutEscapeRight, + // filterWithoutEscape : _.props.filterWithoutEscape, + // filterWithEscapeLeft : _.props.filterWithEscapeLeft, + // filterWithEscapeRight : _.props.filterWithEscapeRight, + // filterWithEscape : _.props.filterWithEscape, + // filter : _.props.filter, + // + // _mapAct0 : _.props._mapAct0, + // _mapAct, + // mapWithoutEscapeLeft : _.props.mapWithoutEscapeLeft, + // mapWithoutEscapeRight : _.props.mapWithoutEscapeRight, + // mapWithoutEscape : _.props.mapWithoutEscape, + // mapWithEscapeLeft : _.props.mapWithEscapeLeft, + // mapWithEscapeRight : _.props.mapWithEscapeRight, + // mapWithEscape : _.props.mapWithEscape, + // map : _.props.map, + +} + +Object.assign( _.countable, CountableExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Countable.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Countable_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Countable_s */ })(); + +/* */ /* begin of file Diagnostic_s */ ( function Diagnostic_s() { function Diagnostic_s_naked() { ( function _l3_Diagnostic_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- +// + +function objectMake( o ) +{ + let result; + + _.assert( arguments.length === 1 ); + + o = optionsAdjust( o ) + + let originalOptions = o; + let constructor = o.pure ? countableConstructorPure : countableConstructorPolluted; + + result = _make( o ); + + return result; + + /* - */ + + function _make( o ) + { + let result; + if( o.new ) + { + if( o.pure ) + result = new countableConstructorPure( o ); + else + result = new countableConstructorPolluted( o ); + } + else + { + result = _objectMake( null, o ); + } + return result; + } + + /* - */ + + function optionsAdjust( o ) + { + _.aux.supplement( o, objectMake.defaults ); + + if( o.countable === null ) + o.countable = true; + if( o.vector === null ) + o.vector = _.number.is( o.length ) ? true : false; + + countableConstructorPure.prototype = Object.create( null ); + + let constructor = o.pure ? countableConstructorPure : countableConstructorPolluted; + + if( o.withConstructor ) + { + countableConstructorPure.prototype.constructor = countableConstructorPure; + _.assert( countableConstructorPolluted.prototype.constructor === countableConstructorPolluted ); + } + else + { + delete countableConstructorPolluted.prototype.constructor; + } + + _.assert( countableConstructorPolluted.prototype !== Object.prototype ); + _.assert( countableConstructorPolluted.prototype !== Function.prototype ); + + if( o.countable ) + if( o.elements === undefined || o.elements === null ) + o.elements = []; + + if( o.vector && o.length === undefined ) + { + _.assert( _.long.is( o.elements ) ); + o.length = o.elements.length; + } + + _.assert( !o.vector || !!o.countable ); + _.assert( !!o.vector === !!_.number.is( o.length ) ); + + return o; + } + + /* */ + + function optionsMake( o ) + { + o = o || Object.create( null ); + return _.props.extend( o, { countable : originalOptions.countable, vector : originalOptions.vector } ); + } + + /* */ + + function TypeNameGet() + { + return 'Custom1'; + } + + /* */ + + function* _iterateGenerator() + { + yield 1; + yield 2; + yield 3; + } + + /* */ + + function _iterate() + { + + let iterator = Object.create( null ); + iterator.next = next; + iterator.index = 0; + iterator.instance = this; + return iterator; + + function next() + { + let result = Object.create( null ); + result.done = this.index === this.instance.elements.length; + if( result.done ) + return result; + result.value = this.instance.elements[ this.index ]; + this.index += 1; + return result; + } + + } + + /* */ + + function countableConstructorPure( o ) + { + if( _.long.is( o ) ) + o = optionsAdjust( optionsMake({ elements : o }) ); + else if( !o ) + o = optionsAdjust( optionsMake() ); + return _objectMake( this, o ); + } + + /* */ + + function countableConstructorPolluted( o ) + { + if( _.long.is( o ) ) + o = optionsAdjust( optionsMake({ elements : o }) ); + else if( !o ) + o = optionsAdjust( optionsMake() ); + let result = _objectMake( this, o ); + if( !o.withConstructor ) + { + _.assert( Object.getPrototypeOf( result ) !== Object.prototype ); + // delete Object.getPrototypeOf( result ).constructor; + _.assert( Object.getPrototypeOf( result ).constructor === Object.prototype.constructor ); + } + return result + } + + /* */ + + function _objectMake( dst, o ) + { + if( dst === null ) + if( o.pure ) + dst = Object.create( null ); + else + dst = {}; + _.props.extend( dst, o ); + + if( o.countable ) + { + if( o.iteratorIsGenerator ) + dst[ Symbol.iterator ] = _iterateGenerator; + else + dst[ Symbol.iterator ] = _iterate; + } + + if( o.withOwnConstructor ) + dst.constructor = constructor; + // dst.constructor = function ownConstructor(){} + + if( !o.basic ) + { + Object.defineProperty( constructor.prototype, Symbol.toStringTag, + { + enumerable : false, + configurable : false, + get : TypeNameGet, + }); + } + + Object.defineProperty( dst, 'makeUndefined', + { + enumerable : false, + configurable : true, + writable : true, + value : makeUndefined, + }); + + Object.defineProperty( dst, 'eSet', + { + enumerable : false, + configurable : true, + writable : true, + value : eSet, + }); + + return dst; + } + + /* */ + + function eSet( key, val ) + { + _.assert( arguments.length === 2 ); + _.assert( _.number.is( key ) ); + this.elements[ key ] = val; + } + + /* */ + + function makeUndefined() + { + debugger; + if( _.object.is( this ) ) + { + let o2 = optionsMake(); + if( o2.elements === null || o2.elements === undefined ) + { + if( _.number.is( this.length ) ) + o2.elements = new Array( this.elements.length ); + if( this.elements && _.number.is( this.elements.length ) ) + o2.elements = new Array( this.elements.length ); + } + optionsAdjust( o2 ); + // return new this.constructor( o2 ); + return _make( o2 ); + } + _.assert( 0 ); + } + + /* */ + +} + +objectMake.defaults = +{ + new : 1, + pure : 0, + basic : 1, + countable : null, + iteratorIsGenerator : 0, + vector : null, + withOwnConstructor : 0, + withConstructor : 1, + elements : null, +} + +// -- +// declare +// -- + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +// + +let DiagnosticExtension = +{ + + objectMake, + /* qqq : for junior : use _.diagnostic.objectMake() in all tests */ + +} + +Object.assign( _.diagnostic, DiagnosticExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Diagnostic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Diagnostic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Diagnostic_s */ })(); + +/* */ /* begin of file Entity_s */ ( function Entity_s() { function Entity_s_naked() { ( function _l3_Entity_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const _functor_functor = _.container._functor_functor; + +_.entity = _.entity || Object.create( null ); + +_.assert( !!_.container.cloneShallow, 'Expects routine _.container.cloneShallow' ); + +// -- +// +// -- + +function identicalShallow( src1, src2, o ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( Object.prototype.toString.call( src1 ) !== Object.prototype.toString.call( src2 ) ) + return false; + + if( src1 === src2 ) + return true; + + if( _.hashMap.like( src1 ) ) + { + /* + - hashMap + */ + return _.hashMap.identicalShallow( src1, src2 ) + } + else if( _.set.like( src1 ) ) + { + /* + - set + */ + return _.set.identicalShallow( src1, src2 ); + } + else if( _.bufferAnyIs( src1 ) ) + { + /* + - BufferNode + - BufferRaw + - BufferRawShared + - BufferTyped + - BufferView + - BufferBytes + */ + return _.buffersIdenticalShallow( src1, src2 ); + } + else if( _.countable.is( src1 ) ) + { + /* + - countable + - vector + - long + - array + */ + return _.countable.identicalShallow( src1, src2 ); + } + else if( _.object.like( src1 ) ) + { + /* + - objectLike + - object + + - Map + - Auxiliary + - MapPure + - MapPolluted + - AuxiliaryPolluted + - MapPrototyped + - AuxiliaryPrototyped + */ + if( _.date.is( src1 ) ) + { + return _.date.identicalShallow( src1, src2 ); + } + else if( _.regexp.is( src1 ) ) + { + return _.regexp.identicalShallow( src1, src2 ); + } + else if( _.aux.is( src1 ) ) + { + return _.aux.identicalShallow( src1, src2 ); + } + + /* non-identical objects */ + return false; + } + else if( _.primitiveIs( src1 ) ) + { + /* + - Symbol + - Number + - BigInt + - Boolean + - String + */ + + return _.primitive.identicalShallow( src1, src2 ); + } + else + { + return false; + } +} + +// + +function equivalentShallow( src1, src2, options ) +{ + /* + - boolLikeTrue and boolLikeTrue - ( true, 1 ) + - boolLikeFalse and boolLikeFalse - ( false, 0 ) + - | number1 - number2 | <= accuracy + - strings that differ only in whitespaces at the start and/or at the end + - regexp with same source and different flags + - countable with the same length and content + */ + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects 2 or 3 arguments' ); + _.assert( options === undefined || _.objectLike( options ), 'Expects map of options as third argument' ); + + let accuracy; + + if( options ) + accuracy = options.accuracy || undefined; + + if( _.primitiveIs( src1 ) && _.primitiveIs( src2 ) ) /* check before type comparison ( 10n & 10 and 1 & true are equivalent ) */ + { + /* + - Symbol + - Number + - BigInt + - Boolean + - String + */ + return _.primitive.equivalentShallow( src1, src2, accuracy ); + } + + if( src1 === src2 ) + return true; + + if( _.bufferAnyIs( src1 ) && _.bufferAnyIs( src2 ) ) + { + /* + - BufferNode + - BufferRaw + - BufferRawShared + - BufferTyped + - BufferView + - BufferBytes + */ + return _.buffersEquivalentShallow( src1, src2 ); + } + else if( _.hashMap.like( src1 ) && _.hashMap.like( src1 ) ) + { + /* + - hashMap + */ + return _.hashMap.equivalentShallow( src1, src2 ) + } + else if( _.set.like( src1 ) && _.set.like( src2 ) ) + { + /* + - set + */ + return _.set.equivalentShallow( src1, src2 ); + } + else if( _.countable.is( src1 ) && _.countable.is( src2 ) ) + { + /* + - countable + - vector + - long + - array + */ + return _.countable.equivalentShallow( src1, src2 ); + } + + if( Object.prototype.toString.call( src1 ) !== Object.prototype.toString.call( src2 ) ) + return false; + + if( _.object.like( src1 ) ) + { + /* + - objectLike + - object + + - Map + - Auxiliary + - MapPure + - MapPolluted + - AuxiliaryPolluted + - MapPrototyped + - AuxiliaryPrototyped + */ + if( _.date.is( src1 ) ) + { + return _.date.equivalentShallow( src1, src2 ); + } + else if( _.regexp.is( src1 ) ) + { + return _.regexp.equivalentShallow( src1, src2 ); + } + else if( _.aux.is( src1 ) ) + { + return _.aux.equivalentShallow( src1, src2 ); + } + + /* non-identical objects */ + return false; + } + else + { + return false; + } +} + +// + +/** + * The routine equal() checks equality of two entities {-src1-} and {-src2-}. + * Routine accepts callbacks {-onEvaluate1-} and {-onEvaluate2-}, which apply to + * entities {-src1-} and {-src2-}. The values returned by callbacks are compared with each other. + * If callbacks is not passed, then routine compares {-src1-} and {-src2-} directly. + * + * @param { * } src1 - First entity to compare. + * @param { * } src2 - Second entity to compare. + * @param { Function } onEvaluate - It's a callback. If the routine has two parameters, + * it is used as an equalizer, and if it has only one, then routine is used as the evaluator. + * @param { Function } onEvaluate2 - The second part of evaluator. Accepts the {-src2-} to search. + * + * @example + * _.entity.equal( 1, 1 ); + * // returns true + * + * @example + * _.entity.equal( 1, 'str' ); + * // returns false + * + * @example + * _.entity.equal( [ 1, 2, 3 ], [ 1, 2, 3 ] ); + * // returns false + * + * @example + * _.entity.equal( [ 1, 2, 3 ], [ 1, 2, 3 ], ( e ) => e[ 0 ] ); + * // returns true + * + * @example + * _.entity.equal( [ 1, 2, 3 ], [ 1, 2, 3 ], ( e1, e2 ) => e1[ 0 ] > e2[ 2 ] ); + * // returns false + * + * @example + * _.entity.equal( [ 1, 2, 3 ], [ 1, 2, 3 ], ( e1 ) => e1[ 2 ], ( e2 ) => e2[ 2 ] ); + * // returns true + * + * @returns { Boolean } - Returns boolean value of equality of two entities. + * @function equal + * @throws { Error } If arguments.length is less then two or more then four. + * @throws { Error } If {-onEvaluate1-} is not a routine. + * @throws { Error } If {-onEvaluate1-} is undefines and onEvaluate2 provided. + * @throws { Error } If {-onEvaluate1-} is evaluator and accepts less or more then one parameter. + * @throws { Error } If {-onEvaluate1-} is equalizer and onEvaluate2 provided. + * @throws { Error } If {-onEvaluate2-} is not a routine. + * @throws { Error } If {-onEvaluate2-} accepts less or more then one parameter. + * @namespace Tools.entity + */ + +function equal( /* src1, src2, onEvaluate1, onEvaluate2 */ ) +{ + let src1 = arguments[ 0 ]; + let src2 = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + + if( !onEvaluate1 ) + { + _.assert( !onEvaluate2 ); + return Object.is( src1, src2 ); + } + else if( onEvaluate1.length === 2 ) /* equalizer */ + { + _.assert( !onEvaluate2 ); + return onEvaluate1( src1, src2 ); + } + else /* evaluator */ + { + if( !onEvaluate2 ) + onEvaluate2 = onEvaluate1; + _.assert( onEvaluate1.length === 1 ); + _.assert( onEvaluate2.length === 1 ); + return onEvaluate1( src1 ) === onEvaluate2( src2 ); + } + +} + +// -- +// maker +// -- + +// function cloneShallow( container ) /* qqq for junior : cover please */ +// { +// _.assert( arguments.length === 1 ); +// return cloneShallow.functor.call( this, container )(); +// } +// +// cloneShallow.functor = _functor_functor( 'cloneShallow' ); +// +// // +// +// function make( container, ... args ) /* qqq for junior : cover please */ +// { +// _.assert( arguments.length === 1 || arguments.length === 2 ); +// return make.functor.call( this, container )( ... args ); +// } +// +// make.functor = _functor_functor( 'make' ); +// +// // +// +// function makeEmpty( container ) /* qqq for junior : cover please */ +// { +// _.assert( arguments.length === 1 ); +// return makeEmpty.functor.call( this, container )(); +// } +// +// makeEmpty.functor = _functor_functor( 'makeEmpty' ); +// +// // +// +// function makeUndefined( container, ... args ) /* qqq for junior : cover please */ +// { +// _.assert( arguments.length === 1 || arguments.length === 2 ); +// return makeUndefined.functor.call( this, container )( ... args ); +// } +// +// makeUndefined.functor = _functor_functor( 'makeUndefined' ); +// +// // -- +// // editor +// // -- +// +// /** +// * The routine empty() clears provided container {-dstContainer-}. +// * +// * @param { Long|Set|HashMap|Aux } dstContainer - Container to be cleared. {-dstContainer-} should be resizable. +// * +// * @example +// * let dst = []; +// * let got = _.container.empty( dst ); +// * console.log( got ); +// * // log [] +// * console.log( got === dst ); +// * log true +// * +// * @example +// * let dst = [ 1, 'str', { a : 2 } ]; +// * let got = _.container.empty( dst ); +// * console.log( got ); +// * // log [] +// * console.log( got === dst ); +// * // log true +// * +// * @example +// * let dst = _.unroll.make( [ 1, 'str', { a : 2 } ] ); +// * let got = _.container.empty( dst ); +// * console.log( got ); +// * // log [] +// * console.log( got === dst ); +// * // log true +// * +// * @example +// * let dst = new Set( [ 1, 'str', { a : 2 } ] ); +// * let got = _.container.empty( dst ); +// * console.log( got ); +// * // log Set {} +// * console.log( got === dst ); +// * // log true +// * +// * @example +// * let dst = new HashMap( [ [ 1, 'str' ], [ 'a', null ] ] ); +// * let got = _.container.empty( dst ); +// * console.log( got ); +// * // log Map {} +// * console.log( got === dst ); +// * // log true +// * +// * @returns { Long|Set|HashMap|Aux } - Returns a empty {-dstContainer-}. +// * @function empty +// * @throws { Error } If arguments.length is less than one. +// * @throws { Error } If {-dstContainer-} is not a Long, not a Set, not a HashMap, not a Aux. +// * @throws { Error } If {-dstContainer-} is not a resizable Long, or if it is a WeakSet or WeakMap. +// * @namespace Tools +// */ +// +// function empty( container ) /* qqq for junior : cover please */ +// { +// _.assert( arguments.length === 1 ); +// return empty.functor.call( this, container )(); +// } +// +// empty.functor = _functor_functor( 'empty' ); + +// -- +// inspector +// -- + +/** + * Returns "length" of entity( src ). Representation of "length" depends on type of( src ): + * - For object returns number of it own enumerable properties; + * - For array or array-like object returns value of length property; + * - For undefined returns 0; + * - In other cases returns 1. + * + * @param { * } src - Source entity. + * + * @example + * _.entity.lengthOf( [ 1, 2, 3 ] ); + * // returns 3 + * + * @example + * _.entity.lengthOf( 'string' ); + * // returns 1 + * + * @example + * _.entity.lengthOf( { a : 1, b : 2 } ); + * // returns 2 + * + * @example + * let src = undefined; + * _.entity.lengthOf( src ); + * // returns 0 + * + * @returns {number} Returns "length" of entity. + * @function lengthOf + * @namespace Tools/entity +*/ + +function lengthOf( src ) /* qqq for junior : cover please */ +{ + _.assert( arguments.length === 1 ); + return lengthOf.functor.call( this, src )(); +} + +lengthOf.functor = _functor_functor( 'lengthOf' ); + +// -- +// entity extension +// -- + +let EntityExtension = +{ + + identicalShallow, + equivalentShallow, + + equal, /* xxx : deprecate? */ + + // exporter + + _exportStringDiagnosticShallow : _.container._exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.container.exportStringDiagnosticShallow, + _exportStringCodeShallow : _.container._exportStringCodeShallow, + exportStringCodeShallow : _.container.exportStringCodeShallow, + exportString : _.container.exportString, + + // editor + + empty : _.container.empty, /* qqq : cover */ + + // inspector + + lengthOf, /* qqq : cover */ + + // elementor + + elementWithCardinal : _.container.elementWithCardinal, /* qqq : cover */ + elementWithKey : _.container.elementWithKey, /* qqq : cover */ + elementWithImplicit : _.container.elementWithImplicit, /* qqq : cover */ + elementWithCardinalSet : _.container.elementWithCardinalSet, /* qqq : cover */ + elementSet : _.container.elementSet, /* qqq : cover */ + + elementDel : _.container.elementDel, /* qqq : cover */ + elementWithKeyDel : _.container.elementWithKeyDel, /* qqq : cover */ + elementWithCardinalDel : _.container.elementWithCardinalDel, /* qqq : cover */ + empty : _.container.empty, /* qqq : for junior : cover */ + + // iterator + + each : _.container.each, /* qqq : cover */ + eachLeft : _.container.eachLeft, /* qqq : cover */ + eachRight : _.container.eachRight, /* qqq : cover */ + + while : _.container.while, /* qqq : cover */ + whileLeft : _.container.whileLeft, /* qqq : cover */ + whileRight : _.container.whileRight, /* qqq : cover */ + + aptLeft : _.container.aptLeft, /* qqq : cover */ + first : _.container.first, /* qqq : cover */ + aptRight : _.container.aptRight, /* qqq : cover */ + last : _.container.last, /* qqq : cover */ + +} + +// + +Object.assign( _.entity, EntityExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Entity.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Entity_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Entity_s */ })(); + +/* */ /* begin of file Escape_s */ ( function Escape_s() { function Escape_s_naked() { ( function _l3_Escape_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.escape.escaped = _.escape.escaped || Object.create( null ); + +// _.assert( _.symbolIs( _.symbol.prototype ) ); +// _.assert( _.symbolIs( _.symbol.constructor ) ); + +// -- +// implementation +// -- + +function isEscapable( src ) +{ + if( _.escape._EscapeMap.has( src ) ) + return true; + if( _.escape.is( src ) ) + return true; + return false; +} + +// + +function left( src ) +{ + _.assert( arguments.length === 1 ); + if( _.escape._EscapeMap.has( src ) ) + return _.escape._EscapeMap.get( src ); + if( _.escape.is( src ) ) + return new _.Escape( src ); + return src; +} + +// + +function rightWithNothing( src ) +{ + _.assert( arguments.length === 1 ); + if( _.escape.is( src ) ) + return src.val; + + if( src === _.undefined ) + return undefined; + if( src === _.null ) + return null; + + if( src === _.nothing ) + return undefined; + + return src; +} + +// + +function rightWithoutNothing( src ) +{ + _.assert( arguments.length === 1 ); + if( _.escape.is( src ) ) + return src.val; + + if( src === _.undefined ) + return undefined; + if( src === _.null ) + return null; + + return src; +} + +// + +function wrap( src ) +{ + _.assert( arguments.length === 1 ); + _.assert( !_.escape.is( src ) ); + return new _.Escape( src ); +} + +// + +function unwrap( src ) +{ + _.assert( arguments.length === 1 ); + if( _.escape.is( src ) ) + return src.val; + return src; +} + +// -- +// class +// -- + +let fo = _.wrap.declare({ name : 'Escape' }); +_.assert( _.Escape === undefined ); +_.assert( _.routineIs( fo.class ) ); +_.assert( fo.class.name === 'Escape' ); +_.Escape = fo.class; +_.assert( _.mapIs( fo.namespace ) ); +Object.assign( _.escape, fo.namespace ); + +// -- +// extension +// -- + +var Extension = +{ + isEscapable, + left, + rightWithNothing, + rightWithoutNothing, + right : rightWithNothing, + wrap, + unwrap, +} + +// + +Object.assign( _.escape, Extension ); +_.escape.escaped.nothing = _.escape.wrap( _.nothing ); +_.escape.escaped.null = _.escape.wrap( _.null ); +_.escape.escaped.undefined = _.escape.wrap( _.undefined ); + +_.escape._EscapeMap = new HashMap(); +_.escape._EscapeMap.set( _.nothing, _.escape.escaped.nothing ); +_.escape._EscapeMap.set( _.null, _.escape.escaped.null ); +_.escape._EscapeMap.set( _.undefined, _.escape.escaped.undefined ); +_.escape._EscapeMap.set( undefined, _.undefined ); +_.escape._EscapeMap.set( null, _.null ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Escape.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Escape_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Escape_s */ })(); + +/* */ /* begin of file Event_s */ ( function Event_s() { function Event_s_naked() { ( function _l3_Event_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +function _chainGenerate( args ) +{ + let chain = []; + + _.assert( arguments.length === 1 ); + _.assert( _.longIs( args ) ); + + for( let a = 0 ; a < args.length-2 ; a++ ) + chainMake( a ); + + // chain.push([ _.event.nameValueFrom( args[ args.length-2 ] ), args[ args.length-1 ] ]); + chain.push([ args[ args.length-2 ], args[ args.length-1 ] ]); + + _.assert( _.routine.is( args[ args.length-1 ] ) ); + + return chain; + + /* */ + + function chainMake( a ) + { + // let e1 = _.event.nameValueFrom( args[ a ] ); + let e1 = args[ a ]; + chain.push([ e1, on ]); + function on() + { + let self = this; + let next = chain[ a + 1 ]; + + if( _.routine.is( self.on ) ) + { + /* + Dmytro : it is strange code because the owners of edispatcher can be classes like Process. + And this solution allows direct call of callbacks when the routine eventGive is not used : + https://github.com/Wandalen/wProcess/blob/master/proto/wtools/abase/l4_process/Basic.s#L210 + https://github.com/Wandalen/wProcedure/blob/master/proto/wtools/abase/l8_procedure/Namespace.s#L59 + */ + self.on( next[ 0 ], next[ 1 ] ); + if( self.eventHasHandler( e1, on ) ) + self.off( e1, on ); + } + else + { + let o = _.event.onHead( _.event.on, next ); + o.once = on.once; + _.event._on( self, o ); + + if( !on.once ) + if( _.event.eventHasHandler( self, { eventName : e1, eventHandler : on } ) ) + _.event.off( self, { callbackMap : { [ e1 ] : on } } ); + } + + } + } +} + +// + +function _chainToCallback( args ) +{ + let chain = _.event._chainGenerate( args ); + let firstPair = chain[ 0 ]; + return firstPair[ 1 ]; +} + +// + +function _chainValidate( chain ) +{ + + for( let i = 0 ; i < chain.length - 1 ; i++ ) + _.assert( _.str.defined( chain[ i ] ) ); + // for( let i = 0 ; i < chain.length - 1 ; i++ ) + // { + // _.assert( _.event.nameIs( chain[ i ] ) ); + // } + _.assert( _.routine.is( chain[ chain.length - 1 ] ) ); + + return true; +} + +// + +function _callbackMapValidate( callbackMap ) +{ + + _.assert( _.mapIs( callbackMap ) ); + for( let k in callbackMap ) + { + let callback = callbackMap[ k ]; + _.assert( _.routine.is( callback ) || _.longIs( callback ) ); + if( _.routine.is( callback ) ) + continue; + _.event._chainValidate( callback ); + } + +} + +// // +// +// function nameValueFrom( name ) +// { +// if( _.strIs( name ) ) +// return name; +// _.assert( _.event.nameIs( name ) ); +// return name.value; +// } +// +// // +// +// function nameIs( name ) +// { +// return name instanceof _.event.Name; +// } +// +// // +// +// /* +// _.process.on( 'available', _.event.Name( 'exit' ), _.event.Name( 'exit' ), _.procedure._eventProcessExitHandle ) +// -> +// _.process.on( _.event.Chain( 'available', 'exit', 'exit' ), _.procedure._eventProcessExitHandle ) +// */ +// +// /* qqq for Dmytro : remove the class */ /* aaa : Dmytro : removed */ +// function Name( name ) +// { +// if( !( this instanceof Name ) ) +// { +// if( _.event.nameIs( name ) ) +// return name; +// return new Name( ... arguments ); +// } +// _.assert( arguments.length === 1 ); +// _.assert( _.strIs( name ) ); +// this.value = name; +// return this; +// } +// +// Name.prototype = Object.create( null ); + +// + +/** + * The routine chainIs() checks of whether the passed value {-src-} is an instance of wTools.event.Chain. + * + * @example + * var chain = { chain : [ 'event1', 'event2' ] }; + * console.log( _.event.chainIs( chain ) ); + * // log : false + * + * @example + * var chain = _.event.chain( 'event1', 'event2' ); + * console.log( _.event.chainIs( chain ) ); + * // log : true + * + * @param { * } src - The value to check. + * @returns { Boolean } - Returns true if {-src-} is an instance of class wTools.event.Chain. + * Otherwise, routine returns false. + * @function chainIs + * @namespace wTools.event + * @extends Tools + */ + +function chainIs( src ) +{ + return src instanceof _.event.Chain; +} + +// + +/** + * The routine Chain() implements class Chain. The instance of the class holds chain of event names. + * + * @example + * var chain = _.event.chain( 'event1', 'event2' ); + * console.log( _.event.chainIs( chain ) ); + * // log : true + * console.log( chain.chain ); + * // log : [ 'event1', 'event2' ] + * + * @example + * var name1 = _.event.Name( 'event1' ); + * var name2 = _.event.Name( 'event2' ); + * var chain = _.event.chain( name1, name2 ); + * console.log( _.event.chainIs( chain ) ); + * // log : true + * console.log( chain.chain.length ); + * // log : 2 + * console.log( chain.chain[ 0 ] === name1 ); + * // log : true + * console.log( chain.chain[ 1 ] === name2 ); + * // log : true + * + * @param { String|wTools.event.Name|wTools.event.Chain } ... arguments - The set of event names of single instance of Chain. + * @returns { wTools.event.Chain } - Returns instance of class. + * @function Chain + * @class wTools.event.Chain + * @throws { Error } If arguments.length is less than 1. + * @throws { Error } If arguments have incompatible type. + * @throws { Error } If arguments contain instance of Chain and another elements. + * @namespace wTools.event + * @extends Tools + */ + +function Chain() +{ + if( !( _.event.chainIs( this ) ) ) + { + if( _.event.chainIs( arguments[ 0 ] ) ) + { + _.assert( arguments.length === 1, 'Expects single Chain or set of event names' ); + return arguments[ 0 ]; + } + return new Chain( ... arguments ); + } + + let result = _.array.make( arguments.length ); + _.assert( arguments.length >= 1, 'Expects events names' ); + for( let i = 0 ; i < arguments.length ; i++ ) + { + _.assert( _.str.is( arguments[ i ] ) ); + result[ i ] = arguments[ i ]; + } + // result[ i ] = _.event.Name( arguments[ i ] ); + + this.chain = result; + return this; +} + +Chain.prototype = Object.create( null ); + +// + +function onHead( routine, args ) +{ + let o; + + _.assert( _.longIs( args ) ); + _.assert( arguments.length === 2 ); + + if( args.length === 2 ) + { + _.assert( _.routine.is( args[ 1 ] ) ); + + o = Object.create( null ); + o.callbackMap = Object.create( null ); + + if( _.event.chainIs( args[ 0 ] ) ) + { + let chain = args[ 0 ].chain; + o.callbackMap[ chain[ 0 ] ] = _.longOnly_( null, chain, [ 1, chain.length - 1 ] ); + o.callbackMap[ chain[ 0 ] ].push( args[ 1 ] ); + // o.callbackMap[ chain[ 0 ].value ] = _.longOnly_( null, chain, [ 1, chain.length - 1 ] ); + // o.callbackMap[ chain[ 0 ].value ].push( args[ 1 ] ); + } + else if( _.str.is( args[ 0 ] ) ) + { + o.callbackMap[ args[ 0 ] ] = args[ 1 ]; + } + // else if( _.event.nameIs( args[ 0 ] ) ) + // { + // o.callbackMap[ args[ 0 ].value ] = args[ 1 ]; + // } + else + { + _.assert( 0, 'Expects Chain with names or single name of event.' ); + } + } + else if( args.length === 1 ) + { + o = args[ 0 ]; + } + else + { + _.assert( 0, 'Expects single options map {-o-} or events Chain and callback as arguments.' ); + } + + if( Config.debug ) + { + _.assert( _.mapIs( o ) ); + _.event._callbackMapValidate( o.callbackMap ); + } + + // _.event._callbackMapNormalize( o.callbackMap ); + + return o; +} + +// + +function _on( edispatcher, o ) +{ + + _.routine.options( _on, o ); + _.assert( _.mapIs( o.callbackMap ) ); + _.assert( _.object.isBasic( edispatcher ) ); + _.assert( _.object.isBasic( edispatcher.events ) ); + _.map.assertHasOnly( o.callbackMap, edispatcher.events, 'Unknown kind of event' ); + _.assert( arguments.length === 2 ); + + const once = !!o.once; + let descriptors = Object.create( null ); + let append; + if( o.first ) + append = _.arrayPrepend; + else + append = _.arrayAppend; + + for( let c in o.callbackMap ) + { + let callback = o.callbackMap[ c ]; + descriptors[ c ] = descriptorMake(); + + if( _.longIs( callback ) ) + callback = _.event._chainToCallback([ c, ... callback ]); + + _.assert( _.routine.is( callback ) ); + + callback = callbackOn_functor.call( descriptors[ c ], callback, c ); + descriptors[ c ].off = off_functor.call( descriptors[ c ], edispatcher, { callbackMap : { [ c ] : callback } } ); + + append( edispatcher.events[ c ], callback ); + + // if( o.first ) + // _.arrayPrepend( edispatcher.events[ c ], callback ); + // else + // _.arrayAppend( edispatcher.events[ c ], callback ); + + /* */ + + } + + return descriptors; + + /* */ + + // function callbackOn_functor( callback ) /* Dmytro : can't extract name from descriptor. Maybe, it can contains field `name` */ + function callbackOn_functor( callback, name ) + { + let self = this; + + function callbackOn() + { + let result; + if( self.enabled ) + { + result = callback.apply( this, arguments ); + if( once === true ) + _.event.off( edispatcher, { callbackMap : { [ name ] : callbackOn } } ); + // _.event.off( edispatcher, { callbackMap : { [ name ] : callbackOnce } } ); /* Dmytro : callbackOnce does not exist */ + } + return result; + } + callbackOn.native = callback; + callbackOn.native.once = once; + + return callbackOn; + } + + /* */ + + function descriptorMake() + { + let descriptor = Object.create( null ); + descriptor.off = null; + descriptor.enabled = true; + descriptor.first = o.first; /* Dmytro : please, explain, does it need to save original value? */ + descriptor.callbackMap = o.callbackMap; /* Dmytro : please, explain, does it need to save link to original callback map? */ + return descriptor; + } + + /* */ + + function off_functor( edispatcher, o ) + { + let self = this; + + return function() + { + _.assert( arguments.length === 0, 'Expects no arguments.' ); + return _.event.off( edispatcher, o ); + } + } + + /* */ + +} + +_on.defaults = +{ + callbackMap : null, + first : false, + once : false, +} + +// const on = _.routine.uniteCloning( on_head, on_body ); +// on.defaults.once = false; + +// + +function on( edispatcher, o ) +{ + o.once = false; + return _.event._on( edispatcher, o ); +} + +// // +// +// function on( edispatcher, o ) +// { +// +// // if( _.longIs( o.callbackMap ) ) +// // o.callbackMap = callbackMapFromChain( o.callbackMap ); +// +// _.routine.options( on, o ); +// _.assert( _.mapIs( o.callbackMap ) ); +// _.assert( _.object.isBasic( edispatcher ) ); +// _.assert( _.object.isBasic( edispatcher.events ) ); +// _.map.assertHasOnly( o.callbackMap, edispatcher.events, 'Unknown kind of event' ); +// _.assert( arguments.length === 2 ); +// +// let descriptors = Object.create( null ); +// +// for( let c in o.callbackMap ) +// { +// let callback = o.callbackMap[ c ]; +// descriptors[ c ] = descriptorMake(); +// +// if( _.longIs( callback ) ) +// callback = _.event._chainToCallback([ c, ... callback ]); +// +// _.assert( _.routine.is( callback ) ); +// +// callback = callbackOn_functor.call( descriptors[ c ], callback ); +// descriptors[ c ].off = off_functor.call( descriptors[ c ], edispatcher, { callbackMap : { [ c ] : callback } } ); +// +// if( o.first ) +// _.arrayPrepend( edispatcher.events[ c ], callback ); +// else +// _.arrayAppend( edispatcher.events[ c ], callback ); +// +// /* */ +// +// } +// +// return descriptors; +// +// /* */ +// +// function callbackOn_functor( callback ) +// { +// let self = this; +// +// function callbackOn() +// { +// let result; +// if( self.enabled ) +// result = callback.apply( this, arguments ); +// return result; +// } +// callbackOn.native = callback; +// +// return callbackOn; +// } +// +// /* */ +// +// function descriptorMake() +// { +// let descriptor = Object.create( null ); +// descriptor.off = null; +// descriptor.enabled = true; +// descriptor.first = o.first; /* Dmytro : please, explain, does it need to save original value? */ +// descriptor.callbackMap = o.callbackMap; /* Dmytro : please, explain, does it need to save link to original callback map? */ +// return descriptor; +// } +// +// /* */ +// +// function off_functor( edispatcher, o ) +// { +// let self = this; +// +// return function() +// { +// _.assert( arguments.length === 0, 'Expects no arguments.' ); +// return _.event.off( edispatcher, o ); +// } +// } +// +// /* */ +// +// } +// +// on.head = on_head; +// on.defaults = +// { +// callbackMap : null, +// first : 0, +// }; + +// // +// +// function on( edispatcher, o ) +// { +// +// // if( _.longIs( o.callbackMap ) ) +// // o.callbackMap = callbackMapFromChain( o.callbackMap ); +// +// _.routine.options( on, o ); +// _.assert( _.mapIs( o.callbackMap ) ); +// _.assert( _.object.isBasic( edispatcher ) ); +// _.assert( _.object.isBasic( edispatcher.events ) ); +// _.map.assertHasOnly( o.callbackMap, edispatcher.events, 'Unknown kind of event' ); +// _.assert( arguments.length === 2 ); +// +// let descriptors = Object.create( null ); +// +// for( let c in o.callbackMap ) +// { +// let callback = o.callbackMap[ c ]; +// descriptors[ c ] = descriptorMake(); +// +// if( _.longIs( callback ) ) +// callback = _.event._chainToCallback([ c, ... callback ]); +// +// _.assert( _.routine.is( callback ) ); +// +// callback = callbackOn_functor.call( descriptors[ c ], callback ); +// descriptors[ c ].off = off_functor.call( descriptors[ c ], edispatcher, { callbackMap : { [ c ] : callback } } ); +// +// if( o.first ) +// _.arrayPrepend( edispatcher.events[ c ], callback ); +// else +// _.arrayAppend( edispatcher.events[ c ], callback ); +// +// /* */ +// +// } +// +// return descriptors; +// +// /* */ +// +// function callbackOn_functor( callback ) +// { +// let self = this; +// +// function callbackOn() +// { +// let result; +// if( self.enabled ) +// result = callback.apply( this, arguments ); +// return result; +// } +// callbackOn.native = callback; +// +// return callbackOn; +// } +// +// /* */ +// +// function descriptorMake() +// { +// let descriptor = Object.create( null ); +// descriptor.off = null; +// descriptor.enabled = true; +// descriptor.first = o.first; /* Dmytro : please, explain, does it need to save original value? */ +// descriptor.callbackMap = o.callbackMap; /* Dmytro : please, explain, does it need to save link to original callback map? */ +// return descriptor; +// } +// +// /* */ +// +// function off_functor( edispatcher, o ) +// { +// let self = this; +// +// return function() +// { +// _.assert( arguments.length === 0, 'Expects no arguments.' ); +// return _.event.off( edispatcher, o ); +// } +// } +// +// /* */ +// +// } +// +// on.head = on_head; +// on.defaults = +// { +// callbackMap : null, +// first : 0, +// }; + +// + +/** + * The routine once() registers callback of some kind in event handler {-edispatcher-}. + * Registered callback executes once and deleted from queue. + * + * @example + * let edispatcher = { events : { begin : [] } }; + * let result = []; + * let onBegin = () => result.push( result.length ); + * console.log( edispatcher.events.begin.length ); + * // log : 0 + * _.event.once( edispatcher, { callbackMap : { begin : onBegin } } ); + * console.log( edispatcher.events.begin.length ); + * // log : 1 + * console.log( result ); + * // log : [] + * + * @example + * let edispatcher = { events : { begin : [] } }; + * let result = []; + * let onBegin = () => result.push( result.length ); + * _.event.once( edispatcher, { callbackMap : { begin : onBegin } } ); + * _.event.eventGive( edispatcher, 'begin' ); + * console.log( edispatcher.events.begin.length ); + * // log : 0 + * console.log( result ); + * // log : [ 0 ] + * + * @example + * let edispatcher = { events : { begin : [], end : [] } }; + * let result = []; + * let onBegin = () => result.push( result.length ); + * let onBegin2 = () => result.push( result.length + 1 ); + * let onEnd = result.splice(); + * _.event.once( edispatcher, { callbackMap : { begin : onBegin } } ); + * _.event.once( edispatcher, { callbackMap : { begin : onBegin2 } } ); + * _.event.once( edispatcher, { callbackMap : { end : onEnd } } ); + * _.event.eventGive( edispatcher, 'begin' ); + * console.log( edispatcher.events.begin.length ); + * // log : 0 + * console.log( result ); + * // log : [ 0, 2 ] + * _.event.eventGive( edispatcher, 'end' ); + * console.log( result ); + * // log : [] + * + * @param { Object } edispatcher - The events handler with map of available events. + * @param { Map|Aux } o - Options map. + * @param { Map } o.callbackMap - Map with pairs: [ eventName ] : [ callback ]. The value + * [ callback ] can be a Function or Array with callbacks. + * @param { Boolean|BoolLike } o.first - If it has value `true`, then callback prepends to callback queue. + * Otherwise, callback appends to callback queue. + * @returns { Map|Aux } - Returns options map {-o-}. + * @function once + * @throws { Error } If arguments.length is not equal to 2. + * @throws { Error } If {-edispatcher-} is not an Object. + * @throws { Error } If {-edispatcher.events-} is not an Object. + * @throws { Error } If {-o-} has incompatible type. + * @throws { Error } If {-o-} has extra options. + * @throws { Error } If {-o.callbackMap-} is not a Map. + * @throws { Error } If {-o.callbackMap-} has events than does not exist in map {-edispatcher.events-}. + * @namespace wTools.event + * @extends Tools + */ + +// const once = _.routine.uniteCloning( on_head, on_body ); +// once.defaults.once = true; +// _.assert( on.defaults.once === false ); + +function once( edispatcher, o ) +{ + o.once = true; + return _.event._on( edispatcher, o ); +} + +/* qqq : for Dmytro : bad! */ +// function once( edispatcher, o ) +// { +// +// _.routine.options( once, o ); +// _.assert( _.mapIs( o.callbackMap ) ); +// _.assert( _.object.isBasic( edispatcher ) ); +// _.assert( _.object.isBasic( edispatcher.events ) ); +// _.map.assertHasOnly( o.callbackMap, edispatcher.events, 'Unknown kind of event' ); +// _.assert( arguments.length === 2 ); +// +// let descriptors = Object.create( null ); +// +// for( let c in o.callbackMap ) +// { +// let callback = o.callbackMap[ c ]; +// descriptors[ c ] = descriptorMake(); +// +// if( _.longIs( callback ) ) +// { +// let length = callback.length; +// _.assert( _.routine.is( callback[ length - 1 ] ), 'Expects routine to execute.' ); +// +// let name = callback[ length - 2 ] || c; +// name = name.value !== undefined ? name.value : name; +// callback[ length - 1 ] = callbackOnce_functor.call( descriptors[ c ], name, callback[ length - 1 ] ); +// callback = _.event._chainToCallback([ c, ... callback ]); +// } +// else +// { +// callback = callbackOnce_functor.call( descriptors[ c ], c, callback ); +// } +// descriptors[ c ].off = off_functor.call( descriptors[ c ], edispatcher, { callbackMap : { [ c ] : callback } } ); +// +// _.assert( _.routine.is( callback ) ); +// +// callbackAdd( edispatcher, c, callback ); +// } +// +// return descriptors; +// +// /* */ +// +// function callbackOnce_functor( name, callback ) +// { +// let self = this; +// +// function callbackOnce() +// { +// let result; +// if( self.enabled ) +// { +// callback.apply( this, arguments ); +// _.event.off( edispatcher, { callbackMap : { [ name ] : callbackOnce } } ); +// } +// return result; +// } +// callbackOnce.native = callback; /* Dmytro : this solution does not affects original callback and interfaces of calls. And simultaneously it slow down searching in routine `off` */ +// +// return callbackOnce; +// } +// +// /* */ +// +// function callbackAdd( handler, name, callback ) +// { +// if( o.first ) +// _.arrayPrepend( handler.events[ name ], callback ); +// else +// _.arrayAppend( handler.events[ name ], callback ); +// } +// +// /* */ +// +// function descriptorMake() +// { +// let descriptor = Object.create( null ); +// descriptor.off = null; +// descriptor.enabled = true; +// descriptor.first = o.first; /* Dmytro : please, explain, does it need to save original value? */ +// descriptor.callbackMap = o.callbackMap; /* Dmytro : please, explain, does it need to save link to original callback map? */ +// +// return descriptor; +// } +// } +// +// once.head = on_head; +// once.defaults = +// { +// callbackMap : null, +// first : 0, +// }; + +// + +/** + * The routine off() removes callback of some kind in event handler {-edispatcher-}. + * + * @example + * let onBegin = () => result.push( result.length ); + * let onBegin2 = () => result.push( result.length ); + * let edispatcher = { events : { begin : [ onBegin, onBegin2 ] } }; + * _.event.off( edispatcher, { callbackMap : { begin : onBegin } } ); + * console.log( edispatcher.events.begin.length ); + * // log : 1 + * console.log( edispatcher.events.begin[ 0 ] === onBegin2 ); + * // log : true + * + * @example + * let onBegin = () => result.push( result.length ); + * let onBegin2 = () => result.push( result.length ); + * let edispatcher = { events : { begin : [ onBegin, onBegin2 ] } }; + * _.event.off( edispatcher, { callbackMap : { begin : null } } ); + * console.log( edispatcher.events.begin.length ); + * // log : 0 + * + * @param { Object } edispatcher - The events handler with map of available events. + * @param { Map|Aux } o - Options map. + * @param { Map } o.callbackMap - Map with pairs: [ eventName ] : [ callback ]. The value + * [ callback ] can be a Function or Null. If null is provided, routine removes all callbacks. + * @returns { Map|Aux } - Returns options map {-o-}. + * @function off + * @throws { Error } If arguments.length is not equal to 2. + * @throws { Error } If {-edispatcher-} is not an Object. + * @throws { Error } If {-edispatcher.events-} is not an Object. + * @throws { Error } If {-o-} has incompatible type. + * @throws { Error } If {-o-} has extra options. + * @throws { Error } If {-o.callbackMap-} is not a Map. + * @throws { Error } If {-o.callbackMap-} has events than does not exist in map {-edispatcher.events-}. + * @throws { Error } If {-edispatcher.events-} callback queue has a few callbacks + * which should be removed separately. + * @namespace wTools.event + * @extends Tools + */ + +function offHead( routine, args ) +{ + + _.assert( _.longIs( args ) ); + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + + let o = args[ 0 ]; + if( args.length === 2 ) + o = { callbackMap : { [ args[ 0 ] ] : args[ 1 ] } } + else if( _.strIs( args[ 0 ] ) ) + o = { callbackMap : { [ args[ 0 ] ] : null } } + + _.assert( _.mapIs( o ) ); + + return o; +} + +// + +function off( edispatcher, o ) +{ + + _.routine.options( off, o ); + _.assert( _.mapIs( o.callbackMap ) ); + _.assert( _.object.isBasic( edispatcher ) ); + _.assert( _.object.isBasic( edispatcher.events ) ); + _.map.assertHasOnly( o.callbackMap, edispatcher.events, 'Unknown kind of event' ); + _.assert( arguments.length === 2 ); + + for( let c in o.callbackMap ) + { + if( o.callbackMap[ c ] === null ) + _.array.empty( edispatcher.events[ c ] ); + else + _.arrayRemoveOnceStrictly( edispatcher.events[ c ], o.callbackMap[ c ], callbackEqualize ); + } + + return o; + + /* */ + + function callbackEqualize( callback, handler ) + { + return handler === callback || handler === callback.native; + } +} + +// off.head = off_head; +off.defaults = +{ + callbackMap : null, +} + +// + +function eventHasHandlerHead( routine, args ) +{ + let o; + + _.assert( _.longIs( args ) ); + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + + if( args.length > 1 ) + { + o = Object.create( null ); + o.eventName = args[ 0 ]; + o.eventHandler = args[ 1 ]; + } + else + { + o = args[ 0 ] + } + + _.assert( _.mapIs( o ) ); + + return o; +} + +// + +/* xxx */ +function eventHasHandler( edispatcher, o ) +{ + + _.routine.options( eventHasHandler, o ); + _.assert( _.strIs( o.eventName ) ); + _.assert( _.routine.is( o.eventHandler ) ); + _.assert( _.mapIs( edispatcher ) ); + _.assert( _.mapIs( edispatcher.events ) ); + _.assert( arguments.length === 2 ); + + return _.longHas( edispatcher.events[ o.eventName ], o.eventHandler, handlerEqualize ); + + /* */ + + function handlerEqualize( callback, handler ) + { + return handler === callback || handler === callback.native; + } +} + +// eventHasHandler.head = eventHasHandler_head; +eventHasHandler.defaults = +{ + eventName : null, + eventHandler : null, +} + +// + +function eventGiveHead( edispatcher, routine, args ) +{ + let o = args[ 0 ]; + + _.assert( arguments.length === 3, 'Expects exactly three arguments.' ); + _.assert( args.length > 0 ); + _.assert( _.aux.is( edispatcher.events ), 'Expects events dispatcher.' ); + + if( _.strIs( o ) ) + o = { event : o }; + _.assert( _.aux.is( o ), 'Expects string or options map in {-o.args[ 1 ]-}.' ); /* Dmytro : restrict using options map in first argument */ + + if( o.onError === null || o.onError === undefined ) + o.onError = onError; + + _.map.assertHasOnly( o, routine.defaults ); + + if( o.args ) + _.assert( args.length === 1 ); /* Dmytro : restrict using options map in first argument */ + else /* Dmytro : do not overwrite arguments if the field exists */ + o.args = args; + + // if( o.args === null ) + // { + // o.args = [ Object.create( null ) ]; + // o.args[ 0 ].event = o.event; + // } + + return o; + + /* */ + + function onError( err, o ) + { + throw _.err( `Error on handing event ${o.event}\n`, err ); + } +} + +// + +function eventGive( edispatcher, o ) +{ + + // if( _.strIs( o ) ) + // o = { event : o } + // _.routine.options( eventGive, o ); + // + // if( o.onError === null ) + // o.onError = onError; + // if( o.args === null ) + // { + // o.args = [ Object.create( null ) ]; + // o.args[ 0 ].event = o.event; + // } + + _.assert( arguments.length === 2 ); + _.assert( !!edispatcher.events[ o.event ], `Unknown event ${o.event}` ); + _.assert( _.long.is( o.args ), 'Expects arguments {-o.args-}' ); + + let was; + let visited = []; + do + { + was = visited.length; + let events = edispatcher.events[ o.event ].slice(); + _.each( events, ( callback ) => + { + if( _.longHas( visited, callback ) ) + return; + visited.push( callback ); + try + { + callback.apply( edispatcher, o.args ); + } + catch( err ) + { + o.onError( err, o ); + } + }); + } + while( was !== visited.length ); + + /* */ + + // function onError( err, o ) + // { + // throw _.err( `Error on handing event ${o.event}\n`, err ); + // } + +} + +eventGive.defaults = +{ + event : null, + args : null, + onError : null, +} + +// -- +// extension +// -- + +let Extension = +{ + + _chainGenerate, + _chainToCallback, + _chainValidate, + _callbackMapValidate, + + // nameValueFrom, + // nameIs, + // Name, + chainIs, + Chain, + + onHead, + _on, + on, + once, + offHead, + off, + // off_functor, + + eventHasHandlerHead, + eventHasHandler, + eventGiveHead, + eventGive, + +} + +Object.assign( _.event, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Event.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Event_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Event_s */ })(); + +/* */ /* begin of file HashMap_s */ ( function HashMap_s() { function HashMap_s_naked() { ( function _l3_HashMap_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// equaler +// -- + +function _identicalShallow( src1, src2 ) +{ + + if( src1.size !== src2.size ) + return false; + + for( let [ key, val ] of src1 ) + { + if( src2.has( key ) === false ) + return false; + + let val2 = src2.get( key ); + + // /* + // in cases of an undefined value, make sure the key + // exists on the object so there are no false positives + // */ + // // if( testVal !== val || ( testVal === undefined && !src2.has( key ) ) ) + // // return false; + + if( !Object.is( val2, val ) ) + return false; + + } + + return true; +} + +// -- +// exporter +// -- + +function _exportStringDiagnosticShallow( src ) +{ + return `{- ${_.entity.strType( src )} with ${_.entity.lengthOf( src )} elements -}`; +} + +// -- +// container interface +// -- + +function _lengthOf( src ) +{ + return src.size; +} + +// + +function _hasKey( src, key ) +{ + return src.has( key ); +} + +// + +function _hasCardinal( src, cardinal ) +{ + if( cardinal < 0 ) + return false; + return cardinal < src.size; +} + +// + +function _keyWithCardinal( src, cardinal ) +{ + if( cardinal < 0 || src.size <= cardinal ) + return [ undefined, false ]; + return [ this.keys[ cardinal ], true ]; +} + +// + +function _cardinalWithKey( src, key ) +{ + if( !src.has( key ) ) + return -1; + let keys = this.keys( src ); + return keys.indexOf( key ); +} + +// + +function _elementWithKey( src, key ) +{ + if( src.has( key ) ) + return [ src.get( key ), key, true ]; + else + return [ undefined, key, false ]; +} + +// + +function _elementWithImplicit( src, key ) +{ + if( _.props.keyIsImplicit( key ) ) + return _.props._onlyImplicitWithKeyTuple( src, key ); + return this._elementWithKey( src, key ); +} + +// + +function _elementWithCardinal( src, cardinal ) +{ + if( cardinal < 0 || src.size <= cardinal || !_.numberIs( cardinal ) ) + return [ undefined, cardinal, false ]; + let entry = [ ... src ][ cardinal ]; + return [ entry[ 1 ], entry[ 0 ], true ]; +} + +// + +function _elementWithKeySet( dst, key, val ) +{ + dst.set( key, val ); + return [ key, true ]; +} + +// + +function _elementWithCardinalSet( dst, cardinal, val ) +{ + let was = this._elementWithCardinal( dst, cardinal ); + if( was[ 2 ] === true ) + { + dst.set( was[ 1 ], val ); + return [ was[ 1 ], true ]; + } + else + { + return [ cardinal, false ]; + } +} + +// + +function _elementWithKeyDel( dst, key ) +{ + if( !this._hasKey( dst, key ) ) + return false; + dst.delete( key ); + return true; +} + +// + +function _elementWithCardinalDel( dst, cardinal ) +{ + let has = this._keyWithCardinal( dst, cardinal ); + if( !has[ 1 ] ) + return false; + dst.delete( has[ 0 ] ); + return true; +} + +// + +function _empty( dst ) +{ + dst.clear(); + return dst; +} + +// + +function _eachLeft( src, onEach ) +{ + let c = 0; + for( let [ k, val ] of src ) + { + onEach( val, k, c, src ); + c += 1; + } +} + +// + +function _eachRight( src, onEach ) +{ + let keys = [ ... src.keys() ]; + for( let c = keys.length-1 ; c >= 0 ; c-- ) + { + let k = keys[ c ]; + let val = src.get( k ); + onEach( val, k, c, src ); + } +} + +// + +function _whileLeft( src, onEach ) +{ + if( src.size === 0 ) + return [ undefined, undefined, -1, true ]; + let c = 0; + let lastk; + for( let [ k, val ] of src ) + { + let r = onEach( val, k, c, src ); + _.assert( r === true || r === false ); + if( r === false ) + return [ val, k, c, false ]; + lastk = k; + c += 1; + } + return [ src.get( lastk ), lastk, c-1, true ]; +} + +// + +function _whileRight( src, onEach ) +{ + if( src.size === 0 ) + return [ undefined, undefined, -1, true ]; + + let keys = [ ... src.keys() ]; + for( let c = keys.length-1 ; c >= 0 ; c-- ) + { + let k = keys[ c ]; + let val = src.get( k ); + let r = onEach( val, k, c, src ); + _.assert( r === true || r === false ); + if( r === false ) + return [ val, k, c, false ]; + } + + var k = keys[ 0 ]; + return [ src.get( k ), k, 0, true ]; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +// + +let Extension = +{ + + // equaler + + _identicalShallow, + identicalShallow : _.props.identicalShallow, + identical : _.props.identical, + _equivalentShallow : _identicalShallow, + equivalentShallow : _.props.equivalentShallow, + equivalent : _.props.equivalent, + + // exporter + + _exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.props.exportStringDiagnosticShallow, + _exportStringCodeShallow : _exportStringDiagnosticShallow, + exportStringCodeShallow : _.props.exportStringCodeShallow, + exportString : _.props.exportString, + + // inspector + + _lengthOf, + lengthOf : _.props.lengthOf, /* qqq : cover */ + _hasKey, + hasKey : _.props.hasKey, /* qqq : cover */ + _hasCardinal, + hasCardinal : _.props.hasCardinal, /* qqq : cover */ + _keyWithCardinal, + keyWithCardinal : _.props.keyWithCardinal, /* qqq : cover */ + _cardinalWithKey, + cardinalWithKey : _.props.cardinalWithKey, /* qqq : cover */ + + // elementor + + _elementGet : _elementWithKey, + elementGet : _.props.elementGet, /* qqq : cover */ + _elementWithKey, + elementWithKey : _.props.elementWithKey, /* qqq : cover */ + _elementWithImplicit : _.props._elementWithImplicit, + elementWithImplicit : _.props.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal, + elementWithCardinal : _.props.elementWithCardinal, /* qqq : cover */ + + _elementSet : _elementWithKeySet, + elementSet : _.props.elementSet, /* qqq : cover */ + _elementWithKeySet, + elementWithKeySet : _.props.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet, + elementWithCardinalSet : _.props.elementWithCardinalSet, /* qqq : cover */ + + _elementDel : _elementWithKeyDel, + elementDel : _.props.elementDel, /* qqq : cover */ + _elementWithKeyDel, + elementWithKeyDel : _.props.elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel, + elementWithCardinalDel : _.props.elementWithCardinalDel, /* qqq : cover */ + _empty, + empty : _.props.empty, /* qqq : for junior : cover */ + + // iterator + + _each : _eachLeft, + each : _.props.each, /* qqq : cover */ + _eachLeft, + eachLeft : _.props.eachLeft, /* qqq : cover */ + _eachRight, + eachRight : _.props.eachRight, /* qqq : cover */ + + _while : _whileLeft, + while : _.props.while, /* qqq : cover */ + _whileLeft, + whileLeft : _.props.whileLeft, /* qqq : cover */ + _whileRight, + whileRight : _.props.whileRight, /* qqq : cover */ + + _aptLeft : _.props._aptLeft, + aptLeft : _.props.aptLeft, /* qqq : cover */ + first : _.props.first, + _aptRight : _.props._aptRight, /* qqq : cover */ + aptRight : _.props.aptRight, + last : _.props.last, /* qqq : cover */ + + _filterAct0 : _.props._filterAct0, + _filterAct : _.props._filterAct, + filterWithoutEscapeLeft : _.props.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.props.filterWithoutEscapeRight, + filterWithoutEscape : _.props.filterWithoutEscape, + filterWithEscapeLeft : _.props.filterWithEscapeLeft, + filterWithEscapeRight : _.props.filterWithEscapeRight, + filterWithEscape : _.props.filterWithEscape, + filter : _.props.filter, + + _mapAct0 : _.props._mapAct0, + _mapAct : _.props._mapAct, + mapWithoutEscapeLeft : _.props.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.props.mapWithoutEscapeRight, + mapWithoutEscape : _.props.mapWithoutEscape, + mapWithEscapeLeft : _.props.mapWithEscapeLeft, + mapWithEscapeRight : _.props.mapWithEscapeRight, + mapWithEscape : _.props.mapWithEscape, + map : _.props.map, + +} + +Object.assign( _.hashMap, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/HashMap.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, HashMap_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file HashMap_s */ })(); + +/* */ /* begin of file Itself_s */ ( function Itself_s() { function Itself_s_naked() { ( function _l3_Itself_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( !!_.blank.identical, 'Expects routine blank.identical' ); +_.assert( !!_.blank.exportString, 'Expects routine _.blank.exportString' ); + +// -- +// container interface +// -- + +function _lengthOf( src ) +{ + return 1; +} + +// + +function _hasKey( src, key ) +{ + if( cardinal === 0 ) + return true; + return false; +} + +// + +function _hasCardinal( src, cardinal ) +{ + if( cardinal === 0 ) + return true; + return false; +} + +// + +function _keyWithCardinal( src, cardinal ) +{ + if( cardinal === 0 ) + return [ 0, true ]; + return [ undefined, false ]; +} + +// + +function _cardinalWithKey( key ) +{ + if( key === 0 ) + return 0; + return -1; +} + +// + +function _elementWithKey( src, key ) +{ + if( key === 0 ) + return [ src, key, true ]; + return [ undefined, key, false ]; +} + +// + +function _elementWithCardinal( src, cardinal ) +{ + if( cardinal === 0 ) + return [ src, cardinal, true ]; + return [ undefined, cardinal, false ]; +} + +// + +function _elementWithKeySet( dst, key, val ) +{ + return [ key, false ]; +} + +// + +function _elementWithCardinalSet( dst, cardinal, val ) +{ + if( cardinal === 0 ) + return [ cardinal, true ]; + else + return [ cardinal, false ]; +} + +// + +function _elementWithKeyDel( dst, key ) +{ + return false; +} + +// + +function _elementWithCardinalDel( dst, cardinal ) +{ + return false; +} + +// + +function _empty( dst ) +{ + return dst; +} + +// + +function _eachLeft( src, onEach ) +{ + onEach( src, null, 0, src ); +} + +// + +function _eachRight( src, onEach ) +{ + onEach( src, null, 0, src ); +} + +// + +function _whileLeft( src, onEach ) +{ + let r = onEach( src, null, 0, src ); + _.assert( r === true || r === false ); + if( r === false ) + return [ src, null, 0, false ]; + return [ src, null, 0, true ]; +} + +// + +function _whileRight( src, onEach ) +{ + let r = onEach( src, null, 0, src ); + _.assert( r === true || r === false ); + if( r === false ) + return [ src, null, 0, false ]; + return [ src, null, 0, true ]; +} + +// -- +// extension +// -- + +let ItselfExtension = +{ + + // equaler + + _identicalShallow : _.blank._identicalShallow, + identicalShallow : _.blank.identicalShallow, + identical : _.blank.identical, + _equivalentShallow : _.blank._equivalentShallow, + equivalentShallow : _.blank.equivalentShallow, + equivalent : _.blank.equivalent, + + // exporter + + _exportStringDiagnosticShallow : _.blank._exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.blank.exportStringDiagnosticShallow, + _exportStringCodeShallow : _.blank._exportStringCodeShallow, + exportStringCodeShallow : _.blank.exportStringCodeShallow, + exportString : _.blank.exportString, + + // inspector + + _lengthOf, + lengthOf : _.props.lengthOf, /* qqq : cover */ + _hasKey, + hasKey : _.props.hasKey, /* qqq : cover */ + _hasCardinal, + hasCardinal : _.props.hasCardinal, /* qqq : cover */ + _keyWithCardinal, + keyWithCardinal : _.props.keyWithCardinal, /* qqq : cover */ + _cardinalWithKey, + cardinalWithKey : _.props.cardinalWithKey, /* qqq : cover */ + + // elementor + + _elementGet : _elementWithKey, + elementGet : _.props.elementGet, /* qqq : cover */ + _elementWithKey, + elementWithKey : _.props.elementWithKey, /* qqq : cover */ + _elementWithImplicit : _.props._elementWithImplicit, + elementWithImplicit : _.props.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal, + elementWithCardinal : _.props.elementWithCardinal, /* qqq : cover */ + + _elementSet : _elementWithKeySet, + elementSet : _.props.elementSet, /* qqq : cover */ + _elementWithKeySet, + elementWithKeySet : _.props.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet, + elementWithCardinalSet : _.props.elementWithCardinalSet, /* qqq : cover */ + + _elementDel : _elementWithKeyDel, + elementDel : _.props.elementDel, /* qqq : cover */ + _elementWithKeyDel, + elementWithKeyDel : _.props.elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel, + elementWithCardinalDel : _.props.elementWithCardinalDel, /* qqq : cover */ + _empty, + empty : _.props.empty, /* qqq : for junior : cover */ + + // iterator + + _each : _eachLeft, + each : _.props.each, /* qqq : cover */ + _eachLeft, + eachLeft : _.props.eachLeft, /* qqq : cover */ + _eachRight, + eachRight : _.props.eachRight, /* qqq : cover */ + + _while : _whileLeft, + while : _.props.while, /* qqq : cover */ + _whileLeft, + whileLeft : _.props.whileLeft, /* qqq : cover */ + _whileRight, + whileRight : _.props.whileRight, /* qqq : cover */ + + _aptLeft : _.props._aptLeft, + aptLeft : _.props.aptLeft, /* qqq : cover */ + first : _.props.first, + _aptRight : _.props._aptRight, /* qqq : cover */ + aptRight : _.props.aptRight, + last : _.props.last, /* qqq : cover */ + + _filterAct0 : _.props._filterAct0, + _filterAct : _.props._filterAct, + filterWithoutEscapeLeft : _.props.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.props.filterWithoutEscapeRight, + filterWithoutEscape : _.props.filterWithoutEscape, + filterWithEscapeLeft : _.props.filterWithEscapeLeft, + filterWithEscapeRight : _.props.filterWithEscapeRight, + filterWithEscape : _.props.filterWithEscape, + filter : _.props.filter, + + _mapAct0 : _.props._mapAct0, + _mapAct : _.props._mapAct, + mapWithoutEscapeLeft : _.props.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.props.mapWithoutEscapeRight, + mapWithoutEscape : _.props.mapWithoutEscape, + mapWithEscapeLeft : _.props.mapWithEscapeLeft, + mapWithEscapeRight : _.props.mapWithEscapeRight, + mapWithEscape : _.props.mapWithEscape, + map : _.props.map, + +} + +Object.assign( _.itself, ItselfExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Itself.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Itself_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Itself_s */ })(); + +/* */ /* begin of file Logic_s */ ( function Logic_s() { function Logic_s_naked() { ( function _l3_Logic_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// logic +// -- + +function _identicalShallow( src1, src2 ) +{ + if( src1 === src2 ) + return true; + return false; +} + +// + +function identicalShallow( src1, src2, o ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( !this.like( src1 ) ) + return false; + if( !this.like( src2 ) ) + return false; + return this._identicalShallow( src1, src2 ); +} + +// + +function _equivalentShallow( src1, src2 ) +{ + if + ( + src1 === src2 + ) + return true; + return false; +} + +// + +function equivalentShallow( src1, src2, o ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( !this.like( src1 ) ) + return false; + if( !this.like( src2 ) ) + return false; + return this._equivalentShallow( src1, src2 ); +} + +// + +function or( elements ) +{ + return new _.logic.node.Or( ... arguments ); +} + +// + +function and( elements ) +{ + return new _.logic.node.And( ... arguments ); +} + +// + +function xor( elements ) +{ + return new _.logic.node.Xor( ... arguments ); +} + +// + +function xand( elements ) +{ + return new _.logic.node.Xand( ... arguments ); +} + +// + +function _if( elements ) +{ + return _.logic.node.If( ... arguments ); +} + +// + +function first( elements ) +{ + return new _.logic.node.First( ... arguments ); +} + +// + +function second( elements ) +{ + return new _.logic.node.Second( ... arguments ); +} + +// + +function not( elements ) +{ + return new _.logic.node.Not( ... arguments ); +} + +// + +function exec( logic, ... args ) +{ + return logic.exec( ... args ); +} + +// -- +// logic extension +// -- + +let LogicExtension = +{ + + // equaler + + _identicalShallow, + identicalShallow, + identical : identicalShallow, + _equivalentShallow, + equivalentShallow, + equivalent : equivalentShallow, + + // + + and, + or, + xor, + xand, + first, + second, + not, + if : _if, + + // + + exec, + +} + +Object.assign( _.logic, LogicExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Logic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Logic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Logic_s */ })(); + +/* */ /* begin of file Map_s */ ( function Map_s() { function Map_s_naked() { ( function _l3_Map_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( !!_.props._elementWithKey, 'Expects routine _.props._elementWithKey' ); +_.assert( !!_.props.exportString, 'Expects routine _.props.exportString' ); + +// -- +// equaler +// -- + +function _identicalShallow( src1, src2 ) +{ + + if( Object.keys( src1 ).length !== Object.keys( src2 ).length ) + return false; + + for( let s in src1 ) + { + if( src1[ s ] !== src2[ s ] ) + return false; + } + + return true; +} + +// + +/** + * The containShallow() returns true, if the first object {-srcMap-} + * has the same values as the second object(ins). + * + * It takes two objects (scr, ins), + * checks if the first object {-srcMap-} has the same [key, value] as + * the second object (ins). + * If true, it returns true, + * otherwise it returns false. + * + * @param { objectLike } src - Target object. + * @param { objectLike } ins - Second object. + * Objects to compare values. + * + * @example + * _.map.containShallow( { a : 7, b : 13, c : 15 }, { a : 7, b : 13 } ); + * // returns true + * + * @example + * _.map.containShallow( { a : 7, b : 13 }, { a : 7, b : 13, c : 15 } ); + * // returns false + * + * @returns { boolean } Returns true, if the first object {-srcMap-} + * has the same values as the second object(ins). + * @function containShallow + * @throws Will throw an error if ( arguments.length !== 2 ). + * @namespace Tools/map + */ + +function containShallow( src, ins ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !this.like( src ) ) + return false; + if( !this.like( ins ) ) + return false; + + for( let s in ins ) + { + if( !( s in src ) ) + continue; + if( src[ s ] !== ins[ s ] ) + return false; + } + + return true; +} + +// /** +// * The mapsAreIdentical() returns true, if the second object (src2) +// * has the same values as the first object(src1). +// * +// * It takes two objects (scr1, src2), checks +// * if both object have the same length and [key, value] return true +// * otherwise it returns false. +// * +// * @param { objectLike } src1 - First object. +// * @param { objectLike } src2 - Target object. +// * Objects to compare values. +// * +// * @example +// * _.map.identical( { a : 7, b : 13 }, { a : 7, b : 13 } ); +// * // returns true +// * +// * @example +// * _.map.identical( { a : 7, b : 13 }, { a : 33, b : 13 } ); +// * // returns false +// * +// * @example +// * _.map.identical( { a : 7, b : 13, c : 33 }, { a : 7, b : 13 } ); +// * // returns false +// * +// * @returns { boolean } Returns true, if the second object (src2) +// * has the same values as the first object(src1). +// * @function mapsAreIdentical +// * @throws Will throw an error if ( arguments.length !== 2 ). +// * @namespace Tools +// */ +// +// function mapsAreIdentical( src1, src2 ) +// { +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// _.assert( !_.primitive.is( src1 ) ); +// _.assert( !_.primitive.is( src2 ) ); +// +// if( Object.keys( src1 ).length !== Object.keys( src2 ).length ) +// return false; +// +// for( let s in src1 ) +// { +// if( src1[ s ] !== src2[ s ] ) +// return false; +// } +// +// return true; +// } + +// -- +// extension +// -- + +/* qqq : for junior : duplicate routines */ + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +// + +let ExtensionMap = +{ + + // equaler + + _identicalShallow, + identicalShallow : _.props.identicalShallow, + identical : _.props.identical, + _equivalentShallow : _identicalShallow, + equivalentShallow : _.props.equivalentShallow, + equivalent : _.props.equivalent, + + containShallow, + contain : containShallow, + + // exporter + + _exportStringDiagnosticShallow : _.props._exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.props.exportStringDiagnosticShallow, + _exportStringCodeShallow : _.props._exportStringCodeShallow, + exportStringCodeShallow : _.props.exportStringCodeShallow, + exportString : _.props.exportString, + + // container interface + + _lengthOf : _.props._lengthOf, + lengthOf : _.props.lengthOf, /* qqq : cover */ + _hasKey : _.props._hasKey, + hasKey : _.props._hasKey, /* qqq : cover */ + _hasCardinal : _.props._hasKey, + hasCardinal : _.props._hasKey, /* qqq : cover */ + _keyWithCardinal : _.props._hasKey, + keyWithCardinal : _.props._hasKey, /* qqq : cover */ + _cardinalWithKey : _.props._cardinalWithKey, + cardinalWithKey : _.props.cardinalWithKey, /* qqq : cover */ + + _elementGet : _.props._elementWithKey, + elementGet : _.props.elementWithKey, /* qqq : cover */ + _elementWithKey : _.props._elementWithKey, + elementWithKey : _.props.elementWithKey, /* qqq : cover */ + _elementWithImplicit : _.props._elementWithImplicit, + elementWithImplicit : _.props.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal : _.props._elementWithCardinal, + elementWithCardinal : _.props.elementWithCardinal, /* qqq : cover */ + + _elementSet : _.props._elementSet, + elementSet : _.props.elementSet, /* qqq : cover */ + _elementWithKeySet : _.props._elementWithKeySet, + elementWithKeySet : _.props.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet : _.props._elementWithCardinalSet, + elementWithCardinalSet : _.props.elementWithCardinalSet, /* qqq : cover */ + + _elementDel : _.props._elementDel, + elementDel : _.props.elementDel, /* qqq : cover */ + _elementWithKeyDel : _.props._elementWithKeyDel, + elementWithKeyDel : _.props.elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel : _.props._elementWithCardinalDel, + elementWithCardinalDel : _.props.elementWithCardinalDel, /* qqq : cover */ + _empty : _.props._empty, + empty : _.props.empty, /* qqq : for junior : cover */ + + _each : _.props._each, + each : _.props.each, /* qqq : cover */ + _eachLeft : _.props._eachLeft, + eachLeft : _.props.eachLeft, /* qqq : cover */ + _eachRight : _.props._eachRight, + eachRight : _.props.eachRight, /* qqq : cover */ + + _while : _.props._while, + while : _.props.while, /* qqq : cover */ + _whileLeft : _.props._whileLeft, + whileLeft : _.props.whileLeft, /* qqq : cover */ + _whileRight : _.props._whileRight, + whileRight : _.props.whileRight, /* qqq : cover */ + + _aptLeft : _.props._aptLeft, + aptLeft : _.props.aptLeft, /* qqq : cover */ + first : _.props.first, + _aptRight : _.props._aptRight, /* qqq : cover */ + aptRight : _.props.aptRight, + last : _.props.last, /* qqq : cover */ + + _filterAct0 : _.props._filterAct0, + _filterAct : _.props._filterAct, + filterWithoutEscapeLeft : _.props.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.props.filterWithoutEscapeRight, + filterWithoutEscape : _.props.filterWithoutEscape, + filterWithEscapeLeft : _.props.filterWithEscapeLeft, + filterWithEscapeRight : _.props.filterWithEscapeRight, + filterWithEscape : _.props.filterWithEscape, + filter : _.props.filter, + + _mapAct0 : _.props._mapAct0, + _mapAct : _.props._mapAct, + mapWithoutEscapeLeft : _.props.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.props.mapWithoutEscapeRight, + mapWithoutEscape : _.props.mapWithoutEscape, + mapWithEscapeLeft : _.props.mapWithEscapeLeft, + mapWithEscapeRight : _.props.mapWithEscapeRight, + mapWithEscape : _.props.mapWithEscape, + map : _.props.map, + +} + +Object.assign( _.map, ExtensionMap ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Map.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Map_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Map_s */ })(); + +/* */ /* begin of file Module_s */ ( function Module_s() { function Module_s_naked() { ( function _l3_Module_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// +// -- + +const _toolsPath = _.path.canonize( __dirname + '/../../../../node_modules/Tools' ); +function toolsPathGet() +{ + return _toolsPath; +} + +// + +const _toolsDir = _.path.canonize( __dirname + '/../../../../wtools' ); +function toolsDirGet() +{ + return _toolsDir; +} + +// -- +// module extension +// -- + +var ModuleExtension = +{ + + toolsPathGet, + toolsDirGet, + +} + +Object.assign( _.module, ModuleExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Module.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Module_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Module_s */ })(); + +/* */ /* begin of file Number_s */ ( function Number_s() { function Number_s_naked() { ( function _l1_Numbers_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// number +// -- + +function _identicalShallow( a, b ) +{ + + if( _.number.s.areAll( [ a, b ] ) ) + return Object.is( a, b ) || a === b; + + return false; +} + +// + +function identicalShallow( src1, src2, o ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( !this.is( src1 ) ) + return false; + if( !this.is( src2 ) ) + return false; + + return this._identicalShallow( ... arguments ); +} + +// + +function _identicalShallowStrictly( a, b ) +{ + /* + it takes into account -0 === +0 case + */ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.number.s.areAll( [ a, b ] ) ) + return Object.is( a, b ); + + return false; +} + +// + +function identicalShallowStrictly( src1, src2, o ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( !this.is( src1 ) ) + return false; + if( !this.is( src2 ) ) + return false; + + return this._identicalShallowStrictly( ... arguments ); +} + +// + +// function _equivalentShallow( a, b, accuracy ) +// { +// +// if( accuracy !== undefined ) +// _.assert( _.number.is( accuracy ) && accuracy >= 0, 'Accuracy has to be a number >= 0' ); +// +// /* qqq for junior : bad! */ +// +// if( _.number.is( a ) && _.number.is( b ) ) +// { +// if( Object.is( a, b ) ) +// return true; +// } +// +// if( !_.number.is( a ) && !_.bigInt.is( a ) ) +// return false; +// +// if( !_.number.is( b ) && !_.bigInt.is( b ) ) +// return false; +// +// /* qqq for junior : cache results of *Is calls at the beginning of the routine */ +// +// // else +// // { +// // return false; +// // } +// +// if( accuracy === undefined ) +// accuracy = _.accuracy; +// +// if( _.bigInt.is( a ) ) +// { +// if( _.intIs( b ) ) +// { +// b = BigInt( b ); +// } +// // else +// // { +// // a = Number( a ); +// // if( a === +Infinity || a === -Infinity ) +// // return false; +// // } +// } +// +// if( _.bigInt.is( b ) ) +// { +// if( _.intIs( a ) ) +// { +// a = BigInt( a ); +// } +// // else +// // { +// // b = Number( b ); +// // if( b === +Infinity || b === -Infinity ) +// // return false; +// // } +// } +// +// if( Object.is( a, b ) ) +// return true; +// +// if( _.bigInt.is( a ) && _.bigInt.is( b ) ) +// { +// if( _.intIs( accuracy ) ) +// { +// return BigIntMath.abs( a - b ) <= BigInt( accuracy ); +// } +// else +// { +// let diff = BigIntMath.abs( a - b ); +// if( diff <= BigInt( Math.floor( accuracy ) ) ) +// return true; +// if( diff > BigInt( Math.ceil( accuracy ) ) ) +// return false; +// diff = Number( diff ); +// if( diff === Infinity || diff === -Infinity ) +// return false; +// return Math.abs( diff ) <= accuracy; +// } +// } +// +// // if( !_.number.is( a ) ) +// // return false; +// // +// // if( !_.number.is( b ) ) +// // return false; +// +// return Math.abs( a - b ) <= accuracy; +// // return +( Math.abs( a - b ) ).toFixed( 10 ) <= +( accuracy ).toFixed( 10 ); +// } + +// + +/* xxx : qqq : refactor */ +function _equivalentShallow( a, b, accuracy ) +{ + let result; + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + if( accuracy !== undefined ) + _.assert + ( + ( _.number.is( accuracy ) || _.bigInt.is( accuracy ) ) && accuracy >= 0 && accuracy !== Infinity, + 'Accuracy has to be a finite Number >= 0' + ); + + let bigIntIsA = _.bigInt.is( a ); + let bigIntIsB = _.bigInt.is( b ); + let numberIsA = _.number.is( a ); + let numberIsB = _.number.is( b ); + + if( !numberIsA && !bigIntIsA ) + return false; + + if( !numberIsB && !bigIntIsB ) + return false; + + if( numberIsA && numberIsB ) + { + if( Object.is( a, b ) ) + return true; + } + + /* + Cases : + a : BIF/BOF/FIB/FOB; + b : BIF/BOF/FIB/FOB; + accuracy : BIF/BOF/FIB/FOB; + + a b accuracy implemented covered + + BIF BIF BIF/BOF/FIB/FOB + ++++ + BIF BOF BIF/BOF/FIB/FOB + ++++ + BIF FIB BIF/BOF/FIB/FOB + ++++ + BIF FOB BIF/BOF/FIB/FOB + ++++ + + BOF BOF BIF/BOF/FIB/FOB + ++++ + BOF FIB BIF/BOF/FIB/FOB + ++++ + BOF FOB BIF/BOF/FIB/FOB + ++++ + + FIB FIB BIF/BOF/FIB/FOB + ++++ + FIB FOB BIF/BOF/FIB/FOB + ++++ + + FOB FOB BIF/BOF/FIB/FOB + ++++ + + Definitions : + BIF = bigint inside range of float ( 0n, 3n, BigInt( Math.pow( 2, 52 ) ) ) + BOF = bigint outside range of float ( BigInt( Math.pow( 2, 54 ) ) ) + FIB = float inside range of bigint ( 5, 30 ) + FOB = float outside range of bigint ( 5.5, 30.1 ) + + */ + + if( accuracy === undefined ) + accuracy = _.accuracy; + + if( bigIntIsA && bigIntIsB ) /* a : BIF/BOF, b : BIF/BOF , accuracy : BIF/BOF/FIB/FOB 3 */ + { + return abs( a - b ) <= accuracy; + } + + if( bigIntIsA ) /* a : BIF/BOF, b : FIB/FOB , accuracy : BIF/BOF/FIB/FOB 4 */ + [ a, b, result ] = bigintCompare( a, b ); + if( result !== undefined ) + return result; + + // { + // if( _.intIs( b ) ) + // { + // b = BigInt( b ); + // } + // else + // { + // if( a >= Number.MIN_SAFE_INTEGER && a <= Number.MAX_SAFE_INTEGER ) /* a : BIF, b : FOB, accuracy : BIF/BOF/FIB/FOB */ + // { + // a = Number( a ); + // } + // else /* a : BOF, b : FOB, accuracy : BIF/BOF/FIB/FOB */ + // { + // if( accuracy >= Number.MIN_SAFE_INTEGER && accuracy <= Number.MAX_SAFE_INTEGER ) /* a : BOF, b : FOB, accuracy : FIB/FOB */ + // { + // let decimal = b % 1; + // b = BigInt( Math.floor( b ) ) + // return abs( a - b ) <= accuracy + decimal; + // } + // else /* a : BOF, b : FOB, accuracy : BIF/BOF */ + // { + // b = BigInt( Math.round( b ) ); + // } + // } + // } + // } + + if( bigIntIsB ) /* a : FIB/FOB, b : BIF/BOF , accuracy : BIF/BOF/FIB/FOB */ + [ b, a, result ] = bigintCompare( b, a ); + if( result !== undefined ) + return result; + + // { + // if( _.intIs( a ) ) /* a : FIB, b : BIF/BOF, accuracy : BIF/BOF/FIB/FOB */ + // { + // a = BigInt( a ); + // } + // else + // { + // if( b >= Number.MIN_SAFE_INTEGER && b <= Number.MAX_SAFE_INTEGER ) /* a : FOB, b : BIF, accuracy : BIF/BOF/FIB/FOB */ + // { + // b = Number( b ); + // } + // else /* a : FOB, b : BOF , accuracy : BIF/BOF/FIB/FOB */ + // { + // if( accuracy >= Number.MIN_SAFE_INTEGER && accuracy <= Number.MAX_SAFE_INTEGER ) /* a : FOB, b : BOF, accuracy : FIB/FOB */ + // { + // let decimal = a % 1; + // a = BigInt( Math.floor( a ) ) + // return abs( a - b ) <= accuracy + decimal; + // } + // else /* a : FOB, b : BOF, accuracy : BIF/BOF */ + // { + // a = BigInt( Math.round( a ) ); + // } + // } + // } + // } + + if( numberIsA && numberIsB ) /* a : FIB/FOB, b : FIB/FOB, accuracy : BIF/BOF/FIB/FOB 3 */ + return Math.abs( a - b ) <= accuracy; + else + return abs( a - b ) <= accuracy; + + /* - */ + + function bigintCompare( a, b ) + { + if( _.intIs( b ) ) + { + b = BigInt( b ); + } + else + { + if( a >= Number.MIN_SAFE_INTEGER && a <= Number.MAX_SAFE_INTEGER ) /* a : BIF, b : FOB, accuracy : BIF/BOF/FIB/FOB */ + { + a = Number( a ); + } + else /* a : BOF, b : FOB, accuracy : BIF/BOF/FIB/FOB */ + { + if( accuracy >= Number.MIN_SAFE_INTEGER && accuracy <= Number.MAX_SAFE_INTEGER ) /* a : BOF, b : FOB, accuracy : FIB/FOB */ + { + let decimal = b % 1; + b = BigInt( Math.floor( b ) ) + return [ a, b, abs( a - b ) <= accuracy + decimal ]; + } + else /* a : BOF, b : FOB, accuracy : BIF/BOF */ + { + b = BigInt( Math.round( b ) ); + } + } + } + return [ a, b, undefined ]; + } + + /* - */ + + function sign( value ) + { + if( value > BigInt( 0 ) ) + return BigInt( 1 ); + if( value < BigInt( 0 ) ) + return BigInt( -1 ); + + return BigInt( 0 ); + } + + /* - */ + + function abs( value ) + { + if( sign( value ) === BigInt( -1 ) ) + return -value; + return value; + } + + /* - */ + +} + +// + +function equivalentShallow( src1, src2, accuracy ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( !this.like( src1 ) ) + return false; + if( !this.like( src2 ) ) + return false; + return this._equivalentShallow( ... arguments ); +} + +// -- +// extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +// + +let NumberExtension = +{ + + // equaler + + _identicalShallow, + identicalShallow, + identical : identicalShallow, + + _identicalShallowStrictly, + identicalShallowStrictly, + identicalStrictly : identicalShallowStrictly, + + _equivalentShallow, + equivalentShallow, + equivalent : equivalentShallow, + + // areEquivalentShallow : areEquivalent, + // areIdentical, + // areIdenticalNotStrictly, + // areEquivalent, + +} + +Object.assign( _.number, NumberExtension ); + +// + +let NumbersExtension = +{ +} + +Object.assign( _.number.s, NumbersExtension ); + +})(); + + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Number.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Number_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Number_s */ })(); + +/* */ /* begin of file Object_s */ ( function Object_s() { function Object_s_naked() { ( function _l3_Object_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( !!_.props._elementWithKey, 'Expects routine _.props._elementWithKey' ); +_.assert( !!_.props.keys, 'Expects routine _.props.keys' ); + +// -- +// equaler +// -- + +function _identicalShallow( src1, src2 ) +{ + + if( _.aux.is( src1 ) && _.aux.is( src2 ) ) + return _.aux._identicalShallow( src1, src2 ); + + if( _.countable.is( src1 ) && _.countable.is( src2 ) ) + return _.countable._identicalShallow( src1, src2 ); + + let equal = _.class.methodEqualOf( src1 ) || _.class.methodEqualOf( src2 ); + if( equal ) + return equal( src1, src2, {} ); + + return src1 === src2; +} + +// + +function _equivalentShallow( src1, src2 ) +{ + + if( _.aux.is( src1 ) && _.aux.is( src2 ) ) + return _.aux._equivalentShallow( src1, src2 ); + + if( _.countable.is( src1 ) && _.countable.is( src2 ) ) + return _.countable._equivalentShallow( src1, src2 ); + + let equal = _.class.methodEqualOf( src1 ) || _.class.methodEqualOf( src2 ); + + if( equal ) + return equal( src1, src2, {} ); + + return src1 === src2; +} + +// -- +// exporter +// -- + +function _exportStringDiagnosticShallow( src ) +{ + let result = ''; + let method = _.class.methodExportStringOf( src ); + + if( method ) + { + result = method.call( src, { verbosity : 1 } ); + result = _.strShort_( result ).result; + } + else + { + if( _.countable.is( src ) ) + result = _.countable.exportStringDiagnosticShallow( src ); + else + result = `{- ${_.entity.strType( src )} -}`; + } + + return result; +} + +// -- +// inspector +// -- + +function _lengthOf( src ) +{ + if( _.countable.is( src ) ) + return _.countable._lengthOf( src ); + return _.props._lengthOf( src ); +} + +// + +function _hasKey( src, key ) +{ + // if( _.number.is( key ) ) + if( _.countable.is( src ) && _.number.is( key ) ) + return _.countable._hasKey( src, key ); + return _.props._hasKey( src, key ); +} + +// + +function _hasCardinal( src, cardinal ) +{ + if( _.countable.is( src ) ) + return _.countable._hasCardinal( src, cardinal ); + return _.props._hasCardinal( src, cardinal ); +} + +// + +function _keyWithCardinal( src, cardinal ) +{ + if( _.countable.is( src ) ) + return _.countable._keyWithCardinal( src, cardinal ); + return _.props._keyWithCardinal( src, cardinal ); +} + +// + +function _cardinalWithKey( src, key ) +{ + if( _.countable.is( src ) ) + return _.countable._cardinalWithKey( src, key ); + return _.props._cardinalWithKey( src, key ); +} + +// -- +// elementor +// -- + +function _elementWithKey( src, key ) +{ + // if( _.number.is( key ) ) + if( _.countable.is( src ) && _.number.is( key ) ) + return _.countable._elementWithKey( src, key ); + return _.props._elementWithKey( src, key ); +} + +// + +function _elementWithCardinal( src, cardinal ) +{ + if( _.countable.is( src ) ) + return _.countable._elementWithCardinal( src, cardinal ); + return _.props._elementWithCardinal( src, cardinal ); +} + +// + +function _elementWithKeySet( dst, key, val ) +{ + // if( _.number.is( key ) ) + if( _.countable.is( src ) && _.number.is( key ) ) + return _.countable._elementWithKeySet( dst, key, val ); + return _.props._elementWithKeySet( dst, key, val ); +} + +// + +function _elementWithCardinalSet( dst, cardinal, val ) +{ + if( _.countable.is( dst ) ) + return _.countable._elementWithCardinalSet( dst, cardinal, val ); + return _.props._elementWithCardinalSet( dst, cardinal, val ); +} + +// + +function _elementWithKeyDel( dst, key ) +{ + // if( _.number.is( key ) ) + if( _.countable.is( src ) && _.number.is( key ) ) + return _.countable._elementWithKeyDel( dst, key ); + return _.props._elementWithKeyDel( dst, key ); +} + +// + +function _elementWithCardinalDel( dst, cardinal ) +{ + if( _.countable.is( dst ) ) + return _.countable._elementWithCardinalDel( dst, cardinal ); + return _.props._elementWithCardinalDel( dst, cardinal ); +} + +// + +function _empty( dst ) +{ + if( _.countable.is( dst ) ) + return _.countable._empty( dst ); + return _.props._empty( dst ); +} + +// -- +// iterator +// -- + +function _eachLeft( src, onEach ) +{ + if( _.countable.is( src ) ) + return _.countable._eachLeft( src, onEach ); + return _.props._eachLeft( src, onEach ); +} + +// + +function _eachRight( src, onEach ) +{ + if( _.countable.is( src ) ) + return _.countable._eachRight( src, onEach ); + return _.props._eachRight( src, onEach ); +} + +// + +function _whileLeft( src, onEach ) +{ + if( _.countable.is( src ) ) + return _.countable._whileLeft( src, onEach ); + return _.props._whileLeft( src, onEach ); +} + +// + +function _whileRight( src, onEach ) +{ + if( _.countable.is( src ) ) + return _.countable._whileRight( src, onEach ); + return _.props._whileRight( src, onEach ); +} + +// + +function _filterAct0( dst, src, ... args ) +{ + if( _.countable.is( src ) ) + return _.countable._filterAct0( dst, src, ... args ); + return _.props._filterAct0( dst, src, ... args ); +} + +// + +function _mapAct0( dst, src, ... args ) +{ + if( _.countable.is( src ) ) + return _.countable._mapAct0( dst, src, ... args ); + return _.props._mapAct0( dst, src, ... args ); +} + +// -- +// extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +// + +let ObjectExtension = +{ + + // equaler + + _identicalShallow, + identicalShallow : _.props.identicalShallow, + identical : _.props.identical, + _equivalentShallow : _identicalShallow, + equivalentShallow : _.props.equivalentShallow, + equivalent : _.props.equivalent, + + // exporter + + _exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.props.exportStringDiagnosticShallow, + _exportStringCodeShallow : _exportStringDiagnosticShallow, + exportStringCodeShallow : _.props.exportStringCodeShallow, + exportString : _.props.exportString, + + // inspector + + _lengthOf, + lengthOf : _.props.lengthOf, /* qqq : cover */ + _hasKey, + hasKey : _.props.hasKey, /* qqq : cover */ + _hasCardinal, + hasCardinal : _.props.hasCardinal, /* qqq : cover */ + _keyWithCardinal, + keyWithCardinal : _.props.keyWithCardinal, /* qqq : cover */ + _cardinalWithKey, + cardinalWithKey : _.props.cardinalWithKey, /* qqq : cover */ + + // elementor + + _elementGet : _elementWithKey, + elementGet : _.props.elementGet, /* qqq : cover */ + _elementWithKey, + elementWithKey : _.props.elementWithKey, /* qqq : cover */ + _elementWithImplicit : _.props._elementWithImplicit, + elementWithImplicit : _.props.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal, + elementWithCardinal : _.props.elementWithCardinal, /* qqq : cover */ + + _elementSet : _elementWithKeySet, + elementSet : _.props.elementSet, /* qqq : cover */ + _elementWithKeySet, + elementWithKeySet : _.props.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet, + elementWithCardinalSet : _.props.elementWithCardinalSet, /* qqq : cover */ + + _elementDel : _elementWithKeyDel, + elementDel : _.props.elementDel, /* qqq : cover */ + _elementWithKeyDel, + elementWithKeyDel : _.props.elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel, + elementWithCardinalDel : _.props.elementWithCardinalDel, /* qqq : cover */ + _empty, + empty : _.props.empty, /* qqq : for junior : cover */ + + // iterator + + _each : _eachLeft, + each : _.props.each, /* qqq : cover */ + _eachLeft, + eachLeft : _.props.eachLeft, /* qqq : cover */ + _eachRight, + eachRight : _.props.eachRight, /* qqq : cover */ + + _while : _whileLeft, + while : _.props.while, /* qqq : cover */ + _whileLeft, + whileLeft : _.props.whileLeft, /* qqq : cover */ + _whileRight, + whileRight : _.props.whileRight, /* qqq : cover */ + + _aptLeft : _.props._aptLeft, + aptLeft : _.props.aptLeft, /* qqq : cover */ + first : _.props.first, + _aptRight : _.props._aptRight, /* qqq : cover */ + aptRight : _.props.aptRight, + last : _.props.last, /* qqq : cover */ + + _filterAct0, + _filterAct : _.props._filterAct, + filterWithoutEscapeLeft : _.props.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.props.filterWithoutEscapeRight, + filterWithoutEscape : _.props.filterWithoutEscape, + filterWithEscapeLeft : _.props.filterWithEscapeLeft, + filterWithEscapeRight : _.props.filterWithEscapeRight, + filterWithEscape : _.props.filterWithEscape, + filter : _.props.filter, + + _mapAct0, + _mapAct : _.props._mapAct, + mapWithoutEscapeLeft : _.props.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.props.mapWithoutEscapeRight, + mapWithoutEscape : _.props.mapWithoutEscape, + mapWithEscapeLeft : _.props.mapWithEscapeLeft, + mapWithEscapeRight : _.props.mapWithEscapeRight, + mapWithEscape : _.props.mapWithEscape, + map : _.props.map, + +} + +// + +Object.assign( _.object, ObjectExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Object.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Object_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Object_s */ })(); + +/* */ /* begin of file Primitive_s */ ( function Primitive_s() { function Primitive_s_naked() { ( function _l3_Primitive_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// primitive +// -- + +function _identicalShallow( src1, src2 ) +{ + + if( !_.primitive.is( src1 ) ) + return false; + if( !_.primitive.is( src2 ) ) + return false; + + return Object.is( src1, src2 ); +} + +// + +function identicalShallow( src1, src2, o ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( !this.like( src1 ) ) + return false; + if( !this.like( src2 ) ) + return false; + + return this._identicalShallow( ... arguments ); +} + +// + +function _equivalentShallow( src1, src2, accuracy ) +{ + + if( _.strsAreAll([ src1, src2 ]) ) + return _.str.equivalentShallow( src1, src2 ); + + if( _.bool.like( src1 ) && _.bool.like( src2 ) ) + return _.bool.equivalentShallow( src1, src2 ); + + if + ( + ( _.number.is( src1 ) || _.bigInt.is( src1 ) ) + && ( _.number.is( src2 ) || _.bigInt.is( src2 ) ) + ) + return _.number.equivalentShallow( src1, src2, accuracy ); + + return Object.is( src1, src2 ); +} + +// + +function equivalentShallow( src1, src2, accuracy ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( !this.like( src1 ) ) + return false; + if( !this.like( src2 ) ) + return false; + return this._equivalentShallow( ... arguments ); +} + +// -- +// +// -- + +function exportStringCodeShallow( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + _.assert( _.primitive.is( src ) ); + + if( _.symbol.is( src ) ) + return _.symbol.exportStringCodeShallow( src ); + + if( _.bigInt.is( src ) ) + return _.bigInt.exportStringCodeShallow( src ); + + if( _.strIs( src ) ) + return `'${src}'`; + + return String( src ); +} + +// + +function exportStringDiagnosticShallow( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + _.assert( _.primitive.is( src ) ); + + if( _.symbol.is( src ) ) + return _.symbol.exportStringDiagnosticShallow( src ); + + if( _.bigInt.is( src ) ) + return _.bigInt.exportStringDiagnosticShallow( src ); + + return String( src ); +} + +// -- +// extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +// + +let PrimitiveExtension = +{ + + // equaler + + _identicalShallow, + identicalShallow, + identical : identicalShallow, + _equivalentShallow, + equivalentShallow, + equivalent : equivalentShallow, + + // exporter + + exportStringCodeShallow, + exportStringDiagnosticShallow, + exportString : exportStringDiagnosticShallow, + +} + +Object.assign( _.primitive, PrimitiveExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Primitive.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Primitive_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Primitive_s */ })(); + +/* */ /* begin of file Process_s */ ( function Process_s() { function Process_s_naked() { ( function _l3_Process_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// +// -- + +function on( o ) +{ + o = _.event.onHead( _.event.on, arguments ); + return _.event.on( this._edispatcher, o ); +} + +on.defaults = +{ + callbackMap : null, +}; + +// + +function once( o ) +{ + o = _.event.onHead( _.event.once, arguments ); + return _.event.once( this._edispatcher, o ); +} + +once.defaults = +{ + callbackMap : null, +}; + +// + +function off( o ) +{ + o = _.event.offHead( _.event.off, arguments ); + return _.event.off( this._edispatcher, o ); +} + +off.defaults = +{ + callbackMap : null, +}; + +// + +function eventHasHandler( o ) +{ + o = _.event.eventHasHandlerHead( _.event.eventHasHandler, arguments ); + return _.event.eventHasHandler( this._edispatcher, o ); +} + +eventHasHandler.defaults = +{ + eventName : null, + eventHandler : null, +} + +// + +function eventGive() +{ + let o = _.event.eventGiveHead( this._edispatcher, eventGive, arguments ); + return _.event.eventGive( this._edispatcher, o ); + // return _.event.eventGive( this._edispatcher, ... arguments ); +} + +eventGive.defaults = +{ + ... _.event.eventGive.defaults, + origination : null, + err : null, +} + +// -- +// +// -- + +let Inspector = null; +function isDebugged() +{ + _.assert( arguments.length === 0, 'Expects no arguments' ); + + // return false; // xxx + + if( typeof process === 'undefined' ) + return false; + + if( Inspector === null ) + try + { + Inspector = require( 'inspector' ); + } + catch( err ) + { + Inspector = false; + } + + if( Inspector ) + return _.strIs( Inspector.url() ); + + if( !process.execArgv.length ) + return false; + + let execArgvString = process.execArgv.join(); + return _.strHasAny( execArgvString, [ '--inspect', '--inspect-brk', '--debug-brk' ] ); +} + +// + +function insideTestContainer() +{ + if( !_global_.process ) + return false; + return 'CI' in _global_.process.env; +} + +// + +function entryPointStructure() +{ + let result = Object.create( null ); + if( _global.process !== undefined ) + { + if( _global.process.argv ) + result.execPath = _global.process.argv.join( ' ' ); + if( _.routine.is( _global.process.cwd ) ) + result.currentPath = _global.process.cwd(); + } + return result; +} + +// + +function entryPointInfo() +{ + let data = _.process.entryPointStructure(); + let result = ''; + + if( data.currentPath ) + result = join( 'Current path', data.currentPath ); + if( data.execPath ) + result = join( 'Exec path', data.execPath ); + + return result; + + /* */ + + function join( left, right ) + { + if( result ) + result += '\n'; + result += left + ' : ' + right; + return result; + } +} + +// -- +// implementation +// -- + +let Events = +{ + 'available' : [], + 'uncaughtError' : [], +} + +let _edispatcher = +{ + events : Events, +} + +let Extension = +{ + + // event + + _edispatcher, + on, + once, + off, + eventHasHandler, + eventGive, + + // dichotomy + + isDebugged, + insideTestContainer, + + // entry point + + entryPointStructure, + entryPointInfo, + +} + +// + +Object.assign( _.process, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Process.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Process_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Process_s */ })(); + +/* */ /* begin of file Regexp_s */ ( function Regexp_s() { function Regexp_s_naked() { ( function _l3_Regexp_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// regexp +// -- + +function _identicalShallow( src1, src2 ) +{ + return src1.source === src2.source && src1.flags === src2.flags; +} + +// + +function identicalShallow( src1, src2, o ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( !_.regexp.is( src1 ) || !_.regexp.is( src2 ) ) + return false; + return _.regexp._identicalShallow( src1, src2 ); +} + +// + +function _equivalentShallow( src1, src2 ) +{ + let strIs1 = _.strIs( src1 ); + let strIs2 = _.strIs( src2 ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !strIs1 && strIs2 ) + return _.regexp._equivalentShallow( src2, src1 ); + + _.assert( _.regexpLike( src1 ), 'Expects string-like ( string or regexp )' ); + _.assert( _.regexpLike( src1 ), 'Expects string-like ( string or regexp )' ); + + if( strIs1 && strIs2 ) + { + return src1 === src2; + // if( src1 === src2 ) + // return true; + // return _.str.lines.strip( src1 ) === _.str.lines.strip( src2 ); + } + else if( strIs1 ) + { + _.assert( !!src2.exec ); + let matched = src2.exec( src1 ); + if( !matched ) + return false; + if( matched[ 0 ].length !== src1.length ) + return false; + return true; + } + else + { + return _.regexp.identical( src1, src2 ); + } + + return false; +} + +// + +function equivalentShallow( src1, src2 ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( !_.regexp.like( src1 ) || !_.regexp.like( src2 ) ) + return false; + return _.regexp._equivalentShallow( src1, src2 ); +} + +// + +function exportStringDiagnosticShallow( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + _.assert( _.regexp.is( src ) ); + + return `/${src.source}/${src.flags}`; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + + regexpIdentical : identicalShallow, + regexpEquivalent : equivalentShallow, + +} + +Object.assign( _, ToolsExtension ) + +// + +let RegexpExtension = +{ + + // regexp + + _identicalShallow, + identicalShallow, + identical : identicalShallow, + _equivalentShallow, + equivalentShallow, + equivalent : equivalentShallow, + + // exporter + + exportString : exportStringDiagnosticShallow, + exportStringDiagnosticShallow, + exportStringCodeShallow : exportStringDiagnosticShallow, + +} + +Object.assign( _.regexp, RegexpExtension ) + +// + +let RegexpsExtension = +{ + + +} + +Object.assign( _.regexp.s, RegexpsExtension ) + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Regexp.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Regexp_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Regexp_s */ })(); + +/* */ /* begin of file Routine_s */ ( function Routine_s() { function Routine_s_naked() { ( function _l3_Routine_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +/* qqq : for Dmytro : update jsdoc, please */ +/** + * The routine er() extend mechanism of routines constructing of routine routine.unite(). + * The routine er() adds to routine {-routine-} field {-er-} that is a functor for generating + * of new routine similar to original routine but with changed map {-defaults-}. + * + * @example + * function test_head( routine, args ) + * { + * let o = args[ 0 ]; + * if( !_.mapIs( o ) ) + * { + * if( o !== undefined ) + * o = { arg : 0 }; + * else + * o = Object.create( null ); + * } + * + * _.routine.options( routine, o ); + * return o; + * } + * + * function test_body( o ) + * { + * return o; + * } + * test_body.defaults = { arg : null, arg2 : 'arg2' }; + * + * let routine = _.routine.unite( test_head, test_body ); + * console.log( routine.er === undefined ); + * // log : true + * + * let erhead = ( routine, args ) => + * { + * if( _.mapIs( args[ 0 ] ) ) + * return args[ 0 ]; + * return { 'arg' : args[ 0 ] }; + * }; + * _.routine.er( routine, erhead ); + * console.log( _.routine.is( routine.er ) ); + * // log : true + * + * let newRoutine = routine.er( 'arg1' ); + * console.log( newRoutine.defaults ); + * // log : { arg : 'arg1', arg2 : 'arg2' } + * + * var resultOld = routine(); + * console.log( resultOld ); + * // log : { arg : null, arg2 : 'arg2' } + * var resultNew = newRoutine(); + * console.log( resultNew ); + * // log : { arg : 'arg1', arg2 : 'arg2' } + * + * @param { Function } routine - The routine from which generates new routine. + * Routine should be generated by routine.unite. + * @param { Function } erhead - The routine to make map {-defaults-} for new routine. + * @returns { Function } - Returns original routine with functor in field {-er-}. + * @function er + * @throws { Error } If arguments.length neither is 1, nor 2. + * @throws { Error } If {-routine-} is not a Function. + * @throws { Error } If {-erhead-} is not a Function. + * @throws { Error } If {-routine-} has not fields {-head-} and {-body-}. + * The fields should have type Function. + * @namespace Tools + */ + +function er( routine, erhead ) +{ + if( routine.er ) + return routine.er; /* Dmytro : maybe before return should be assert like : _.assert( _.routine.is( routine.er ) ) */ + routine.er = _.routine.erMake( ... arguments ); + return routine; +} + +// + +/* qqq : for Dmytro : update jsdoc, please */ +/** + * The routine erMake() extend mechanism of routines constructing of routine routine.unite(). + * The routine erMake() returns functor for generating of new routine similar to original + * routine {-routine-} but with changed map {-defaults-}. + * + * @example + * function test_head( routine, args ) + * { + * let o = args[ 0 ]; + * if( !_.mapIs( o ) ) + * { + * if( o !== undefined ) + * o = { arg : 0 }; + * else + * o = Object.create( null ); + * } + * + * _.routine.options( routine, o ); + * return o; + * } + * + * function test_body( o ) + * { + * return o; + * } + * test_body.defaults = { arg : null, arg2 : 'arg2' }; + * + * let routine = _.routine.unite( test_head, test_body ); + * let erhead = ( routine, args ) => + * { + * if( _.mapIs( args[ 0 ] ) ) + * return args[ 0 ]; + * return { 'arg' : args[ 0 ] }; + * }; + * let functor = _.routine.erMake( routine, erhead ); + * console.log( _.routine.is( functor ) ); + * // log : true + * + * let newRoutine = functor( 'arg1' ); + * console.log( newRoutine.defaults ); + * // log : { arg : 'arg1', arg2 : 'arg2' } + * + * var resultOld = routine(); + * console.log( resultOld ); + * // log : { arg : null, arg2 : 'arg2' } + * var resultNew = newRoutine(); + * console.log( resultNew ); + * // log : { arg : 'arg1', arg2 : 'arg2' } + * + * @param { Function } routine - The routine from which generates new routine. + * Routine should be generated by routine.unite. + * @param { Function } erhead - The routine to make map {-defaults-} for new routine. + * @returns { Function } - Returns functor to generate new routine with changed map {-defaults-}. + * @function erMake + * @throws { Error } If arguments.length neither is 1, nor 2. + * @throws { Error } If {-routine-} is not a Function. + * @throws { Error } If {-erhead-} is not a Function. + * @throws { Error } If {-routine-} has not fields {-head-} and {-body-}. + * The fields should have type Function. + * @namespace Tools + */ + +function erMake( routine, erhead ) +{ + + erhead = erhead || routine.erhead || routine.head; + let head = routine.head; + let body = routine.body; + let defaults = routine.defaults; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.routine.is( routine ) ); + _.assert( _.routine.is( erhead ) ); + _.assert( _.routine.is( head ) ); + _.assert( _.routine.is( body ) ); + _.assert( _.object.isBasic( defaults ) ); + + return erMake; + + function erMake() + { + let self = this; + let op = erhead.call( self, routine, arguments ); + + _.assert( _.mapIs( op ) ); + _.map.assertHasOnly( op, defaults ); + + er.defaults = _.props.supplement( op, defaults ); + + return er; + + function er() + { + let result; + let op2 = head.call( self, er, arguments ); + if( _.unrollIs( op2 ) ) + result = body.apply( self, op2 ); + else if( _.mapIs( op2 ) ) + result = body.call( self, op2 ); + return result; + } + + } + +} + +// -- +// +// -- + +function exportStringDiagnosticShallow( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + _.assert( _.routine.is( src ) ); + + if( src.name ) + return `{- routine ${src.name} -}`; + else + return `{- routine.anonymous -}`; +} + +// -- +// extension +// -- + +let RoutineExtension = +{ + + // er + + er, + erMake, + + // exporter + + exportString : exportStringDiagnosticShallow, + // exportStringDiagnosticShallow : exportStringDiagnosticShallow, + exportStringDiagnosticShallow, + exportStringCodeShallow : exportStringDiagnosticShallow, + // exportStringDiagnostic : exportStringDiagnosticShallow, + // exportStringCode : exportStringDiagnosticShallow, + +} + +// + +Object.assign( _.routine, RoutineExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Routine.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Routine_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Routine_s */ })(); + +/* */ /* begin of file Seeker_s */ ( function Seeker_s() { function Seeker_s_naked() { ( function _l3_Seeker_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// tools extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Seeker.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Seeker_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Seeker_s */ })(); + +/* */ /* begin of file Set_s */ ( function Set_s() { function Set_s_naked() { ( function _l3_Set_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// +// -- + +function toArray( src ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.set.like( src ) ); + return [ ... src ]; +} + +// + +function setsToArrays( srcs ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.longIs( srcs ) ); + let result = []; + for( let s = 0, l = srcs.length ; s < l ; s++ ) + result[ s ] = _.set.toArray( srcs[ s ] ); + return result; +} + +// -- +// exporter +// -- + +function _exportStringDiagnosticShallow( src, o ) +{ + return `{- ${_.entity.strType( src )} with ${_.entity.lengthOf( src )} elements -}`; +} + +// -- +// equaler +// -- + +function _identicalShallow( src1, src2 ) +{ + if( src1.size !== src2.size) + return false; + + for( let el of src1 ) + if( !src2.has( el ) ) + return false; + + return true; +} + +// -- +// container interface +// -- + +function _lengthOf( src ) +{ + return src.size; +} + +// + +function _hasKey( src, key ) +{ + return src.has( key ); +} + +// + +function _hasCardinal( src, cardinal ) +{ + if( cardinal < 0 ) + return false; + return cardinal < src.size; +} + +// + +function _keyWithCardinal( src, cardinal ) +{ + if( cardinal < 0 || src.size <= cardinal ) + return [ undefined, false ]; + return [ [ ... src ][ cardinal ], true ]; +} + +// + +function _cardinalWithKey( src, key ) +{ + return [ ... src ].indexOf( key ); +} + +// + +function _elementWithKey( src, key ) +{ + if( src.has( key ) ) + return [ key, key, true ]; + return [ undefined, key, false ]; +} + +// + +function _elementWithCardinal( src, key ) +{ + if( key < 0 || src.size <= key || !_.numberIs( key ) ) + if( src.size <= key || !_.number.is( key ) ) + return [ undefined, key, false ]; + return [ [ ... src ][ key ], key, true ]; +} + +// + +function _elementWithKeySet( dst, key, val ) +{ + // debugger; + dst.add( val ); + return [ val, true ]; +} + +// + +function _elementWithCardinalSet( dst, cardinal, val ) +{ + let was = this._elementWithCardinal( dst, cardinal ); + if( was[ 2 ] === true ) + { + dst.delete( was[ 0 ] ); + dst.add( val ); + return [ val, true ]; + } + else + { + return [ cardinal, false ]; + } +} + +// + +function _elementWithKeyDel( dst, key ) +{ + if( !this._hasKey( dst, key ) ) + return false; + dst.delete( key ); + return true; +} + +// + +function _elementWithCardinalDel( dst, cardinal ) +{ + let has = this._keyWithCardinal( dst, cardinal ); + if( !has[ 1 ] ) + return false; + dst.delete( has[ 0 ] ); + return true; +} + +// + +function _empty( dst ) +{ + dst.clear(); + return dst; +} + +// + +function _eachLeft( src, onEach ) +{ + let c = 0; + for( let e of src ) + { + onEach( e, e, c, src ); + c += 1; + } +} + +// + +function _eachRight( src, onEach ) +{ + let src2 = [ ... src ]; + for( let k = src2.length-1 ; k >= 0 ; k-- ) + { + let e = src[ k ]; + onEach( e, e, k, src ); + } +} + +// + +function _whileLeft( src, onEach ) +{ + if( src.size === 0 ) + return [ undefined, undefined, -1, true ]; + let c = 0; + let laste; + for( let e of src ) + { + let r = onEach( e, e, c, src ); + _.assert( r === true || r === false ); + if( r === false ) + return [ e, e, c, false ]; + laste = e; + c += 1; + } + return [ laste, laste, src.size-1, true ]; +} + +// + +function _whileRight( src, onEach ) +{ + if( src.size === 0 ) + return [ undefined, undefined, -1, true ]; + var src2 = [ ... src ]; + for( let k = src2.length-1 ; k >= 0 ; k-- ) + { + var e = src2[ k ]; + let r = onEach( e, e, k, src ); + _.assert( r === true || r === false ); + if( r === false ) + return [ e, e, k, false ]; + } + var e = src2[ 0 ]; + return [ e, e, 0, true ]; +} + +// -- +// set extension +// -- + +let SetExtension = +{ + + // from, + toArray, + + // equaler + + _identicalShallow, + identicalShallow : _.props.identicalShallow, + identical : _.props.identical, + _equivalentShallow : _identicalShallow, + equivalentShallow : _.props.equivalentShallow, + equivalent : _.props.equivalent, + + // exporter + + _exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.props.exportStringDiagnosticShallow, + _exportStringCodeShallow : _exportStringDiagnosticShallow, + exportStringCodeShallow : _.props.exportStringCodeShallow, + exportString : _.props.exportString, + + // inspector + + _lengthOf, + lengthOf : _.props.lengthOf, /* qqq : cover */ + _hasKey, + hasKey : _.props.hasKey, /* qqq : cover */ + _hasCardinal, + hasCardinal : _.props.hasCardinal, /* qqq : cover */ + _keyWithCardinal, + keyWithCardinal : _.props.keyWithCardinal, /* qqq : cover */ + _cardinalWithKey, + cardinalWithKey : _.props.cardinalWithKey, /* qqq : cover */ + + // elementor + + _elementGet : _elementWithKey, + elementGet : _.props.elementGet, /* qqq : cover */ + _elementWithKey, + elementWithKey : _.props.elementWithKey, /* qqq : cover */ + _elementWithImplicit : _.props._elementWithImplicit, + elementWithImplicit : _.props.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal, + elementWithCardinal : _.props.elementWithCardinal, /* qqq : cover */ + + _elementSet : _elementWithKeySet, + elementSet : _.props.elementSet, /* qqq : cover */ + _elementWithKeySet, + elementWithKeySet : _.props.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet, + elementWithCardinalSet : _.props.elementWithCardinalSet, /* qqq : cover */ + + _elementDel : _elementWithKeyDel, + elementDel : _.props.elementDel, /* qqq : cover */ + _elementWithKeyDel, + elementWithKeyDel : _.props.elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel, + elementWithCardinalDel : _.props.elementWithCardinalDel, /* qqq : cover */ + _empty, + empty : _.props.empty, /* qqq : for junior : cover */ + + // iterator + + _each : _eachLeft, + each : _.props.each, /* qqq : cover */ + _eachLeft, + eachLeft : _.props.eachLeft, /* qqq : cover */ + _eachRight, + eachRight : _.props.eachRight, /* qqq : cover */ + + _while : _whileLeft, + while : _.props.while, /* qqq : cover */ + _whileLeft, + whileLeft : _.props.whileLeft, /* qqq : cover */ + _whileRight, + whileRight : _.props.whileRight, /* qqq : cover */ + + _aptLeft : _.props._aptLeft, + aptLeft : _.props.aptLeft, /* qqq : cover */ + first : _.props.first, + _aptRight : _.props._aptRight, /* qqq : cover */ + aptRight : _.props.aptRight, + last : _.props.last, /* qqq : cover */ + + _filterAct0 : _.props._filterAct0, + _filterAct : _.props._filterAct, + filterWithoutEscapeLeft : _.props.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.props.filterWithoutEscapeRight, + filterWithoutEscape : _.props.filterWithoutEscape, + filterWithEscapeLeft : _.props.filterWithEscapeLeft, + filterWithEscapeRight : _.props.filterWithEscapeRight, + filterWithEscape : _.props.filterWithEscape, + filter : _.props.filter, + + _mapAct0 : _.props._mapAct0, + _mapAct : _.props._mapAct, + mapWithoutEscapeLeft : _.props.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.props.mapWithoutEscapeRight, + mapWithoutEscape : _.props.mapWithoutEscape, + mapWithEscapeLeft : _.props.mapWithEscapeLeft, + mapWithEscapeRight : _.props.mapWithEscapeRight, + mapWithEscape : _.props.mapWithEscape, + map : _.props.map, + +} + +Object.assign( _.set, SetExtension ); + +// -- +// sets extension +// -- + +let SetsExtension = +{ + + // set + + // from : setsFrom, + toArrays : setsToArrays, + +} + +Object.assign( _.sets, SetsExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + setToArray : toArray, + setsToArrays, + +} + +Object.assign( _, ToolsExtension ); + +// + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Set.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Set_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Set_s */ })(); + +/* */ /* begin of file Str_s */ ( function Str_s() { function Str_s_naked() { ( function _l3_Str_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// exporter +// -- + +function _exportStringDiagnosticShallow( src, o ) +{ + return src; +} + +// + +function exportStringDiagnosticShallow( src, o ) +{ + let result; + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects 1 or 2 arguments' ); + _.assert( this.like( src ) ); + return this._exportStringDiagnosticShallow( ... arguments ); +} + +// + +function _exportStringCodeShallow( src, o ) +{ + return `'${src}'`; +} + +// + +function exportStringCodeShallow( src, o ) +{ + let result; + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects 1 or 2 arguments' ); + _.assert( this.like( src ) ); + return this._exportStringCodeShallow( ... arguments ); +} + +// -- +// equaler +// -- + +function _identicalShallow( src1, src2 ) +{ + return src1 === src2; +} + +// + +function identicalShallow( src1, src2, accuracy ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( !this.is( src1 ) ) + return false; + if( !this.is( src2 ) ) + return false; + return this._identicalShallow( ... arguments ); +} + +// + +// function _equivalentShallow( src1, src2 ) +// { +// let strIs1 = _.strIs( src1 ); +// let strIs2 = _.strIs( src2 ); +// +// // _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// // +// // if( !strIs1 && strIs2 ) +// // return this._equivalentShallow( src2, src1 ); +// +// // _.assert( _.regexpLike( src1 ), 'Expects string-like ( string or regexp )' ); +// // _.assert( _.regexpLike( src1 ), 'Expects string-like ( string or regexp )' ); +// +// if( strIs1 && strIs2 ) +// { +// /* qqq : for junior : bad | aaa : Fixed. */ +// if( src1 === src2 ) +// return true; +// return _.str.lines.strip( src1 ) === _.str.lines.strip( src2 ); +// } +// else +// { +// return false; +// // return _.regexpIdentical( src1, src2 ); +// } +// +// return false; +// } + +// +// +// function _equivalentShallow( src1, src2 ) +// { +// let strIs1 = _.strIs( src1 ); +// let strIs2 = _.strIs( src2 ); +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// +// if( !strIs1 && strIs2 ) +// return this._equivalentShallow( src2, src1 ); +// +// _.assert( _.regexpLike( src1 ), 'Expects string-like ( string or regexp )' ); +// _.assert( _.regexpLike( src1 ), 'Expects string-like ( string or regexp )' ); +// +// if( strIs1 && strIs2 ) +// { +// /* qqq : for junior : bad | aaa : Fixed. */ +// if( src1 === src2 ) +// return true; +// +// return _.str.lines.strip( src1 ) === _.str.lines.strip( src2 ); +// +// } +// else if( strIs1 ) +// { +// _.assert( !!src2.exec ); +// let matched = src2.exec( src1 ); +// if( !matched ) +// return false; +// if( matched[ 0 ].length !== src1.length ) +// return false; +// return true; +// } +// else +// { +// return _.regexpIdentical( src1, src2 ); +// } +// +// return false; +// } + +// + +function _equivalentShallow( src1, src2 ) +{ + let strIs1 = _.strIs( src1 ); + let strIs2 = _.strIs( src2 ); + + if( !strIs1 && strIs2 ) + return this._equivalentShallow( src2, src1 ); + + if( strIs1 && strIs2 ) + { + if( src1 === src2 ) + return true; + return _.str.lines.strip( src1 ) === _.str.lines.strip( src2 ); + } + else if( strIs1 ) + { + _.assert( !!src2.exec ); + let matched = src2.exec( src1 ); + if( !matched ) + return false; + if( matched[ 0 ].length !== src1.length ) + return false; + return true; + } + else + { + return _.regexpIdentical( src1, src2 ); + } + + return false; +} + +// + +function equivalentShallow( src1, src2, accuracy ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + if( !_.regexp.like( src1 ) ) + return false; + if( !_.regexp.like( src2 ) ) + return false; + return _.str._equivalentShallow( ... arguments ); +} + +// +// // +// +// function strsEquivalent( src1, src2 ) +// { +// +// _.assert( _.strIs( src1 ) || _.regexpIs( src1 ) || _.longIs( src1 ), 'Expects string/regexp or array of strings/regexps {-src1-}' ); +// _.assert( _.strIs( src2 ) || _.regexpIs( src2 ) || _.longIs( src2 ), 'Expects string/regexp or array of strings/regexps {-src2-}' ); +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// +// let isLong1 = _.longIs( src1 ); +// let isLong2 = _.longIs( src2 ); +// +// if( isLong1 && isLong2 ) +// { +// let result = []; +// _.assert( src1.length === src2.length ); +// for( let i = 0, len = src1.length ; i < len; i++ ) +// { +// result[ i ] = _.str.equivalent( src1[ i ], src2[ i ] ); +// } +// return result; +// } +// else if( !isLong1 && isLong2 ) +// { +// let result = []; +// for( let i = 0, len = src2.length ; i < len; i++ ) +// { +// result[ i ] = _.str.equivalent( src1, src2[ i ] ); +// } +// return result; +// } +// else if( isLong1 && !isLong2 ) +// { +// let result = []; +// for( let i = 0, len = src1.length ; i < len; i++ ) +// { +// result[ i ] = _.str.equivalent( src1[ i ], src2 ); +// } +// return result; +// } +// else +// { +// return _.str.equivalent( src1, src2 ); +// } +// +// } + +// -- +// +// -- + +/** + * Prepends string( begin ) to the source( src ) if prefix( begin ) is not match with first chars of string( src ), + * otherwise returns original string. + * @param { String } src - Source string to parse. + * @param { String } begin - String to prepend. + * + * @example + * _.strPrependOnce( 'test', 'test' ); + * // returns 'test' + * + * @example + * _.strPrependOnce( 'abc', 'x' ); + * // returns 'xabc' + * + * @returns { String } Returns result of prepending string( begin ) to source( src ) or original string. + * @function prependOnce + * @namespace Tools + */ + +function prependOnce( src, begin ) +{ + _.assert( _.strIs( src ) && _.strIs( begin ), 'Expects {-src-} and {-begin-} as strings' ); + if( src.lastIndexOf( begin, 0 ) === 0 ) + return src; + else + return begin + src; +} + +// + +/** + * Appends string( end ) to the source( src ) if postfix( end ) is not match with last chars of string( src ), + * otherwise returns original string. + * @param {string} src - Source string to parse. + * @param {string} end - String to append. + * + * @example + * _.strAppendOnce( 'test', 'test' ); + * // returns 'test' + * + * @example + * _.strAppendOnce( 'abc', 'x' ); + * // returns 'abcx' + * + * @returns {string} Returns result of appending string( end ) to source( src ) or original string. + * @function appendOnce + * @namespace Tools + */ + +function appendOnce( src, end ) +{ + _.assert( _.strIs( src ) && _.strIs( end ), 'Expects {-src-} and {-end-} as strings' ); + if( src.indexOf( end, src.length - end.length ) === -1 ) + return src + end; + else + return src; +} + +// -- +// str extension +// -- + +let StrExtension = +{ + + // exporter + + _exportStringDiagnosticShallow, + exportStringDiagnosticShallow, + _exportStringCodeShallow, + exportStringCodeShallow, + exportString : exportStringDiagnosticShallow, + + // equaler + + _identicalShallow, + identicalShallow, + identical : identicalShallow, + _equivalentShallow, + equivalentShallow, + equivalent : equivalentShallow, + + prependOnce, + appendOnce, + +} + +Object.assign( _.str, StrExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + /* qqq : for Rahul : ask */ + + strPrependOnce : prependOnce, + strAppendOnce : appendOnce, + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Str.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Str_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Str_s */ })(); + +/* */ /* begin of file Stringer_s */ ( function Stringer_s() { function Stringer_s_naked() { ( function _l3_Stringer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.stringer = _.stringer || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// stringer extension +// -- + +let StringerExtension = +{ +} + +Object.assign( _.stringer, StringerExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Stringer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Stringer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Stringer_s */ })(); + +/* */ /* begin of file Time_s */ ( function Time_s() { function Time_s_naked() { ( function _l3_Time_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +function _sleep( delay ) +{ + _.assert( _.intIs( delay ) && delay >= 0, 'Specify valid value {-delay-}.' ); + let now = _.time.now(); + while( ( _.time.now() - now ) < delay ) + { + if( Math.random() === 0 ); + } +} + +// + +/** + * The routine sleep() suspends program execution on time delay {-delay-}. + * + * @example + * let result = []; + * let periodic = _.time.periodic( 100, () => result.length < 10 ? result.push( 1 ) : undefined ); + * let before = _.time.now(); + * _.time.sleep( 500 ); + * console.log( result.length <= 1 ); + * // log : true + * let after = _.time.now(); + * let delta = after - before; + * console.log( delta <= 550 ); + * // log : true + * + * @param { Number } delay - The delay to suspend program. + * @returns { Undefined } - Returns not a value, suspends program. + * @function sleep + * @throws { Error } If arguments.length is less then 1 or great then 2. + * @throws { Error } If {-delay-} is not a Number. + * @throws { Error } If {-delay-} is less then zero. + * @throws { Error } If {-delay-} has not finite value. + * @namespace wTools.time + * @extends Tools + */ + +function sleep( delay ) +{ + _.assert( arguments.length === 1 ); + _.time._sleep.apply( this, arguments ); +} + +// + +/** + * The routine from() returns the time since 01.01.1970 in ms. + * + * @example + * let date = new Date(); + * console.log( _.time.from( date ) ); + * // log : 1603174830154 + * + * @param { Number|Date|String } time - The time to convert. + * @returns { Number } - Returns time since 01.01.1970. + * @function from + * @throws { Error } If arguments.length is not equal to 1. + * @throws { Error } If {-time-} neither is a Number, nor a Date, nor a valid time String. + * @namespace wTools.time + * @extends Tools + */ + +function from( time ) +{ + + _.assert( arguments.length === 1 ); + + if( _.number.is( time ) ) + { + return time; + } + if( _.date.is( time ) ) + { + return time.getTime(); + } + if( _.strIs( time ) ) + { + time = Date.parse( time ); + if( !isNaN( time ) ) + return time; + else + _.assert( 0, 'Wrong time format' ); + } + _.assert( 0, 'Not clear how to coerce to time', _.entity.strType( time ) ); +} + +// -- +// extension +// -- + +let TimeExtension = +{ + + _sleep, + sleep, + + from, + +} + +// + +Object.assign( _.time, TimeExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Time.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Time_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Time_s */ })(); + +/* */ /* begin of file Unroll_s */ ( function Unroll_s() { function Unroll_s_naked() { ( function _l3_Unroll_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( !!_.long._elementWithKey, 'Expects routine array._elementWithKey' ); + +// -- +// exporter +// -- + +function _exportStringDiagnosticShallow( src ) +{ + return `{- ${_.entity.strType( src )}.unroll with ${this._lengthOf( src )} elements -}`; +} + +// -- +// declaration +// -- + +let unrollSymbol = Symbol.for( 'unroll' ); + +// -- +// declaration +// -- + +let ToolsExtension = +{ +} + +// + +Object.assign( _, ToolsExtension ); + +// + +/* qqq : for junior : make replacements */ + +let UnrollExtension = +{ + + // equaler + + _identicalShallow : _.long._identicalShallow, + identicalShallow : _.long.identicalShallow, + identical : _.long.identical, + _equivalentShallow : _.long._equivalentShallow, + equivalentShallow : _.long.equivalentShallow, + equivalent : _.long.equivalent, + + // exporter + + _exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.long.exportStringDiagnosticShallow, + _exportStringCodeShallow : _exportStringDiagnosticShallow, + exportStringCodeShallow : _.long.exportStringCodeShallow, + exportString : _.long.exportString, + + // container interface + + _lengthOf : _.long._lengthOf, + lengthOf : _.long.lengthOf, /* qqq : cover */ + + _hasKey : _.long._hasKey, + hasKey : _.long._hasKey, /* qqq : cover */ + _hasCardinal : _.long._hasKey, + hasCardinal : _.long._hasKey, /* qqq : cover */ + _keyWithCardinal : _.long._hasKey, + keyWithCardinal : _.long._hasKey, /* qqq : cover */ + _cardinalWithKey : _.long._cardinalWithKey, + cardinalWithKey : _.long.cardinalWithKey, /* qqq : cover */ + + _elementGet : _.long._elementWithKey, + elementGet : _.long.elementWithKey, /* qqq : cover */ + _elementWithKey : _.long._elementWithKey, + elementWithKey : _.long.elementWithKey, /* qqq : cover */ + _elementWithImplicit : _.long._elementWithImplicit, + elementWithImplicit : _.long.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal : _.long._elementWithCardinal, + elementWithCardinal : _.long.elementWithCardinal, /* qqq : cover */ + + _elementSet : _.long._elementSet, + elementSet : _.long.elementSet, /* qqq : cover */ + _elementWithKeySet : _.long._elementWithKeySet, + elementWithKeySet : _.long.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet : _.long._elementWithCardinalSet, + elementWithCardinalSet : _.long.elementWithCardinalSet, /* qqq : cover */ + + _elementAppend : _.array._elementAppend, + elementAppend : _.array.elementAppend, /* qqq : cover */ + _elementPrepend : _.array._elementPrepend, + elementPrepend : _.array.elementPrepend, /* qqq : cover */ + + _elementDel : _.array._elementDel, + elementDel : _.array.elementDel, /* qqq : cover */ + _elementWithKeyDel : _.array._elementWithKeyDel, + elementWithKeyDel : _.array.elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel : _.array._elementWithCardinalDel, + elementWithCardinalDel : _.array.elementWithCardinalDel, /* qqq : cover */ + _empty : _.array._empty, + empty : _.array.empty, /* qqq : for junior : cover */ + + _each : _.long._each, + each : _.long.each, /* qqq : cover */ + _eachLeft : _.long._eachLeft, + eachLeft : _.long.eachLeft, /* qqq : cover */ + _eachRight : _.long._eachRight, + eachRight : _.long.eachRight, /* qqq : cover */ + + _while : _.long._while, + while : _.long.while, /* qqq : cover */ + _whileLeft : _.long._whileLeft, + whileLeft : _.long.whileLeft, /* qqq : cover */ + _whileRight : _.long._whileRight, + whileRight : _.long.whileRight, /* qqq : cover */ + + _aptLeft : _.long._aptLeft, + aptLeft : _.long.aptLeft, /* qqq : cover */ + first : _.long.first, + _aptRight : _.long._aptRight, /* qqq : cover */ + aptRight : _.long.aptRight, + last : _.long.last, /* qqq : cover */ + + _filterAct : _.long._filterAct, + filterWithoutEscapeLeft : _.long.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.long.filterWithoutEscapeRight, + filterWithoutEscape : _.long.filterWithoutEscape, + filterWithEscapeLeft : _.long.filterWithEscapeLeft, + filterWithEscapeRight : _.long.filterWithEscapeRight, + filterWithEscape : _.long.filterWithEscape, + filter : _.long.filter, + + _mapAct : _.long._mapAct, + mapWithoutEscapeLeft : _.long.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.long.mapWithoutEscapeRight, + mapWithoutEscape : _.long.mapWithoutEscape, + mapWithEscapeLeft : _.long.mapWithEscapeLeft, + mapWithEscapeRight : _.long.mapWithEscapeRight, + mapWithEscape : _.long.mapWithEscape, + map : _.long.map, + +} + +// + +Object.assign( _.unroll, UnrollExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Unroll.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Unroll_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Unroll_s */ })(); + +/* */ /* begin of file Vector_s */ ( function Vector_s() { function Vector_s_naked() { ( function _l3_Vector_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( !!_.countable._elementWithKey, 'Expects routine countable._elementWithKey' ); + +// -- +// dichotomy +// -- + +function adapterIs( src ) +{ + return Object.prototype.toString.call( src ) === '[object VectorAdapter]'; +} + +// + +function constructorIsVectorAdapter( src ) +{ + if( !src ) + return false; + return '_vectorBuffer' in src.prototype; +} + +// -- +// extension +// -- + +var ToolsExtension = +{ + vectorAdapterIs : adapterIs, + vadIs : adapterIs, + constructorIsVectorAdapter, + constructorIsVad : constructorIsVectorAdapter, +} + +Object.assign( _, ToolsExtension ); + +// + +var VectorExtension = +{ + + // dichotomy + + adapterIs, + constructorIsVectorAdapter, + + // equaler + + /* qqq : implement more optimal own version of this routines */ + _identicalShallow : _.countable.identicalShallow, + identicalShallow : _.countable.identicalShallow, + identical : _.countable.identical, + _equivalentShallow : _.countable.identicalShallow, + equivalentShallow : _.countable.equivalentShallow, + equivalent : _.countable.equivalent, + + // exporter + + /* qqq : implement more optimal own version of this routines */ + _exportStringDiagnosticShallow : _.countable._exportStringDiagnosticShallow, + exportStringDiagnosticShallow : _.countable.exportStringDiagnosticShallow, + _exportStringCodeShallow : _.countable._exportStringCodeShallow, + exportStringCodeShallow : _.countable.exportStringCodeShallow, + exportString : _.countable.exportString, + + // container interface + + _lengthOf : _.countable._lengthOf, + lengthOf : _.countable.lengthOf, /* qqq : cover */ + + _hasKey : _.countable._hasKey, + hasKey : _.countable._hasKey, /* qqq : cover */ + _hasCardinal : _.countable._hasKey, + hasCardinal : _.countable._hasKey, /* qqq : cover */ + _keyWithCardinal : _.countable._hasKey, + keyWithCardinal : _.countable._hasKey, /* qqq : cover */ + _cardinalWithKey : _.countable._cardinalWithKey, + cardinalWithKey : _.countable.cardinalWithKey, /* qqq : cover */ + + _elementGet : _.countable._elementWithKey, + elementGet : _.countable.elementWithKey, /* qqq : cover */ + _elementWithKey : _.countable._elementWithKey, + elementWithKey : _.countable.elementWithKey, /* qqq : cover */ + _elementWithImplicit : _.countable._elementWithImplicit, + elementWithImplicit : _.countable.elementWithImplicit, /* qqq : cover */ + _elementWithCardinal : _.countable._elementWithCardinal, + elementWithCardinal : _.countable.elementWithCardinal, /* qqq : cover */ + + _elementSet : _.countable._elementSet, + elementSet : _.countable.elementSet, /* qqq : cover */ + _elementWithKeySet : _.countable._elementWithKeySet, + elementWithKeySet : _.countable.elementWithKeySet, /* qqq : cover */ + _elementWithCardinalSet : _.countable._elementWithCardinalSet, + elementWithCardinalSet : _.countable.elementWithCardinalSet, /* qqq : cover */ + + _elementDel : _.countable._elementDel, + elementDel : _.countable.elementDel, /* qqq : cover */ + _elementWithKeyDel : _.countable._elementWithKeyDel, + elementWithKeyDel : _.countable.elementWithKeyDel, /* qqq : cover */ + _elementWithCardinalDel : _.countable._elementWithCardinalDel, + elementWithCardinalDel : _.countable.elementWithCardinalDel, /* qqq : cover */ + _empty : _.countable._empty, + empty : _.countable.empty, /* qqq : cover */ + + _elementAppend : _.countable._elementAppend, + elementAppend : _.countable.elementAppend, /* qqq : cover */ + _elementPrepend : _.countable._elementPrepend, + elementPrepend : _.countable.elementPrepend, /* qqq : cover */ + + _each : _.countable._each, + each : _.countable.each, /* qqq : cover */ + _eachLeft : _.countable._eachLeft, + eachLeft : _.countable.eachLeft, /* qqq : cover */ + _eachRight : _.countable._eachRight, + eachRight : _.countable.eachRight, /* qqq : cover */ + + _while : _.countable._while, + while : _.countable.while, /* qqq : cover */ + _whileLeft : _.countable._whileLeft, + whileLeft : _.countable.whileLeft, /* qqq : cover */ + _whileRight : _.countable._whileRight, + whileRight : _.countable.whileRight, /* qqq : cover */ + + _aptLeft : _.countable._aptLeft, + aptLeft : _.countable.aptLeft, /* qqq : cover */ + first : _.countable.first, + _aptRight : _.countable._aptRight, /* qqq : cover */ + aptRight : _.countable.aptRight, + last : _.countable.last, /* qqq : cover */ + + _filterAct : _.countable._filterAct, + filterWithoutEscapeLeft : _.countable.filterWithoutEscapeLeft, + filterWithoutEscapeRight : _.countable.filterWithoutEscapeRight, + filterWithoutEscape : _.countable.filterWithoutEscape, + filterWithEscapeLeft : _.countable.filterWithEscapeLeft, + filterWithEscapeRight : _.countable.filterWithEscapeRight, + filterWithEscape : _.countable.filterWithEscape, + filter : _.countable.filter, + + _mapAct : _.countable._mapAct, + mapWithoutEscapeLeft : _.countable.mapWithoutEscapeLeft, + mapWithoutEscapeRight : _.countable.mapWithoutEscapeRight, + mapWithoutEscape : _.countable.mapWithoutEscape, + mapWithEscapeLeft : _.countable.mapWithEscapeLeft, + mapWithEscapeRight : _.countable.mapWithEscapeRight, + mapWithEscape : _.countable.mapWithEscape, + map : _.countable.map, + + // _filterAct0 : _.countable._filterAct0, + // _filterAct : _.countable._filterAct, + // filterWithoutEscapeLeft : _.countable.filterWithoutEscapeLeft, + // filterWithoutEscapeRight : _.countable.filterWithoutEscapeRight, + // filterWithoutEscape : _.countable.filterWithoutEscape, + // filterWithEscapeLeft : _.countable.filterWithEscapeLeft, + // filterWithEscapeRight : _.countable.filterWithEscapeRight, + // filterWithEscape : _.countable.filterWithEscape, + // filter : _.countable.filter, + // + // _mapAct0 : _.countable._mapAct0, + // _mapAct : _.countable._mapAct, + // mapWithoutEscapeLeft : _.countable.mapWithoutEscapeLeft, + // mapWithoutEscapeRight : _.countable.mapWithoutEscapeRight, + // mapWithoutEscape : _.countable.mapWithoutEscape, + // mapWithEscapeLeft : _.countable.mapWithEscapeLeft, + // mapWithEscapeRight : _.countable.mapWithEscapeRight, + // mapWithEscape : _.countable.mapWithEscape, + // map : _.countable.map, + +} + +Object.assign( _.vector, VectorExtension ); + +// + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/Vector.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Vector_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Vector_s */ })(); + +/* */ /* begin of file zErr_s */ ( function zErr_s() { function zErr_s_naked() { ( function _l3_Err_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +function _handleUncaught2( o ) +{ + const __ = _global_.globals && _globals_.testing.wTools; + const process0 = processNamespaceGet(); + + optionsRefine(); + + /* xxx qqq : resolve issue in browser + if file has syntax error then unachught error should not ( probably ) be throwen + because browser thows uncontrolled information about syntax error after that + avoid duplication of errors in log + */ + + o.err = errRefine( o.err ); + + processUncaughtErrorEvent(); + + if( _.error.isAttended( o.err ) ) + return; + + consoleUnbar(); + + console.error( o.prefix ); + + errLogFields(); + errLog(); + + console.error( o.postfix ); + + processExit(); + + /* */ + + function optionsRefine() + { + + if( !o.origination ) + o.origination = 'uncaught error'; + + // for( let k in o ) + // if( _handleUncaught2.defaults[ k ] !== undefined ) + // { + // console.error( `Routine::_handleUncaught2() does not expect option::${k}` ); + // } + + o.prefix = `--------------- ${o.origination} --------------->\n`; + o.postfix = `--------------- ${o.origination} ---------------<\n`; + o.logger = _global.logger || _global.console; + + } + + /* */ + + function consoleUnbar() + { + let Logger = loggerClassGet(); + try + { + if( Logger && Logger.ConsoleBar && Logger.ConsoleIsBarred( console ) ) + Logger.ConsoleBar({ on : 0 }); + } + catch( err2 ) + { + debugger; + console.error( err2 ); + } + } + + /* */ + + function errLog() + { + try + { + if( _.error && _.error._log ) + _.error._log( o.err, o.logger ); + else + console.error( o.err ); + } + catch( err2 ) + { + debugger; + console.error( err2 ); + console.error( o.err ); + } + } + + /* */ + + function errLogFields() + { + if( !o.err.originalMessage && _.object.like && _.object.like( o.err ) ) + try + { + let props = Object.create( null ); + for( let k in o.err ) + props[ k ] = o.err[ k ]; + // let serr = _.entity.exportString && _.props ? _.entity.exportString.fields( o.err, { errorAsMap : 1 } ) : o.err; + o.logger.error( _.entity.exportString( props ) ); + debugger; + } + catch( err2 ) + { + debugger; + console.error( err2 ); + } + } + + /* */ + + function errRefine( err ) + { + try + { + return _.error.process( err ); + } + catch( err2 ) + { + console.error( err2 ); + return err; + } + } + + /* */ + + function processNamespaceGet() + { + let result; + if( !result && _.process && _.process.exitReason ) + result = _.process; + if( !result && _realGlobal_ && _realGlobal_.wTools && _realGlobal_.wTools.process && _realGlobal_.wTools.process.exitReason ) + result = _realGlobal_.wTools.process; + if + ( + !result + && _realGlobal_._globals_.testing + && __ + && __.process + && __.process.exitReason + ) + result = __.process; + if( !result ) + result = _.process; + return result; + } + + /* */ + + function loggerClassGet() + { + let result; + if( !result && _.Logger && _.Logger.ConsoleBar ) + result = _.Logger; + if( !result && _realGlobal_ && _realGlobal_.wTools && _realGlobal_.wTools.Logger && _realGlobal_.wTools.Logger.ConsoleBar ) + result = _realGlobal_.wTools.Logger; + if + ( + !result + && __ + && __.Logger + && __.Logger.ConsoleBar + ) + result = __.Logger; + return result; + } + + /* */ + + function processUncaughtErrorEvent() + { + try + { + // if( process0.eventGive ) /* xxx : cover in starter not catching uncaught error */ + if( process0 && process0.eventGive ) + // process0.eventGive({ event : 'uncaughtError', args : [ o ] }); + /* xxx : move to namespace app? */ + process0.eventGive({ event : 'uncaughtError', origination : o.origination, err : o.err }); + for( let g in _realGlobal_._globals_ ) + { + const _global = _realGlobal_._globals_[ g ]; + if( _global.wTools && _global.wTools.process && _global.wTools.process.eventGive ) + if( _global.wTools.process !== process0 ) + _global.wTools.process.eventGive({ event : 'uncaughtError', origination : o.origination, err : o.err }); + // _global.wTools.process.eventGive({ event : 'uncaughtError', args : [ o ] }); + } + } + catch( err2 ) + { + debugger; + console.log( err2 ); + exitError( err2, false ); + } + } + + /* */ + + function exitError( err, rewriting ) + { + let set = false; + debugger; + if( process0 && process0.exit ) + try + { + process0.exitCode( -1 ); + if( !process0.exitReason() ) + process0.exitReason( err ); + set = true; + } + catch( err2 ) + { + debugger; + console.log( err2 ); + } + if( !set ) + try + { + if( _global.process ) + { + if( !process.exitCode ) + process.exitCode = -1; + set = true; + } + } + catch( err2 ) + { + } + } + + /* */ + + function processExit() + { + exitError( o.err, true ); + if( process0 && process0.exit ) + try + { + process0.exit(); + } + catch( err2 ) + { + debugger; + console.log( err2 ); + exitError( o.err, false ); + } + try + { + if( _global.process ) + process.exit(); + } + catch( err2 ) + { + } + } + +} + +_handleUncaught2.defaults = +{ + err : null, + origination : null, +} + +// + +function _handleUncaughtAsync( err ) +{ + + if( _.error.isAttended( err ) ) + return err; + + if( !err ) + debugger; + _.error.wary( err, 1 ); + + if( _.error.isSuspended( err ) ) + return err; + + let timer = _.time._finally( _.error.uncaughtDelayTime, function uncaught() + { + + if( _.error.isAttended( err ) ) + return; + + if( _.error.isSuspended( err ) ) + return; + + if( !err ) + debugger; + + _.error._handleUncaught2({ err, origination : 'uncaught asynchronous error' }); + + }); + + return err; +} + +// + +function _setupUncaughtErrorHandler9() +{ + + if( !_realGlobal_._setupUncaughtErrorHandlerDone ) + { + debugger; + throw Error( 'setup0 should be called first' ); + } + + if( _realGlobal_._setupUncaughtErrorHandlerDone > 1 ) + return; + + _realGlobal_._setupUncaughtErrorHandlerDone = 2; + + /* */ + + if( _global.process && _.routine.is( _global.process.on ) ) + { + _.error._handleUncaughtHead = _errHeadNode; + } + else if( Object.hasOwnProperty.call( _global, 'onerror' ) ) + { + _.error._handleUncaughtHead = _errHeadBrowser; + } + + /* */ + + function _errHeadBrowser( args ) + { + let [ message, sourcePath, lineno, colno, error ] = args; + let err = error || message; + + if( _._err ) + err = _._err + ({ + args : [ error || message ], + level : 1, + fallBackStack : 'at handleError @ ' + sourcePath + ':' + lineno, + throwLocation : + { + filePath : sourcePath, + line : lineno, + col : colno, + }, + }); + + return [ { err, args } ]; + } + + /* */ + + function _errHeadNode( args ) + { + return [ { err : args[ 0 ], args } ]; + } + + /* */ + +} + +// + +/* qqq : for junior : for Rahul : implement performance test */ +/* xxx : optimize */ +function error_functor( name, onErrorMake ) +{ + + _.assert( _._err.defaults[ name ] === undefined ); + + if( _.strIs( onErrorMake ) || _.arrayIs( onErrorMake ) ) + { + let prepend = onErrorMake; + onErrorMake = function onErrorMake() + { + debugger; + let args = _.arrayAppendArrays( [], [ prepend, arguments ] ); + return args; + } + } + else if( !onErrorMake ) + { + onErrorMake = function onErrorMake() + { + return arguments; + } + } + + let Error = + { + [ name ] : function() + { + if( ( this instanceof ErrorConstructor ) ) + { + + let err1 = this; + let args1 = onErrorMake.apply( err1, arguments ); + _.assert( _.argumentsArray.like( args1 ) ); + let args2 = args1; + + if( !Array.prototype.includes.call( args2, err1 ) ) + args2 = [ err1, ... args1 ]; + let err2 = _._err({ args : args2, level : 2, concealed : { [ name ] : true } }); + _.assert( err1 === err2 ); + _.assert( err2 instanceof _global.Error ); + _.assert( err2 instanceof ErrorConstructor ); + return err2; + + } + else + { + + if( arguments.length === 1 && arguments[ 0 ] && arguments[ 0 ] instanceof ErrorConstructor ) + return arguments[ 0 ]; + + let err1; + for( let i = 0 ; i < arguments.length ; i++ ) + if( arguments[ i ] && arguments[ i ] instanceof ErrorConstructor ) + { + err1 = arguments[ i ]; + break; + } + + if( err1 ) + return ErrorConstructor.apply( err1, arguments ); + return new ErrorConstructor( ... arguments ); + } + } + } + + let ErrorConstructor = Error[ name ]; + + _.assert + ( + ErrorConstructor.name === name, + 'Looks like your interpreter does not support dynamice naming of functions. Please use ES2015 or later interpreter.' + ); + + ErrorConstructor.prototype = Object.create( _global.Error.prototype ); + ErrorConstructor.prototype.constructor = ErrorConstructor; + // ErrorConstructor.constructor = ErrorConstructor; + // ErrorConstructor.constructor = Object.create( _global.Error.constructor ); + Object.setPrototypeOf( ErrorConstructor, _global.Error ); + + return ErrorConstructor; +} + +// -- +// extension +// -- + +let Extension = +{ + + _handleUncaught2, + _handleUncaughtAsync, + _setupUncaughtErrorHandler9, + + error_functor, + + uncaughtDelayTime : 100, + +} + +// + +/* _.props.extend */Object.assign( _.error, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3/zErr.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, zErr_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file zErr_s */ })(); + +/* */ /* begin of file _1Seeker_s */ ( function _1Seeker_s() { function _1Seeker_s_naked() { ( function _l5_1Seeker_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +function head( routine, args ) +{ + _.assert( arguments.length === 2 ); + _.assert( !!routine.defaults.Seeker ); + let o = routine.defaults.Seeker.optionsFromArguments( args ); + o.Seeker = o.Seeker || routine.defaults; + _.map.assertHasOnly( o, routine.defaults ); + _.assert + ( + _.props.keys( routine.defaults ).length === _.props.keys( o.Seeker ).length, + () => `${_.props.keys( routine.defaults ).length} <> ${_.props.keys( o.Seeker ).length}` + ); + let it = o.Seeker.optionsToIteration( null, o ); + return it; +} + +// + +function optionsFromArguments( args ) +{ + let o; + + if( args.length === 1 ) + { + o = args[ 0 ]; + } + else if( args.length === 2 ) + { + o = { src : args[ 0 ], onUp : args[ 1 ] }; + } + else if( args.length === 3 ) + { + o = { src : args[ 0 ], onUp : args[ 1 ], onDown : args[ 2 ] }; + } + else _.assert( 0, 'look expects single options-map, 2 or 3 arguments' ); + + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + _.assert( arguments.length === 1 ); + _.assert( _.aux.is( o ) ); + + return o; +} + +// + +function optionsToIteration( iterator, o ) +{ + _.assert( o.it === undefined ); + _.assert( _.mapIs( o ) ); + _.assert( !_.props.ownEnumerable( o, 'constructor' ) ); + _.assert( arguments.length === 2 ); + if( iterator === null ) + iterator = o.Seeker.iteratorRetype( o ); + else + Object.assign( iterator, o ); + o.Seeker.iteratorInit( iterator ); + let it = iterator.iteratorIterationMake(); + _.assert( it.Seeker.iterationProper( it ) ); + return it; +} + +// + +function iteratorProper( it ) +{ + if( !it ) + return false; + if( !it.Seeker ) + return false; + if( it.iterator !== it ) + return false; + if( it.constructor !== this.constructor ) + return false; + return true; +} + +// + +function iteratorRetype( iterator ) +{ + Object.setPrototypeOf( iterator, iterator.Seeker ); + iterator.iterator = iterator; + return iterator; +} + +// + +function iteratorInit( iterator ) +{ + let seeker = this; + seeker.iteratorInitBegin( iterator ); + seeker.iteratorInitEnd( iterator ); +} + +// + +function iteratorInitBegin( iterator ) +{ + iterator.iterator = iterator; + return iterator; +} + +// + +const _iteratorInitExcluding = new Set([ 'Seeker', 'iterationPrototype', 'firstIterationPrototype', 'iterator' ]); +function iteratorInitEnd( iterator ) +{ + + iterator.iterationPrototype = Object.create( iterator ); + iterator.firstIterationPrototype = Object.create( iterator.iterationPrototype ); + Object.assign( iterator.iterationPrototype, iterator.Seeker.Iteration ); + + for( const [ key, val ] of Object.entries( iterator ) ) + { + if( _iteratorInitExcluding.has( key ) ) + continue; + + if( !_.props.own( iterator.iterationPrototype, key ) ) + continue; + + if( _.props.has( iterator.Iteration, key ) ) + { + if( iterator.firstIterationPrototype[ key ] !== val ) + { + iterator.firstIterationPrototype[ key ] = val; + } + } + else + { + if( iterator.iterationPrototype[ key ] !== val ) + { + iterator.iterationPrototype[ key ] = val; + } + } + + } + + Object.preventExtensions( iterator.iterationPrototype ); + return iterator; +} + +// + +function iteratorIterationMake() +{ + let it = this; + let newIt = Object.create( it.firstIterationPrototype ); + return newIt; +} + +// + +function iterationMake() +{ + let it = this; + let newIt = Object.create( it.iterationPrototype ); + + for( let k in it.Seeker.IterationPreserve ) + newIt[ k ] = it[ k ]; + + newIt.down = it; /* xxx */ + + return newIt; +} + +// + +function iterationProper( it ) +{ + if( !it ) + return false; + if( !it.Seeker ) + return false; + if( !it.iterator ) + return false; + if( it.iterator === it ) + return false; + if( it.constructor !== this.constructor ) + return false; + return true; +} + +// -- +// +// -- + +/** + * @function is + * @class Tools.Seeker + */ + +function is( src ) +{ + if( !src ) + return false; + if( !src.Seeker ) + return false; + return _.prototype.isPrototypeFor( src, src.Seeker ); +} + +// + +/** + * @function iteratorIs + * @class Tools.Seeker + */ + +function iteratorIs( it ) +{ + if( !it ) + return false; + if( !it.Seeker ) + return false; + if( it.iterator !== it ) + return false; + return true; +} + +// + +/** + * @function iterationIs + * @class Tools.Seeker + */ + +function iterationIs( it ) +{ + if( !it ) + return false; + if( !it.Seeker ) + return false; + if( !it.iterator ) + return false; + if( it.iterator === it ) + return false; + return true; +} + +// + +function classDefine( o ) +{ + + _.routine.options( classDefine, o ); + + if( o.parent === null ) + o.parent = this.Seeker; + if( o.name === null ) + o.name = 'CustomSeeker' + + _.assert( _.object.isBasic( o.parent ), `Parent should be object` ); + + let seeker = _.props.extend( null, o.parent ); + + if( !o.seeker || !o.seeker.constructor || o.seeker.constructor === Object ) + { + let CustomSeeker = (function() + { + return ({ + [ o.name ] : function(){}, + })[ o.name ]; + })(); + seeker.constructor = CustomSeeker; + _.assert( seeker.constructor.name === o.name ); + } + + if( o.prime ) + _.props.extend( seeker, o.prime ); + if( o.seeker ) + _.props.extend( seeker, o.seeker ); + if( o.iterator ) + _.props.extend( seeker, o.iterator ); + if( o.iterationPreserve ) + o.iteration = _.props.supplement( o.iteration || Object.create( null ), o.iterationPreserve ); + + seeker.Seeker = seeker; + seeker.OriginalSeeker = seeker; + seeker.Prime = Object.create( seeker.Prime || null ); + if( o.prime ) + _.props.extend( seeker.Prime, o.prime ); + Object.preventExtensions( seeker.Prime ); + + if( o.exec || seeker.exec ) + seeker.exec = exec_functor( o.exec || seeker.exec ); + if( o.execIt || seeker.execIt ) + seeker.execIt = exec_functor( o.execIt || seeker.execIt ); + + let iterator = seeker.Iterator = Object.assign( Object.create( null ), seeker.Iterator ); + if( o.iterator ) + _.props.extend( iterator, o.iterator ); + + seeker.Iteration = Object.assign( Object.create( null ), seeker.Iteration ); + let iterationPreserve = seeker.IterationPreserve = Object.assign( Object.create( null ), seeker.IterationPreserve ); + if( o.iterationPreserve ) + { + _.props.extend( iterationPreserve, o.iterationPreserve ); + } + if( o.iteration ) + _.props.extend( seeker.Iteration, o.iteration ); + + Object.freeze( seeker.Iterator ); + Object.freeze( seeker.Iteration ); + Object.freeze( seeker.IterationPreserve ); + + validate(); + + return seeker; + + /* - */ + + function exec_functor( original ) + { + _.assert( _.routineIs( original.head ) ); + _.assert( _.routineIs( original.body ) ); + if( !original.body.defaults ) + original.body.defaults = seeker; + let exec = _.routine._amend + ({ + dst : null, + srcs : [ original, { defaults : seeker } ], + strategy : 'replacing', + amending : 'extending', + }); + _.assert( exec.defaults === seeker ); + _.assert( exec.body.defaults === seeker ); + return exec; + } + + /* - */ + + function validate() + { + if( !Config.debug ) + return; + + /* qqq : add explanation for each assert */ + _.assert( seeker.Prime.Seeker === undefined ); + _.assert( !_.props.has( seeker.Iteration, 'src' ) || seeker.Iteration.src === undefined ); + _.assert( !_.props.has( seeker.IterationPreserve, 'src' ) || seeker.IterationPreserve.src === undefined ); + _.assert( !_.props.has( seeker, 'src' ) || seeker.src === undefined ); + _.assert( !_.props.has( seeker.Iteration, 'root' ) || seeker.Iteration.root === undefined ); + _.assert( !_.props.has( seeker, 'root' ) || seeker.root === undefined ); + if( _.props.has( seeker, 'dst' ) ) + { + _.assert( _.props.has( seeker.Iteration, 'dst' ) && seeker.Iteration.dst === undefined ); + _.assert( _.props.has( seeker, 'dst' ) && seeker.dst === undefined ); + } + + for( let k in seeker.Iteration ) + if( _.props.has( seeker, k ) ) + { + _.assert + ( + seeker[ k ] === seeker.Iteration[ k ], + () => `Conflicting default value of field::${k} of Seeker::${o.name}` + + `\n${seeker[ k ]} <> ${seeker.Iteration[ k ]}` + ); + } + + } + + /* - */ + +} + +classDefine.defaults = +{ + name : null, + parent : null, + prime : null, + seeker : null, + iterator : null, + iteration : null, + iterationPreserve : null, + exec : null, + execIt : null, +} + +// -- +// +// -- + +const Seeker = Object.create( null ); +Seeker.OriginalSeeker = Seeker; +Seeker.Seeker = Seeker; +Seeker.constructor = function Seeker() /* xxx : implement */ +{ + _.assert( 0, 'not implemented' ); + let prototype = _.prototype.of( this ); + _.assert( _.object.isBasic( prototype ) ); + _.assert( prototype.exec.defaults === prototype ); + let result = this.head( prototype.exec, arguments ); + _.assert( result === this ); + return this; +} + +_.prototype.set( Seeker.constructor, null ); +Seeker.constructor.prototype = Seeker; + +Seeker.head = head; +Seeker.optionsToIteration = optionsToIteration; +Seeker.optionsFromArguments = optionsFromArguments; +Seeker.iteratorProper = iteratorProper; +Seeker.iteratorRetype = iteratorRetype; +Seeker.iteratorInit = iteratorInit; +Seeker.iteratorInitBegin = iteratorInitBegin; +Seeker.iteratorInitEnd = iteratorInitEnd; +Seeker.iteratorIterationMake = iteratorIterationMake; +Seeker.iterationMake = iterationMake; +Seeker.iterationProper = iterationProper; +Seeker.onUp = null; +Seeker.onDown = null; +Seeker.iterationPrototype = null; +Seeker.firstIterationPrototype = null; + +/* xxx : remove Iterator? */ +const Iterator = Seeker.Iterator = Object.create( null ); + +const Iteration = Seeker.Iteration = Object.create( null ); +Iteration.down = null; + +const IterationPreserve = Seeker.IterationPreserve = Object.create( null ); + +// -- +// seeker extension +// -- + +let SeekerExtension = +{ + + Seeker, + + is, + iteratorIs, + iterationIs, + classDefine, + +} + +Object.assign( _.seeker, SeekerExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/1Seeker.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, _1Seeker_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file _1Seeker_s */ })(); + +/* */ /* begin of file ArgumentsArray_s */ ( function ArgumentsArray_s() { function ArgumentsArray_s_naked() { ( function _l5_ArgumentsArray_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +// + +let ArgumentsArrayExtension = +{ +} + +Object.assign( _.argumentsArray, ArgumentsArrayExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/ArgumentsArray.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ArgumentsArray_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ArgumentsArray_s */ })(); + +/* */ /* begin of file Array_s */ ( function Array_s() { function Array_s_naked() { ( function _l5_Array_s_() +{ + +'use strict'; + +const _ArrayIndexOf = Array.prototype.indexOf; +const _ArrayIncludes = Array.prototype.includes; +if( !_ArrayIncludes ) +_ArrayIncludes = function( e ){ _ArrayIndexOf.call( this, e ) } + +const _global = _global_; +const _ = _global_.wTools; + +/* + | can grow | can shrink | range +grow + - positive +select - + positive +relength + + positive +but - + negative +*/ + +/* array / long / buffer */ +/* - / inplace */ + +/* + +alteration Routines : + +- array { Op } { Tense } { Second } { How } + +alteration Op : [ Append , Prepend , Remove, Flatten ] // operation +alteration Tense : [ - , ed ] // what to return +alteration Second : [ -, element, array, array ] // how to treat src arguments +alteration How : [ - , Once , OnceStrictly ] // how to treat repeats + +~ 60 routines + +*/ + +// -- +// array checker +// -- + +function constructorLikeArray( src ) +{ + if( !src ) + return false; + + if( src === Function ) + return false; + if( src === Object ) + return false; + if( src === String ) + return false; + + if( _.primitive.is( src ) ) + return false; + + if( !( 'length' in src.prototype ) ) + return false; + if( Object.propertyIsEnumerable.call( src.prototype, 'length' ) ) + return false; + + return true; +} + +// -- +// array producer +// -- + +/** + * The routine arrayFromCoercing() returns Array from provided argument {-src-}. The feature of routine is possibility of + * converting an object-like {-src-} into Array. Also, routine longFromCoercing() converts string with number literals + * to an Array. + * + * @param { Array|Long|ObjectLike|String } src - An instance to convert into Array. + * If {-src-} is instance of Array, then routine converts not {-src-}. + * + * @example + * let src = [ 3, 7, 13, 'abc', false, undefined, null, {} ]; + * let got = _.arrayFromCoercing( src ); + * // returns [ 3, 7, 13, 'abc', false, undefined, null, {} ] + * console.log( got === src ); + * // log true + * + * @example + * let src = _.argumentsArray.make( [ 3, 7, 13, 'abc', false, undefined, null, {} ] ); + * let got = _.arrayFromCoercing( src ); + * // returns [ 3, 7, 13, 'abc', false, undefined, null, {} ] + * console.log( got === src ); + * // log false + * + * @example + * let src = { a : 3, b : 7, c : 13 }; + * let got = _.arrayFromCoercing( src ); + * // returns [ [ 'a', 3 ], [ 'b', 7 ], [ 'c', 13 ] ] + * + * @example + * let src = "3, 7, 13, 3.5abc, 5def, 7.5ghi, 13jkl"; + * let got = _.arrayFromCoercing( src ); + * // returns [ 3, 7, 13, 3.5, 5, 7.5, 13 ] + * + * @returns { Array } - Returns an Array. If {-src-} is Array instance, then routine returns original {-src-}. + * @function arrayFromCoercing + * @throws { Error } If {-src-} is not an Array, not a Long, not object-like, not a String. + * @namespace Tools + */ + +function arrayFromCoercing( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.arrayIs( src ) && !_.unrollIs( src ) ) + return src; + + if( _.longIs( src ) ) + return Array.prototype.slice.call( src ); + + if( _.strIs( src ) ) + return this.arrayFromStr( src ); + + if( _.object.isBasic( src ) ) + return _.props.pairs( src ); + + _.assert( 0, 'Unknown data type : ' + _.entity.strType( src ) ); +} + +// + +function arrayFromStr( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ) ); + return src.split(/[, ]+/).map( ( s ) => s.length ? parseFloat( s ) : undefined ); +} + +// -- +// array transformer +// -- + +function arrayExtendAppending( dst, src ) +{ + + _.assert( arguments.length === 2 ); + + if( _.longIs( src ) ) + { + + if( dst === null || dst === undefined ) + dst = _.longSlice( src ); + else if( _.arrayIs( dst ) ) + dst = _.arrayAppendArray( dst, src ); + else if( _.longLike( dst ) ) + dst = _.arrayAppendArrays( null, [ dst, src ] ); + else + dst = _.arrayAppendArray( [ dst ], src ); + + } + else + { + + if( dst === null || dst === undefined ) + dst = [ src ]; + else if( _.arrayIs( dst ) ) + dst = _.arrayAppend( dst, src ); + else if( _.longLike( dst ) ) + dst = _.arrayAppendArrays( null, [ dst, src ] ); + else + dst = _.arrayAppend( [ dst ], src ); + + } + + return dst; +} + +// + +function arrayExtendPrepending( dst, src ) +{ + + _.assert( arguments.length === 2 ); + + if( _.longIs( src ) ) + { + + if( dst === null || dst === undefined ) + dst = _.longSlice( src ); + else if( _.arrayIs( dst ) ) + dst = _.arrayPrependArray( dst, src ); + else if( _.longLike( dst ) ) + dst = _.arrayPrependArrays( null, [ dst, src ] ); + else + dst = _.arrayPrependArray( [ dst ], src ); + + } + else + { + + if( dst === null || dst === undefined ) + dst = [ src ]; + else if( _.arrayIs( dst ) ) + dst = _.arrayPrepend( dst, src ); + else if( _.longLike( dst ) ) + dst = _.arrayPrependArrays( null, [ dst, src ] ); + else + dst = _.arrayPrepend( [ dst ], src ); + + } + + return dst; +} + +// + +/** + * The routine arrayBut() returns a shallow copy of provided array {-src-}. Routine removes existing + * elements in bounds defined by {-range-} and insert new elements from {-ins-}. The original + * source array {-src-} will not be modified. + * + * @param { Array|Unroll } src - The Array or Unroll from which makes a shallow copy. + * @param { Range|Number } range - The two-element array that defines the start index and the end index for removing elements. + * If {-range-} is number, then it defines the start index, and the end index is start index incremented by one. + * If {-range-} is undefined, routine returns copy of {-src-}. + * If range[ 0 ] < 0, then start index sets to 0. + * If range[ 1 ] > src.length, end index sets to src.length. + * If range[ 1 ] <= range[ 0 ], then routine removes not elements, the insertion of elements begins at start index. + * @param { Long } ins - The Long with elements for insertion. Inserting begins at start index. + * If quantity of removed elements is not equal to ins.length, then returned array will have length different to src.length. + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayBut( src ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5 ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayBut( src, 2, [ 'str' ] ); + * console.log( got ); + * // log [ 1, 2, 'str', 4, 5 ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayBut( src, [ 1, 4 ], [ 'str' ] ); + * console.log( got ); + * // log [ 1, 'str', 5 ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayBut( src, [ -5, 10 ], [ 'str' ] ); + * console.log( got ); + * // log [ 'str' ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayBut( src, [ 4, 1 ], [ 'str' ] ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 'str', 5 ] + * console.log( got === src ); + * // log false + * + * @returns { Array|Unroll } Returns a copy of Array / Unroll with removed or replaced existing elements and / or added new elements. + * @function arrayBut + * @throws { Error } If arguments.length is less then one or more then three. + * @throws { Error } If argument {-src-} is not an array or unroll. + * @throws { Error } If range.length is less or more then two. + * @throws { Error } If range elements is not number / undefined. + * @throws { Error } If argument {-ins-} is not Long / undefined. + * @namespace Tools + */ + +function arrayBut( src, range, ins ) +{ + + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + + if( range === undefined ) + return _.array.make( src ); + + if( _.number.is( range ) ) + range = [ range, range + 1 ]; + + _.assert( _.arrayIs( src ) ); + _.assert( _.intervalIs( range ) ); + _.assert( ins === undefined || _.longLike( ins ) ); + + _.ointerval.clamp/*rangeClamp*/( range, [ 0, src.length ] ); + if( range[ 1 ] < range[ 0 ] ) + range[ 1 ] = range[ 0 ]; + + let args = [ range[ 0 ], range[ 1 ] - range[ 0 ] ]; + + if( ins ) + _.arrayAppendArray( args, ins ); + + let result = src.slice(); + + result.splice.apply( result, args ); + + return result; +} + +// + +/** + * The routine arrayButInplace() returns a provided array {-src-} with removed existing elements in bounds + * defined by {-range-} and inserted new elements from {-ins-}. + * + * @param { Array|Unroll } src - The Array or Unroll to remove, replace or add elements. + * @param { Range|Number } range - The two-element array that defines the start index and the end index for removing elements. + * If {-range-} is number, then it defines the start index, and the end index defines as start index incremented by one. + * If {-range-} is undefined, routine returns {-src-}. + * If range[ 0 ] < 0, then start index sets to 0. + * If range[ 1 ] > src.length, end index sets to src.length. + * If range[ 1 ] <= range[ 0 ], then routine removes no elements, the insertion of elements begins at start index. + * @param { Long } ins - The Long with elements for insertion. Inserting begins at start index. + * If quantity of removed elements is not equal to ins.length, then returned array will have length different to original src.length. + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayButInplace( src ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5 ] + * console.log( got === src ); + * // log true + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayButInplace( src, 2, [ 'str' ] ); + * console.log( got ); + * // log [ 1, 2, 'str', 4, 5 ] + * console.log( got === src ); + * // log true + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayButInplace( src, [ 1, 4 ], [ 'str' ] ); + * console.log( got ); + * // log [ 1, 'str', 5 ] + * console.log( got === src ); + * // log true + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayButInplace( src, [ -5, 10 ], [ 'str' ] ); + * console.log( got ); + * // log [ 'str' ] + * console.log( got === src ); + * // log true + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayButInplace( src, [ 4, 1 ], [ 'str' ] ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 'str', 5 ] + * console.log( got === src ); + * // log true + * + * @returns { Array|Unroll } Returns original Array / Unroll with removed or replaced existing elements and / or added new elements. + * @function arrayButInplace + * @throws { Error } If arguments.length is less then one or more then three. + * @throws { Error } If argument {-src-} is not an array or unroll. + * @throws { Error } If range.length is less or more then two. + * @throws { Error } If range elements is not number / undefined. + * @throws { Error } If argument {-ins-} is not Long / undefined. + * @namespace Tools + */ + +function arrayButInplace( src, range, ins ) +{ + + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + + if( range === undefined ) + return src; + + if( _.number.is( range ) ) + range = [ range, range + 1 ]; + + _.assert( _.arrayLikeResizable( src ) ); + _.assert( _.intervalIs( range ) ); + _.assert( ins === undefined || _.longLike( ins ) ); + + _.ointerval.clamp( range, [ 0, src.length ] ); + if( range[ 1 ] < range[ 0 ] ) + range[ 1 ] = range[ 0 ]; + + let args = [ range[ 0 ], range[ 1 ] - range[ 0 ] ]; + + if( ins ) + { + if( !Object.isExtensible( src ) && ins.length > range[ 1 ] - range[ 0 ] ) + _.assert( 0, 'Array is not resizable, cannot change length of array' ); + else + _.arrayAppendArray( args, ins ); + } + + + let result = src; + + result.splice.apply( result, args ); + + return result; +} + +// + +function arrayBut_( /* dst, src, cinterval, ins */ ) +{ + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + + if( arguments.length < 4 && dst !== null && dst !== src ) + { + dst = arguments[ 0 ]; + src = arguments[ 0 ]; + cinterval = arguments[ 1 ]; + ins = arguments[ 2 ]; + } + + if( cinterval === undefined ) + { + cinterval = [ 0, -1 ]; + ins = undefined; + } + else if( _.number.is( cinterval ) ) + { + cinterval = [ cinterval, cinterval ]; + } + + _.assert( _.arrayIs( dst ) || dst === null, 'Expects {-dst-} of Array type or null' ); + _.assert( _.longIs( src ), 'Expects {-src-} of Array type' ); + _.assert( _.intervalIs( cinterval ), 'Expects cinterval {-cinterval-}' ); + _.assert( _.longLike( ins ) || ins === undefined || ins === null, 'Expects long {-ins-} for insertion' ); + + let first = cinterval[ 0 ] = cinterval[ 0 ] !== undefined ? cinterval[ 0 ] : 0; + let last = cinterval[ 1 ] = cinterval[ 1 ] !== undefined ? cinterval[ 1 ] : src.length - 1; + + if( first < 0 ) + first = 0; + if( first > src.length ) + first = src.length; + if( last > src.length - 1 ) + last = src.length - 1; + + if( last + 1 < first ) + last = first - 1; + + let delta = last - first + 1; + let insLength = ins ? ins.length : 0; + let delta2 = delta - insLength; + let resultLength = src.length - delta2; + + let result = dst; + if( dst === null ) + { + result = _.array.makeUndefined( resultLength ); + } + else if( dst === src ) + { + if( !( ( dst.length === resultLength ) && delta === 0 ) ) + ins ? dst.splice( first, delta, ... ins ) : dst.splice( first, delta ); + return dst; + } + else if( dst.length !== resultLength ) + { + if( dst.length < resultLength ) + _.assert( Object.isExtensible( result ), 'Expects extensible array {-dst-}' ); + dst.length = resultLength; + } + + for( let i = 0 ; i < first ; i++ ) + result[ i ] = src[ i ]; + + for( let i = last + 1 ; i < src.length ; i++ ) + result[ i - delta2 ] = src[ i ]; + + if( ins ) + { + for( let i = 0 ; i < ins.length ; i++ ) + result[ first + i ] = ins[ i ]; + } + + return result; +} + +// + +/** + * The routine arrayShrink() returns a copy of a portion of provided array {-src-} into a new array object + * selected by {-range-}. The original {-src-} will not be modified. + * + * @param { Array|Unroll } src - The Array or Unroll from which makes a shallow copy. + * @param { Range|Number } range - The two-element array that defines the start index and the end index for copying elements. + * If {-range-} is number, then it defines the start index, and the end index sets to src.length. + * If {-range-} is undefined, routine returns copy of {-src-}. + * If range[ 0 ] < 0, then start index sets to 0. + * If range[ 1 ] > src.length, end index sets to src.length. + * If range[ 1 ] <= range[ 0 ], then routine returns empty array object. + * @param { * } ins - The object of any type for insertion. + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayShrink( src ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5 ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayShrink( src, 2, 'str' ); + * console.log( got ); + * // log [ 3, 4, 5 ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayShrink( src, [ 1, 4 ], 'str' ); + * console.log( got ); + * // log [ 2, 3, 4 ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayShrink( src, [ -5, 10 ], 'str' ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5 ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayShrink( src, [ 4, 1 ], 'str' ); + * console.log( got ); + * // log [] + * console.log( got === src ); + * // log false + * + * @returns { Array|Unroll } Returns a copy of Array / Unroll containing the extracted elements. + * @function arrayShrink + * @throws { Error } If arguments.length is less then one or more then three. + * @throws { Error } If argument {-src-} is not an array or unroll. + * @throws { Error } If range.length is less or more then two. + * @throws { Error } If range elements is not number / undefined. + * @namespace Tools + */ + +function arrayShrink( src, range, ins ) +{ + let result; + + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + + if( range === undefined ) + return src.slice(); + + if( _.number.is( range ) ) + range = [ range, src.length ]; + + _.assert( _.arrayIs( src ) ); + _.assert( _.intervalIs( range ) ); + + _.ointerval.clamp/*rangeClamp*/( range, [ 0, src.length ] ); + if( range[ 1 ] < range[ 0 ] ) + range[ 1 ] = range[ 0 ]; + + if( range[ 0 ] === 0 && range[ 1 ] === src.length ) + return src.slice( src ); + + result = _.array.makeUndefined( src, range[ 1 ]-range[ 0 ] ); + + let f2 = Math.max( range[ 0 ], 0 ); + let l2 = Math.min( src.length, range[ 1 ] ); + for( let r = f2 ; r < l2 ; r++ ) + result[ r-range[ 0 ] ] = src[ r ]; + + return result; +} + +// + +/** + * The routine arrayShrinkInplace() returns a portion of provided array {-src-} selected by {-range-}. + * + * @param { Array|Unroll } src - The Array or Unroll from which selects elements. + * @param { Range|Number } range - The two-element array that defines the start index and the end index for copying elements. + * If {-range-} is number, then it defines the start index, and the end index sets to src.length. + * If {-range-} is undefined, routine returns {-src-}. + * If range[ 0 ] < 0, then start index sets to 0. + * If range[ 1 ] > src.length, end index sets to src.length. + * If range[ 1 ] <= range[ 0 ], then routine returns empty array object. + * @param { * } ins - The object of any type for insertion. + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayShrinkInplace( src ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5 ] + * console.log( got === src ); + * // log true + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayShrinkInplace( src, 2, 'str' ); + * console.log( got ); + * // log [ 3, 4, 5 ] + * console.log( got === src ); + * // log true + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayShrinkInplace( src, [ 1, 4 ], 'str' ); + * console.log( got ); + * // log [ 2, 3, 4 ] + * console.log( got === src ); + * // log true + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayShrinkInplace( src, [ -5, 10 ], 'str' ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5 ] + * console.log( got === src ); + * // log true + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayShrinkInplace( src, [ 4, 1 ], 'str' ); + * console.log( got ); + * // log [] + * console.log( got === src ); + * // log true + * + * @returns { Array|Unroll } Returns a Array / Unroll containing the selected elements. + * @function arrayShrinkInplace + * @throws { Error } If arguments.length is less then one or more then three. + * @throws { Error } If argument {-src-} is not an array or unroll. + * @throws { Error } If range.length is less or more then two. + * @throws { Error } If range elements is not number / undefined. + * @namespace Tools + */ + +function arrayShrinkInplace( src, range, ins ) +{ + + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + + if( range === undefined ) + return src; + + if( _.number.is( range ) ) + range = [ range, src.length ]; + + _.assert( _.arrayIs( src ) ); + _.assert( _.intervalIs( range ) ); + + _.ointerval.clamp/*rangeClamp*/( range, [ 0, src.length ] ); + if( range[ 1 ] < range[ 0 ] ) + range[ 1 ] = range[ 0 ]; + + if( range[ 0 ] === 0 && range[ 1 ] === src.length ) + return src; + + let f2 = Math.max( range[ 0 ], 0 ); + let l2 = Math.min( src.length, range[ 1 ] ); + + let result = src; + + result.splice.apply( result, [ 0, f2 ] ); + result.length = range[ 1 ] - range[ 0 ]; + + return result; +} + +// + +function arrayShrink_( dst, src, cinterval ) +{ + _.assert( 1 <= arguments.length && arguments.length <= 3, 'Expects not {-ins-} argument' ); + + if( arguments.length < 3 && dst !== null && dst !== src ) + { + dst = arguments[ 0 ]; + src = arguments[ 0 ]; + cinterval = arguments[ 1 ]; + } + + if( cinterval === undefined ) + cinterval = [ 0, src.length - 1 ]; + if( _.number.is( cinterval ) ) + cinterval = [ 0, cinterval ]; + + _.assert( _.arrayIs( dst ) || dst === null, 'Expects {-dst-} of Array type or null' ); + _.assert( _.arrayIs( src ), 'Expects {-src-} of Array type' ); + _.assert( _.intervalIs( cinterval ), 'Expects cinterval {-cinterval-}' ); + + let first = cinterval[ 0 ] = cinterval[ 0 ] !== undefined ? cinterval[ 0 ] : 0; + let last = cinterval[ 1 ] = cinterval[ 1 ] !== undefined ? cinterval[ 1 ] : src.length - 1; + + if( first < 0 ) + first = 0; + if( last > src.length - 1 ) + last = src.length - 1; + + if( last + 1 < first ) + last = first - 1; + + let first2 = Math.max( first, 0 ); + let last2 = Math.min( src.length - 1, last ); + + let resultLength = last - first + 1; + + let result = dst; + if( dst === null ) + { + result = _.array.makeUndefined( resultLength ); + } + else if( dst === src ) + { + result.splice.apply( result, [ 0, first2 ] ); + result.length = resultLength; + return result; + } + else if( dst.length < resultLength ) + { + _.assert( Object.isExtensible( dst ), 'Array is not extensible, cannot change array' ); + result.length = resultLength; + } + + for( let i = first2 ; i < last2 + 1 ; i++ ) + result[ i - first2 ] = src[ i ]; + + return result; +} + +// + +/** + * Routine arrayGrow() changes length of provided array {-src-} by copying it elements to newly created array + * using range {-range-} positions of the original array and value to fill free space after copy {-ins-}. + * Routine can only grows size of array.The original {-src-} will not be modified. + * + * @param { Array|Unroll } src - The Array or Unroll from which makes a shallow copy. + * @param { Range|Number } range - The two-element array that defines the start index and the end index for copying elements. + * If {-range-} is number, then it defines the end index, and the start index is 0. + * If range[ 0 ] < 0, then start index sets to 0, end index incrementes by absolute value of range[ 0 ]. + * If range[ 0 ] > 0, then start index sets to 0. + * If range[ 1 ] > src.length, end index sets to src.length. + * If range[ 1 ] <= range[ 0 ], then routine returns copy of origin array. + * @param { * } ins - object of any type. Used to fill the space left after copying elements of the original array. + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayGrow( src ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5 ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayGrow( src, 7, 'str' ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5, 'str', 'str' ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayGrow( src, [ 1, 6 ], 'str' ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5, 'str' ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayGrow( src, [ -5, 6 ], 7 ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5, 7, 7, 7, 7, 7, 7 ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayGrow( src, [ 4, 1 ], 'str' ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5 ] + * console.log( got === src ); + * // log false + * + * @returns { Array|Unroll } Returns a copy of Array / Unroll with changed length. + * @function arrayGrow + * @throws { Error } If arguments.length is less then one or more then three. + * @throws { Error } If argument {-src-} is not an array or unroll. + * @throws { Error } If range.length is less or more then two. + * @throws { Error } If range elements is not number / undefined. + * @namespace Tools + */ + +function arrayGrow( src, range, ins ) +{ + let result; + + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + + if( range === undefined ) + return src.slice(); + + if( _.number.is( range ) ) + range = [ 0, range ]; + + let f = range ? range[ 0 ] : undefined; + let l = range ? range[ 1 ] : undefined; + + f = f !== undefined ? f : 0; + l = l !== undefined ? l : src.length; + + _.assert( _.arrayIs( src ) ); + _.assert( _.intervalIs( range ) ) + + if( l < f ) + l = f; + + if( f < 0 ) + { + l -= f; + f -= f; + } + + if( f > 0 ) + f = 0; + if( l < src.length ) + l = src.length; + + if( l === src.length ) + return src.slice(); + + result = _.array.makeUndefined( src, l-f ); + + let f2 = Math.max( f, 0 ); + let l2 = Math.min( src.length, l ); + for( let r = f2 ; r < l2 ; r++ ) + result[ r-f ] = src[ r ]; + + if( ins !== undefined ) + { + for( let r = l2 - f; r < result.length ; r++ ) + { + result[ r ] = ins; + } + } + + return result; +} + +// + +/** + * Routine arrayGrowInplace() changes length of provided array {-src-} using range {-range-} positions of the original + * array and value to fill free space after copy {-ins-}. Routine can only grows size of array. + * + * @param { Array|Unroll } src - The Array or Unroll to grow length. + * @param { Range|Number } range - The two-element array that defines the start index and the end index for copying elements. + * If {-range-} is number, then it defines the end index, and the start index is 0. + * If range[ 0 ] < 0, then start index sets to 0, end index incrementes by absolute value of range[ 0 ]. + * If range[ 0 ] > 0, then start index sets to 0. + * If range[ 1 ] > src.length, end index sets to src.length. + * If range[ 1 ] <= range[ 0 ], then routine returns copy of origin array. + * @param { * } ins - The object of any type. Used to fill the space left of the original array. + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayGrow( src ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5 ] + * console.log( got === src ); + * // log true + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayGrow( src, 7, 'str' ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5, 'str', 'str' ] + * console.log( got === src ); + * // log true + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayGrow( src, [ 1, 6 ], 'str' ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5, 'str' ] + * console.log( got === src ); + * // log true + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayGrow( src, [ -5, 6 ], 7 ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5, 7, 7, 7, 7, 7, 7 ] + * console.log( got === src ); + * // log true + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayGrow( src, [ 4, 1 ], 'str' ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5 ] + * console.log( got === src ); + * // log true + * + * @returns { Array|Unroll } Returns a provided Array / Unroll with changed length. + * @function arrayGrowInplace + * @throws { Error } If arguments.length is less then one or more then three. + * @throws { Error } If argument {-src-} is not an array or unroll. + * @throws { Error } If range.length is less or more then two. + * @throws { Error } If range elements is not number / undefined. + * @namespace Tools + */ + +function arrayGrowInplace( src, range, ins ) +{ + + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + + if( range === undefined ) + return src; + + if( _.number.is( range ) ) + range = [ 0, range ]; + + let f = range ? range[ 0 ] : undefined; + let l = range ? range[ 1 ] : undefined; + + f = f !== undefined ? f : 0; + l = l !== undefined ? l : src.length; + + _.assert( _.arrayIs( src ) ); + _.assert( _.intervalIs( range ) ) + + if( f < 0 ) + { + l -= f; + f -= f; + } + + if( l < f ) + l = f; + + if( f > 0 ) + f = 0; + if( l < src.length ) + l = src.length; + + if( l === src.length ) + return src; + + if( !Object.isExtensible( src ) && src.length < l ) + _.assert( 0, 'Array is not extensible, cannot change length of array' ); + + let resultLength = l - f; + let f2 = Math.max( -range[ 0 ], 0 ); + let l2 = Math.min( src.length, l ); + l2 += f2; + + src.splice( f, 0, ... _.dup( ins, f2 ) ); + src.splice( l2, 0, ... _.dup( ins, resultLength <= l2 ? 0 : resultLength - l2 ) ); + return src; +} + +// + +function arrayGrow_( /* dst, src, cinterval, ins */ ) +{ + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + + if( arguments.length < 4 && dst !== null && dst !== src ) + { + dst = arguments[ 0 ]; + src = arguments[ 0 ]; + cinterval = arguments[ 1 ]; + ins = arguments[ 2 ]; + } + + if( cinterval === undefined ) + cinterval = [ 0, src.length - 1 ]; + if( _.number.is( cinterval ) ) + cinterval = [ 0, cinterval - 1 ]; + + _.assert( _.arrayIs( dst ) || dst === null, 'Expects {-dst-} of Array type or null' ); + _.assert( _.arrayIs( src ), 'Expects {-src-} of Array type' ); + _.assert( _.intervalIs( cinterval ), 'Expects cinterval {-cinterval-}' ); + + let f = cinterval[ 0 ] === undefined ? 0 : cinterval[ 0 ]; + let l = cinterval[ 1 ] === undefined ? src.length - 1 : cinterval[ 1 ]; + + if( f > 0 ) + f = 0; + if( l < src.length - 1 ) + l = src.length - 1; + + if( f < 0 ) + { + l -= f; + f -= f; + } + + if( l + 1 < f ) + l = f - 1; + + let f2 = Math.max( -cinterval[ 0 ], 0 ); + let l2 = Math.min( src.length - 1 + f2, l + f2 ); + + let resultLength = l - f + 1; + + let result = dst; + if( dst === null ) + { + result = _.array.make( resultLength ); + } + else if( dst === src ) + { + if( dst.length === resultLength ) + return dst; + + _.assert( Object.isExtensible( dst ), 'Array is not extensible, cannot change array' ); + + dst.splice( f, 0, ... _.dup( ins, f2 ) ); + dst.splice( l2 + 1, 0, ... _.dup( ins, resultLength <= l2 ? 0 : resultLength - l2 - 1 ) ); + return dst; + } + else if( dst.length < resultLength && !Object.isExtensible( dst ) ) + { + _.assert( 0, 'Array is not extensible, cannot change array' ); + } + + for( let r = f2 ; r < l2 + 1 ; r++ ) + result[ r ] = src[ r - f2 ]; + + if( ins !== undefined ) + { + for( let r = 0 ; r < f2 ; r++ ) + result[ r ] = ins; + + for( let r = l2 + 1 ; r < resultLength ; r++ ) + result[ r ] = ins; + } + + return result; +} + +// function arrayGrow_( dst, src, range, ins ) +// { +// +// [ dst, src, range, ins ] = _argumentsOnlyArray.apply( this, arguments ); +// +// if( range === undefined ) +// return returnDst(); +// +// if( _.number.is( range ) ) +// range = [ 0, range ]; +// _.assert( _.intervalIs( range ) || _.number.is( range ) || range === undefined ); +// +// let f = range[ 0 ] === undefined ? 0 : range[ 0 ]; +// let l = range[ 1 ] === undefined ? 0 : range[ 1 ]; +// +// if( l < f ) +// l = f; +// +// if( f < 0 ) +// { +// l -= f; +// f -= f; +// } +// +// if( f > 0 ) +// f = 0; +// if( l < src.length ) +// l = src.length; +// +// if( l === src.length ) +// return returnDst(); +// +// let l2 = src.length; +// +// let result; +// if( dst !== false ) +// { +// if( dst.length !== undefined ) +// result = dst; +// else +// result = src.slice(); +// +// if( !Object.isExtensible( dst ) && dst.length < l - f ) +// _.assert( 0, 'Array is not extensible, cannot change array' ); +// +// for( let i = 0; i < l2; i++ ) +// result[ i ] = src[ i ]; +// } +// else +// { +// if( !Object.isExtensible( src ) && src.length < l - f ) +// _.assert( 0, 'Array is not extensible, cannot change array' ); +// +// result = src; +// } +// +// result.length = l; +// +// if( ins !== undefined ) +// { +// for( let r = l2; r < result.length ; r++ ) +// result[ r ] = ins; +// } +// +// return result; +// +// /* */ +// +// function returnDst() +// { +// if( dst.length !== undefined ) +// dst.splice( 0, dst.length, ... src ); +// else +// dst = dst === true ? src.slice() : src; +// +// return dst; +// } +// } + +// + +/** + * Routine arrayRelength() changes length of provided array {-src-} by copying it elements to newly created array object + * using range (range) positions of the original array and value to fill free space after copy (val). + * Routine can grows and reduces size of Long. The original {-src-} will not be modified. + * + * @param { Array|Unroll } src - The Array or Unroll from which makes a shallow copy. + * @param { Range|Number } range - The two-element array that defines the start index and the end index for copying elements. + * If {-range-} is number, then it defines the start index, and the end index sets to src.length. + * If range[ 0 ] < 0, then start index sets to 0. + * If range[ 1 ] <= range[ 0 ], then routine returns empty array. + * @param { * } ins - The object of any type. Inserting begins from last index of {-src-} to end index. + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayRelength( src ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5 ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayRelength( src, 7, 'str' ); + * console.log( got ); + * // log [] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayRelength( src, [ 1, 6 ], 'str' ); + * console.log( got ); + * // log [ 2, 3, 4, 5, 'str' ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayRelength( src, [ -5, 6 ], 7 ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5, 7 ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayRelength( src, [ 4, 1 ], 'str' ); + * console.log( got ); + * // log [] + * console.log( got === src ); + * // log false + * + * @returns { Array|Unroll } Returns a copy provided Array / Unroll with changed length. + * @function arrayRelength + * @throws { Error } If arguments.length is less then one or more then three. + * @throws { Error } If argument {-src-} is not an array or unroll. + * @throws { Error } If range.length is less or more then two. + * @throws { Error } If range elements is not number / undefined. + * @namespace Tools + */ + +function arrayRelength( src, range, ins ) +{ + let result; + + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + + if( range === undefined ) + return src.slice(); + + if( _.number.is( range ) ) + range = [ range, src.length ]; + + let f = range ? range[ 0 ] : undefined; + let l = range ? range[ 1 ] : undefined; + + f = f !== undefined ? f : 0; + l = l !== undefined ? l : src.length; + + _.assert( _.arrayIs( src ) ); + _.assert( _.intervalIs( range ) ); + + if( l < f ) + l = f; + + if( f < 0 ) + f = 0; + + if( f === 0 && l === src.length ) + return src.slice( src ); + + result = _.array.makeUndefined( src, l-f ); + + let f2 = Math.max( f, 0 ); + let l2 = Math.min( src.length, l ); + for( let r = f2 ; r < l2 ; r++ ) + result[ r-f2 ] = src[ r ]; + + if( ins !== undefined ) + { + for( let r = l2 - f; r < result.length ; r++ ) + result[ r ] = ins; + } + + return result; +} + +// + +/** + * Routine arrayRelengthInplace() changes length of provided array {-src-} using range {-range-} positions of the original + * array and value to fill free space after copy {-ins-}. Routine can grows and reduce size of Long. + * + * @param { Array|Unroll } src - The Array or Unroll to change length. + * @param { Range|Number } range - The two-element array that defines the start index and the end index of new array. + * If {-range-} is number, then it defines the start index, and the end index sets to src.length. + * If range[ 0 ] < 0, then start index sets to 0. + * If range[ 1 ] <= range[ 0 ], then routine returns empty array. + * @param { * } ins - The object of any type. Inserting begins from last index of {-src-} to end index. + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayRelengthInplace( src ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5 ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayRelengthInplace( src, 7, 'str' ); + * console.log( got ); + * // log [] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayRelengthInplace( src, [ 1, 6 ], 'str' ); + * console.log( got ); + * // log [ 2, 3, 4, 5, 'str' ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayRelengthInplace( src, [ -5, 6 ], 7 ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 5, 7 ] + * console.log( got === src ); + * // log false + * + * @example + * var src = [ 1, 2, 3, 4, 5 ]; + * var got = _.arrayRelengthInplace( src, [ 4, 1 ], 'str' ); + * console.log( got ); + * // log [] + * console.log( got === src ); + * // log false + * + * @returns { Array|Unroll } Returns a provided Array / Unroll with changed length. + * @function arrayRelengthInplace + * @throws { Error } If arguments.length is less then one or more then three. + * @throws { Error } If argument {-src-} is not an array or unroll. + * @throws { Error } If range.length is less or more then two. + * @throws { Error } If range elements is not number / undefined. + * @namespace Tools + */ + +function arrayRelengthInplace( src, range, ins ) +{ + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + + if( range === undefined ) + return src; + + if( _.number.is( range ) ) + range = [ range, src.length ]; + + let f = range ? range[ 0 ] : undefined; + let l = range ? range[ 1 ] : undefined; + + f = f !== undefined ? f : 0; + l = l !== undefined ? l : src.length; + + _.assert( _.arrayIs( src ) ); + _.assert( _.intervalIs( range ) ); + + if( l < f ) + l = f; + + if( f < 0 ) + f = 0; + + if( f === 0 && l === src.length ) + return src; + + if( !Object.isExtensible( src ) && src.length < l - f ) + _.assert( 0, 'Array is not extensible, cannot change length of array' ); + + let f2 = Math.max( f, 0 ); + let l2 = Math.min( src.length, l ); + + let result = src; + + result.splice.apply( result, [ 0, f ] ); + result.length = l - f; + + if( ins !== undefined ) + { + for( let r = l2 - f; r < result.length ; r++ ) + result[ r ] = ins; + } + + return result; +} + +// + +function arrayRelength_( /* dst, src, cinterval, ins */ ) +{ + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + + if( arguments.length < 4 && dst !== null && dst !== src ) + { + dst = arguments[ 0 ]; + src = arguments[ 0 ]; + cinterval = arguments[ 1 ]; + ins = arguments[ 2 ]; + } + + if( cinterval === undefined ) + cinterval = [ 0, src.length - 1 ]; + if( _.number.is( cinterval ) ) + cinterval = [ 0, cinterval - 1 ]; + + _.assert( _.arrayIs( dst ) || dst === null, 'Expects {-dst-} of Array type or null' ); + _.assert( _.arrayIs( src ), 'Expects {-src-} of Array type' ); + _.assert( _.intervalIs( cinterval ), 'Expects cinterval {-cinterval-}' ); + + let first = cinterval[ 0 ] = cinterval[ 0 ] !== undefined ? cinterval[ 0 ] : 0; + let last = cinterval[ 1 ] = cinterval[ 1 ] !== undefined ? cinterval[ 1 ] : src.length - 1; + + if( last < first ) + last = first - 1; + + if( first < 0 ) + { + last -= first; + first -= first; + } + + let first2 = Math.max( Math.abs( cinterval[ 0 ] ), 0 ); + let last2 = Math.min( src.length - 1, last ); + + let resultLength = last - first + 1; + + let result = dst; + if( dst === null ) + { + result = _.array.makeUndefined( src, resultLength ); + } + else if( dst === src ) + { + if( dst.length === resultLength && cinterval[ 0 ] === 0 ) + { + return dst; + } + if( resultLength === 0 ) + { + return _.array.empty( dst ); + } + + if( dst.length < resultLength ) + _.assert( Object.isExtensible( dst ), 'dst is not extensible, cannot change dst' ); + + if( cinterval[ 0 ] < 0 ) + { + dst.splice( first, 0, ... _.dup( ins, first2 ) ); + dst.splice( last2 + 1, src.length - last2, ... _.dup( ins, last - last2 ) ); + } + else + { + dst.splice( 0, first ); + dst.splice( last2 + 1 - first2, dst.length - last2, ... _.dup( ins, last - last2 ) ); + } + return dst; + } + + /* */ + + if( result.length < resultLength ) + _.assert( Object.isExtensible( result ), 'dst is not extensible, cannot change dst' ); + + if( resultLength === 0 ) + { + return _.array.empty( result ); + } + if( cinterval[ 0 ] < 0 ) + { + result.splice( 0, first2, ... _.dup( ins, first2 ) ); + result.splice( first2, last2 - first2, ... src.slice( 0, last2 + 1 - first2 ) ); + result.splice( last2 + 1, result.length - last2, ... _.dup( ins, last - last2 ) ); + } + else + { + result.splice( 0, last2 + 1, ... src.slice( first2, last2 + 1 )); + result.splice( last2 + 1 - first2, result.length - last2, ... _.dup( ins, last - last2 ) ); + } + + return result; +} + +// -- +// array remove +// -- + +/** + * ArrayRemove, arrayRemoveOnce, arrayRemoveOnceStrictly and arrayRemoved behave just like + * arrayRemoveElement, arrayRemoveElementOnce, arrayRemoveElementOnceStrictly and arrayRemovedElement. + */ + +function arrayRemove( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.arrayRemoved.apply( this, arguments ); + return dstArray; +} + +// + +function arrayRemoveOnce( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.arrayRemovedOnce.apply( this, arguments ); + return dstArray; +} + +// + +function arrayRemoveOnceStrictly( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.arrayRemoveElementOnceStrictly.apply( this, arguments ); + return dstArray; +} + +// + +function arrayRemoved( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let removedElements = _.arrayRemovedElement.apply( this, arguments ); + return removedElements; +} + +// + +/** + * ArrayRemovedOnce and arrayRemovedOnceStrictly behave just like arrayRemovedElementOnce and arrayRemovedElementOnceStrictly, + * but return the index of the removed element, instead of the removed element + */ + +function arrayRemovedOnce( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let index = _.longLeftIndex.apply( _, arguments ); + if( index >= 0 ) + dstArray.splice( index, 1 ); + + return index; +} + +// + +function arrayRemovedOnceStrictly( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let index = _.longLeftIndex.apply( _, arguments ); + if( index >= 0 ) + { + dstArray.splice( index, 1 ); + } + else _.assert( 0, () => 'Array does not have element ' + _.entity.exportStringDiagnosticShallow( ins ) ); + + let newIndex = _.longLeftIndex.apply( _, arguments ); + _.assert( newIndex < 0, () => 'The element ' + _.entity.exportStringDiagnosticShallow( ins ) + ' is several times in dstArray' ); + + return index; +} + +// + +function arrayRemoveElement( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.arrayRemovedElement.apply( this, arguments ); + return dstArray; +} + +// + +/** + * The arrayRemoveElementOnce() routine removes the first matching element from (dstArray) + * that corresponds to the condition in the callback function and returns a modified array. + * + * It takes two (dstArray, ins) or three (dstArray, ins, onEvaluate) arguments, + * checks if arguments passed two, it calls the routine + * [arrayRemovedElementOnce( dstArray, ins )]{@link wTools.arrayRemovedElementOnce} + * Otherwise, if passed three arguments, it calls the routine + * [arrayRemovedElementOnce( dstArray, ins, onEvaluate )]{@link wTools.arrayRemovedElementOnce} + * @see wTools.arrayRemovedElementOnce + * @param { Array } dstArray - The source array. + * @param { * } ins - The value to remove. + * @param { wTools~compareCallback } [ onEvaluate ] - The callback that compares (ins) with elements of the array. + * By default, it checks the equality of two arguments. + * + * @example + * _.arrayRemoveElementOnce( [ 1, 'str', 2, 3, 'str' ], 'str' ); + * // returns [ 1, 2, 3, 'str' ] + * + * @example + * _.arrayRemoveElementOnce( [ 3, 7, 33, 13, 33 ], 13, function( el, ins ) { + * return el > ins; + * }); + * // returns [ 3, 7, 13, 33 ] + * + * @returns { Array } - Returns the modified (dstArray) array with the new length. + * @function arrayRemoveElementOnce + * @throws { Error } If the first argument is not an array. + * @throws { Error } If passed less than two or more than three arguments. + * @throws { Error } If the third argument is not a function. + * @namespace Tools + */ + +function arrayRemoveElementOnce( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + _.arrayRemovedElementOnce.apply( this, arguments ); + return dstArray; +} + +// + +function arrayRemoveElementOnceStrictly( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result; + if( Config.debug ) + { + let result = _.arrayRemovedElementOnce.apply( this, arguments ); + let index = _.longLeftIndex.apply( _, arguments ); + _.assert( index < 0 ); + _.assert( result >= 0, () => 'Array does not have element ' + _.entity.exportStringDiagnosticShallow( ins ) ); + } + else + { + let result = _.arrayRemovedElement.apply( this, [ dstArray, ins ] ); + } + return dstArray; +} + +/* +function arrayRemoveElementOnceStrictly( dstArray, ins, evaluator1, evaluator2 ) +{ + let result = arrayRemovedElementOnce.apply( this, arguments ); + _.assert( result >= 0, () => 'Array does not have element ' + _.entity.exportStringDiagnosticShallow( ins ) ); + return dstArray; +} +*/ + +// + +function arrayRemovedElement( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let index = _.longLeftIndex.apply( this, arguments ); + let removedElements = 0; + + for( let i = 0; i < dstArray.length; i++ ) /* Dmytro : bad implementation, this cycle run routine longLeftIndex even if it not needs, better implementation commented below */ + { + if( index !== -1 ) + { + dstArray.splice( index, 1 ); + removedElements = removedElements + 1; + i = i - 1 ; + } + index = _.longLeftIndex.apply( this, arguments ); /* Dmytro : this call uses not offset, it makes routine slower */ + } + + return removedElements; + + // let removedElements = 0; + // let index = _.longLeftIndex.apply( this, arguments ); + // evaluator1 = _.number.is( evaluator1 ) ? undefined : evaluator1; + // + // while( index !== -1 ) + // { + // dstArray.splice( index, 1 ); + // removedElements = removedElements + 1; + // index = _.longLeftIndex( dstArray, ins, index, evaluator1, evaluator2 ); + // } + // + // return removedElements; +} + +// + +function arrayRemovedElement_( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let removedElement; + + let index = _.longLeftIndex.apply( this, arguments ); + evaluator1 = _.number.is( evaluator1 ) ? undefined : evaluator1; + + if( index !== -1 ) + removedElement = dstArray[ index ]; + + while( index !== -1 ) + { + dstArray.splice( index, 1 ); + index = _.longLeftIndex( dstArray, ins, index, evaluator1, evaluator2 ); + } + + return removedElement; +} + +// + +/** + * The callback function to compare two values. + * + * @callback wTools~compareCallback + * @param { * } el - The element of the array. + * @param { * } ins - The value to compare. + */ + +/** + * The arrayRemovedElementOnce() routine returns the index of the first matching element from (dstArray) + * that corresponds to the condition in the callback function and remove this element. + * + * It takes two (dstArray, ins) or three (dstArray, ins, onEvaluate) arguments, + * checks if arguments passed two, it calls built in function(dstArray.indexOf(ins)) + * that looking for the value of the (ins) in the (dstArray). + * If true, it removes the value (ins) from (dstArray) array by corresponding index. + * Otherwise, if passed three arguments, it calls the routine + * [longLeftIndex( dstArray, ins, onEvaluate )]{@link wTools.longLeftIndex} + * If callback function(onEvaluate) returns true, it returns the index that will be removed from (dstArray). + * @see {@link wTools.longLeftIndex} - See for more information. + * + * @param { Array } dstArray - The source array. + * @param { * } ins - The value to remove. + * @param { wTools~compareCallback } [ onEvaluate ] - The callback that compares (ins) with elements of the array. + * By default, it checks the equality of two arguments. + * + * @example + * _.arrayRemovedElementOnce( [ 2, 4, 6 ], 4, function( el ) { + * return el; + * }); + * // returns 1 + * + * @example + * _.arrayRemovedElementOnce( [ 2, 4, 6 ], 2 ); + * // returns 0 + * + * @returns { Number } - Returns the index of the value (ins) that was removed from (dstArray). + * @function arrayRemovedElementOnce + * @throws { Error } If the first argument is not an array-like. + * @throws { Error } If passed less than two or more than three arguments. + * @throws { Error } If the third argument is not a function. + * @namespace Tools + */ + +function arrayRemovedElementOnce( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let index = _.longLeftIndex.apply( _, arguments ); + if( index >= 0 ) + dstArray.splice( index, 1 ); + + return index; + /* "!!! : breaking" */ + /* // arrayRemovedElementOnce should return the removed element + let result; + let index = _.longLeftIndex.apply( _, arguments ); + + if( index >= 0 ) + { + result = dstArray[ index ]; + dstArray.splice( index, 1 ); + } + + return result; + */ +} + +// + +function arrayRemovedElementOnce_( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let removedElement; + let index = _.longLeftIndex.apply( _, arguments ); + if( index >= 0 ) + { + removedElement = dstArray[ index ]; + dstArray.splice( index, 1 ); + } + + return removedElement; +} + +// + +function arrayRemovedElementOnceStrictly( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result; + let index = _.longLeftIndex.apply( _, arguments ); + if( index >= 0 ) + { + result = dstArray[ index ]; + dstArray.splice( index, 1 ); + } + else _.assert( 0, () => 'Array does not have element ' + _.entity.exportStringDiagnosticShallow( ins ) ); + + index = _.longLeftIndex.apply( _, arguments ); + _.assert( index < 0, () => 'The element ' + _.entity.exportStringDiagnosticShallow( ins ) + ' is several times in dstArray' ); + + return result; +} + +// + +function arrayRemovedElementOnceStrictly_( /* dstArray, ins, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let removedElement; + let index = _.longLeftIndex.apply( _, arguments ); + if( index >= 0 ) + { + removedElement = dstArray[ index ]; + dstArray.splice( index, 1 ); + } + else _.assert( 0, () => 'Array does not have element ' + _.entity.exportStringDiagnosticShallow( ins ) ); + + index = _.longLeftIndex.apply( _, arguments ); + _.assert( index < 0, () => 'The element ' + _.entity.exportStringDiagnosticShallow( ins ) + ' is several times in dstArray' ); + + return removedElement; +} + +/* +function arrayRemovedElementOnceStrictly( dstArray, ins, evaluator1, evaluator2 ) +{ + + let result; + let index = _.longLeftIndex.apply( _, arguments ); + if( index >= 0 ) + { + result = dstArray[ index ]; + dstArray.splice( index, 1 ); + } + else _.assert( 0, () => 'Array does not have element ' + _.entity.exportStringDiagnosticShallow( ins ) ); + + return result; +} +*/ + +// + +function arrayRemoveArray( dstArray, insArray ) +{ + arrayRemovedArray.apply( this, arguments ); + return dstArray; +} + +// + +function arrayRemoveArrayOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + arrayRemovedArrayOnce.apply( this, arguments ); + return dstArray; +} + +// + +function arrayRemoveArrayOnceStrictly( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result; + if( Config.debug ) + { + let insArrayLength = insArray.length; + result = arrayRemovedArrayOnce.apply( this, arguments ); + let index = - 1; + for( let i = 0, len = insArray.length; i < len ; i++ ) + { + index = dstArray.indexOf( insArray[ i ] ); + _.assert( index < 0 ); + } + _.assert( result === insArrayLength ); + + } + else + { + result = arrayRemovedArray.apply( this, [ dstArray, insArray ] ); + } + return dstArray; +} + +/* +function arrayRemoveArrayOnceStrictly( dstArray, insArray, evaluator1, evaluator2 ) +{ + let result = arrayRemovedArrayOnce.apply( this, arguments ); + _.assert( result === insArray.length ); + return dstArray; +} +*/ + +// + +function arrayRemovedArray( dstArray, insArray ) +{ + _.assert( arguments.length === 2 ) + _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + _.assert( _.longLike( insArray ) ); + + if( dstArray === insArray ) + return dstArray.splice( 0 ).length; + + let result = 0; + let index = -1; + + for( let i = 0, len = insArray.length; i < len ; i++ ) + { + index = dstArray.indexOf( insArray[ i ] ); + while( index !== -1 ) + { + dstArray.splice( index, 1 ); + result += 1; + index = dstArray.indexOf( insArray[ i ], index ); + } + } + + return result; +} + +// + +/** + * The callback function to compare two values. + * + * @callback arrayRemovedArrayOnce~onEvaluate + * @param { * } el - The element of the (dstArray[n]) array. + * @param { * } ins - The value to compare (insArray[n]). + */ + +/** + * The arrayRemovedArrayOnce() determines whether a (dstArray) array has the same values as in a (insArray) array, + * and returns amount of the deleted elements from the (dstArray). + * + * It takes two (dstArray, insArray) or three (dstArray, insArray, onEqualize) arguments, creates variable (let result = 0), + * checks if (arguments[..]) passed two, it iterates over the (insArray) array and calls for each element built in function(dstArray.indexOf(insArray[i])). + * that looking for the value of the (insArray[i]) array in the (dstArray) array. + * If true, it removes the value (insArray[i]) from (dstArray) array by corresponding index, + * and incrementing the variable (result++). + * Otherwise, if passed three (arguments[...]), it iterates over the (insArray) and calls for each element the routine + * + * If callback function(onEqualize) returns true, it returns the index that will be removed from (dstArray), + * and then incrementing the variable (result++). + * + * @see wTools.longLeftIndex + * + * @param { longLike } dstArray - The target array. + * @param { longLike } insArray - The source array. + * @param { function } onEqualize - The callback function. By default, it checks the equality of two arguments. + * + * @example + * _.arrayRemovedArrayOnce( [ ], [ ] ); + * // returns 0 + * + * @example + * _.arrayRemovedArrayOnce( [ 1, 2, 3, 4, 5 ], [ 6, 2, 7, 5, 8 ] ); + * // returns 2 + * + * @example + * _.arrayRemovedArrayOnce( [ 1, 2, 3, 4, 5 ], [ 6, 2, 7, 5, 8 ], function( a, b ) { + * return a < b; + * } ); + * // returns 4 + * + * @returns { number } Returns amount of the deleted elements from the (dstArray). + * @function arrayRemovedArrayOnce + * @throws { Error } Will throw an Error if (dstArray) is not an array-like. + * @throws { Error } Will throw an Error if (insArray) is not an array-like. + * @throws { Error } Will throw an Error if (arguments.length < 2 || arguments.length > 3). + * @namespace Tools + */ + +function arrayRemovedArrayOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + _.assert( _.longLike( insArray ) ); + + if( dstArray === insArray ) + if( arguments.length === 2 ) + return dstArray.splice( 0 ).length; + + let result = 0; + let index = -1; + + for( let i = insArray.length - 1; i >= 0 ; i-- ) + { + index = _.longLeftIndex( dstArray, insArray[ i ], evaluator1, evaluator2 ); + + if( index >= 0 ) + { + dstArray.splice( index, 1 ); + result += 1; + } + } + + return result; +} + +// + +function arrayRemovedArrayOnceStrictly( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result; + if( Config.debug ) + { + let insArrayLength = insArray.length; + result = arrayRemovedArrayOnce.apply( this, arguments ); + let index = - 1; + for( let i = 0, len = insArray.length; i < len ; i++ ) + { + index = dstArray.indexOf( insArray[ i ] ); + _.assert( index < 0 ); + } + _.assert( result === insArrayLength ); + + } + else + { + result = arrayRemovedArray.apply( this, [ dstArray, insArray ] ); + } + return result; +} + +// + +function arrayRemoveArrays( dstArray, insArray ) +{ + arrayRemovedArrays.apply( this, arguments ); + return dstArray; +} + +// + +function arrayRemoveArraysOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + arrayRemovedArraysOnce.apply( this, arguments ); + return dstArray; +} + +// + +function arrayRemoveArraysOnceStrictly( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result; + if( Config.debug ) + { + let expected = 0; + for( let i = insArray.length - 1; i >= 0; i-- ) + { + if( _.longLike( insArray[ i ] ) ) + expected += insArray[ i ].length; + else + expected += 1; + } + + result = arrayRemovedArraysOnce.apply( this, arguments ); + + _.assert( result === expected ); + _.assert( arrayRemovedArraysOnce.apply( this, arguments ) === 0 ); + } + else + { + result = arrayRemovedArrays.apply( this, [ dstArray, insArray ] ); + } + + return dstArray; +} + +/* +function arrayRemoveArraysOnceStrictly( dstArray, insArray, evaluator1, evaluator2 ) +{ + let result = arrayRemovedArraysOnce.apply( this, arguments ); + + let expected = 0; + for( let i = insArray.length - 1; i >= 0; i-- ) + { + if( _.longLike( insArray[ i ] ) ) + expected += insArray[ i ].length; + else + expected += 1; + } + + _.assert( result === expected ); + + return dstArray; +} +*/ + +// + +function arrayRemovedArrays( dstArray, insArray ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.arrayIs( dstArray ), 'arrayRemovedArrays :', 'Expects array' ); + _.assert( _.longLike( insArray ), 'arrayRemovedArrays :', 'Expects longLike entity' ); + + let result = 0; + + if( dstArray === insArray ) + { + result = insArray.length; + dstArray.splice( 0 ); + return result; + } + + function _remove( argument ) + { + let index = dstArray.indexOf( argument ); + while( index !== -1 ) + { + dstArray.splice( index, 1 ); + result += 1; + index = dstArray.indexOf( argument, index ); + } + } + + for( let a = insArray.length - 1; a >= 0; a-- ) + { + if( _.longLike( insArray[ a ] ) ) + { + let array = insArray[ a ]; + for( let i = array.length - 1; i >= 0; i-- ) + _remove( array[ i ] ); + } + else + { + _remove( insArray[ a ] ); + } + } + + return result; +} + +// + +function arrayRemovedArraysOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + _.assert( _.arrayIs( dstArray ), 'arrayRemovedArraysOnce :', 'Expects array' ); + _.assert( _.longLike( insArray ), 'arrayRemovedArraysOnce :', 'Expects longLike entity' ); + + let result = 0; + + if( dstArray === insArray ) + if( arguments.length === 2 ) + { + result = insArray.length; + dstArray.splice( 0 ); + return result; + } + + function _removeOnce( argument ) + { + let index = _.longLeftIndex( dstArray, argument, evaluator1, evaluator2 ); + if( index >= 0 ) + { + dstArray.splice( index, 1 ); + result += 1; + } + } + + for( let a = insArray.length - 1; a >= 0; a-- ) + { + if( _.longLike( insArray[ a ] ) ) + { + let array = insArray[ a ]; + for( let i = array.length - 1; i >= 0; i-- ) + _removeOnce( array[ i ] ); + } + else + { + _removeOnce( insArray[ a ] ); + } + } + + return result; +} + +// + +function arrayRemovedArraysOnceStrictly( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result; + if( Config.debug ) + { + let expected = 0; + for( let i = insArray.length - 1; i >= 0; i-- ) + { + if( _.longLike( insArray[ i ] ) ) + expected += insArray[ i ].length; + else + expected += 1; + } + + result = arrayRemovedArraysOnce.apply( this, arguments ); + + _.assert( result === expected ); + _.assert( arrayRemovedArraysOnce.apply( this, arguments ) === 0 ); + } + else + { + result = arrayRemovedArrays.apply( this, [ dstArray, insArray ] ); + } + + return result; +} + +// + +/** + * The arrayRemoveDuplicates( dstArray, evaluator ) routine returns the dstArray with the duplicated elements removed. + * + * @param { ArrayIs } dstArray - The source and destination array. + * @param { Function } [ evaluator = function( e ) { return e } ] - A callback function. + * + * @example + * _.arrayRemoveDuplicates( [ 1, 1, 2, 'abc', 'abc', 4, true, true ] ); + * // returns [ 1, 2, 'abc', 4, true ] + * + * @example + * _.arrayRemoveDuplicates( [ 1, 2, 3, 4, 5 ] ); + * // returns [ 1, 2, 3, 4, 5 ] + * + * @returns { Number } - Returns the source array without the duplicated elements. + * @function arrayRemoveDuplicates + * @throws { Error } If passed arguments is less than one or more than two. + * @throws { Error } If the first argument is not an array. + * @throws { Error } If the second argument is not a Function. + * @namespace Tools + */ + +function arrayRemoveDuplicates( dstArray, evaluator ) +{ + _.assert( 1 <= arguments.length || arguments.length <= 2 ); + _.assert( _.arrayIs( dstArray ), 'Expects Array' ); + + for( let i = 0 ; i < dstArray.length ; i++ ) + { + let index; + do + { + index = _.longRightIndex( dstArray, dstArray[ i ], evaluator ); + if( index !== i ) + { + dstArray.splice( index, 1 ); + } + } + while( index !== i ); + } + + return dstArray; +} + +/* +/* +function arrayRemoveDuplicates( dstArray, evaluator ) +{ + _.assert( 1 <= arguments.length || arguments.length <= 2 ); + _.assert( _.arrayIs( dstArray ), 'arrayRemoveDuplicates :', 'Expects Array' ); + + for( let i1 = 0 ; i1 < dstArray.length ; i1++ ) + { + let element1 = dstArray[ i1 ]; + let index = _.longRightIndex( dstArray, element1, evaluator ); + + while ( index !== i1 ) + { + dstArray.splice( index, 1 ); + index = _.longRightIndex( dstArray, element1, evaluator ); + } + } + + return dstArray; +} +*/ + +// -- +// array flatten +// -- + +/** + * The arrayFlatten() routine returns an array that contains all the passed arguments. + * + * It creates two variables the (result) - array and the {-srcMap-} - elements of array-like object (arguments[]), + * iterate over array-like object (arguments[]) and assigns to the {-srcMap-} each element, + * checks if {-srcMap-} is not equal to the 'undefined'. + * If true, it adds element to the result. + * If {-srcMap-} is an Array and if element(s) of the {-srcMap-} is not equal to the 'undefined'. + * If true, it adds to the (result) each element of the {-srcMap-} array. + * Otherwise, if {-srcMap-} is an Array and if element(s) of the {-srcMap-} is equal to the 'undefined' it throws an Error. + * + * @param {...*} arguments - One or more argument(s). + * + * @example + * _.arrayFlatten( 'str', {}, [ 1, 2 ], 5, true ); + * // returns [ 'str', {}, 1, 2, 5, true ] + * + * @returns { Array } - Returns an array of the passed argument(s). + * @function arrayFlatten + * @throws { Error } If (arguments[...]) is an Array and has an 'undefined' element. + * @namespace Tools + */ + +function arrayFlatten( dstArray, insArray ) +{ + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + _.arrayFlattened.apply( this, arguments ); + + return dstArray; +} + +// + +function arrayFlattenOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + _.arrayFlattenedOnce.apply( this, arguments ); + return dstArray; +} + +// + +function arrayFlattenOnceStrictly( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.arrayFlattenedOnceStrictly.apply( this, arguments ); + return dstArray; +} + +// + +function arrayFlattened( dstArray, src ) +{ + let result = 0; + let length = dstArray.length; + let visited = []; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.object.isBasic( this ) ); + _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${dstArray}"` ); + + if( arguments.length === 1 ) + { + for( let i = 0 ; i < dstArray.length ; i++ ) + { + let e = dstArray[ i ]; + if( _.longLike( e ) || _.set.like( e ) ) + { + dstArray.splice( i, 1 ); + if( e !== dstArray ) + i = containerReplace( e, i ); + i -= 1; + } + else + { + result += 1; + } + } + + return result; + } + + /* + Dmytro : stack is unstable if dstArray.push( dstArray ) + */ + if( _.longHas( dstArray, dstArray ) ) + { + let i = _.longLeftIndex( dstArray, dstArray ); + + while( i !== -1 ) + { + dstArray.splice( i, 1 ); + i = _.longLeftIndex( dstArray, dstArray ); + } + } + + if( _.longLike( src ) || _.set.like( src ) ) + { + containerAppend( src ); + } + else + { + dstArray.push( src ); + result += 1; + } + + return result; + + /* */ + + function containerAppend( src ) + { + if( _.longHas( visited, src ) ) + return; + visited.push( src ); + + let count; + if( src === dstArray ) + count = length; + else + count = src.length; + + for( let e of src ) + { + if( count < 1 ) + break; + count--; + + if( _.longLike( e ) || _.set.like( e ) ) + { + containerAppend( e ) + } + else + { + dstArray.push( e ); + result += 1; + } + } + + visited.pop(); + } + + /* */ + + function containerReplace( src, index ) + { + for( let e of src ) + { + if( _.longLike( e ) || _.set.like( e ) ) + { + index = containerReplace( e, index ); + } + else + { + dstArray.splice( index, 0, e ); + result += 1; + index += 1; + } + } + return index; + } + +} + +// + +function arrayFlattenedOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result = 0; + let length = dstArray.length; + let visited = []; + + _.assert( arguments.length && arguments.length <= 4 ); + _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + + if( arguments.length === 1 ) + { + _.arrayRemoveDuplicates( dstArray ); + + for( let i = 0 ; i < dstArray.length ; i++ ) + { + let e = dstArray[ i ]; + if( _.longLike( e ) || _.set.like( e ) ) + { + dstArray.splice( i, 1 ); + if( e !== dstArray ) + i = containerReplace( e, i ); + i -= 1; + } + else + { + result += 1; + } + } + + return result; + } + + if( _.longHas( dstArray, dstArray ) ) + { + let i = _.longLeftIndex( dstArray, dstArray ); + + while( i !== -1 ) + { + dstArray.splice( i, 1 ); + i = _.longLeftIndex( dstArray, dstArray ); + } + } + + if( _.longLike( insArray ) || _.set.like( insArray ) ) + { + containerAppend( insArray ); + } + else if( _.longLeftIndex( dstArray, insArray, evaluator1, evaluator2 ) === -1 ) + { + dstArray.push( insArray ); + result += 1; + } + + return result; + + /* */ + + function containerAppend( src ) + { + if( _.longHas( visited, src ) ) + return; + visited.push( src ); + + let count; + if( src === dstArray ) + count = length; + else + count = src.length; + + + for( let e of src ) + { + if( count < 1 ) + break; + count--; + + if( _.longLike( e ) || _.set.like( e ) ) + { + containerAppend( e ) + } + else if( _.longLeftIndex( dstArray, e, evaluator1, evaluator2 ) === -1 ) + { + dstArray.push( e ); + result += 1; + } + } + + visited.pop(); + } + + /* */ + + function containerReplace( src, index ) + { + for( let e of src ) + { + if( _.longLike( e ) || _.set.like( e ) ) + { + index = containerReplace( e, index ); + } + else if( _.longLeftIndex( dstArray, e ) === -1 ) + { + dstArray.splice( index, 0, e ); + result += 1; + index += 1; + } + } + return index; + } +} + +// function arrayFlattenedOnce( dstArray, insArray, evaluator1, evaluator2 ) +// { +// +// _.assert( arguments.length && arguments.length <= 4 ); +// _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); +// +// if( arguments.length === 1 ) +// { +// _.arrayRemoveDuplicates( dstArray ); +// +// for( let i = dstArray.length-1; i >= 0; --i ) +// if( _.longLike( dstArray[ i ] ) ) +// { +// let insArray = dstArray[ i ]; +// dstArray.splice( i, 1 ); +// onLongOnce( insArray, i ); +// } +// return dstArray; +// } +// +// let result = 0; +// +// if( _.longLike( insArray ) ) +// { +// for( let i = 0, len = insArray.length; i < len; i++ ) +// { +// _.assert( insArray[ i ] !== undefined, 'The Array should have no undefined' ); +// if( _.longLike( insArray[ i ] ) ) +// { +// let c = _.arrayFlattenedOnce( dstArray, insArray[ i ], evaluator1, evaluator2 ); +// result += c; +// } +// else +// { +// let index = _.longLeftIndex( dstArray, insArray[ i ], evaluator1, evaluator2 ); +// if( index === -1 ) +// { +// dstArray.push( insArray[ i ] ); +// result += 1; +// } +// } +// } +// } +// else +// { +// +// _.assert( insArray !== undefined, 'The Array should have no undefined' ); +// +// let index = _.longLeftIndex( dstArray, insArray, evaluator1, evaluator2 ); +// if( index === -1 ) +// { +// dstArray.push( insArray ); +// result += 1; +// } +// } +// +// return result; +// +// /* */ +// +// function onLongOnce( insArray, insIndex ) +// { +// for( let i = 0, len = insArray.length; i < len; i++ ) +// { +// if( _.longLike( insArray[ i ] ) ) +// onLongOnce( insArray[ i ], insIndex ) +// else if( _.longLeftIndex( dstArray, insArray[ i ] ) === -1 ) +// dstArray.splice( insIndex++, 0, insArray[ i ] ); +// } +// } +// } + +// + +function arrayFlattenedOnceStrictly( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result = 0; + let visited = []; + + _.assert( arguments.length && arguments.length <= 4 ); + _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + + let oldLength = dstArray.length; + _.arrayRemoveDuplicates( dstArray ); + let newLength = dstArray.length; + if( Config.debug ) + _.assert( oldLength === newLength, 'Elements in dstArray must not be repeated' ); + + if( arguments.length === 1 ) + { + for( let i = 0 ; i < dstArray.length ; i++ ) + { + let e = dstArray[ i ]; + if( _.longLike( e ) || _.set.like( e ) ) + { + dstArray.splice( i, 1 ); + if( e !== dstArray ) + i = containerReplace( e, i ); + i -= 1; + } + else + { + result += 1; + } + } + + return result; + } + + if( _.longHas( dstArray, dstArray ) ) + { + let i = _.longLeftIndex( dstArray, dstArray ); + + while( i !== -1 ) + { + dstArray.splice( i, 1 ); + i = _.longLeftIndex( dstArray, dstArray ); + } + } + + if( _.longLike( insArray ) || _.set.like( insArray ) ) + { + containerAppend( insArray ); + } + else if( _.longLeftIndex( dstArray, insArray, evaluator1, evaluator2 ) === -1 ) + { + _.assert( insArray !== undefined, 'The container should be no undefined' ); + + dstArray.push( insArray ); + result += 1; + } + else if( Config.debug ) + _.assert( 0, 'Elements must not be repeated' ); + + return result; + + /* */ + + function containerAppend( src ) + { + if( _.longHas( visited, src ) ) + return; + visited.push( src ); + + let count; + if( src === dstArray ) + count = oldLength; + else + count = src.length; + + + for( let e of src ) + { + if( count < 1 ) + break; + count--; + + _.assert( e !== undefined, 'The container should have no undefined' ); + + if( _.longLike( e ) || _.set.like( e ) ) + { + containerAppend( e ) + } + else if( _.longLeftIndex( dstArray, e, evaluator1, evaluator2 ) === -1 ) + { + dstArray.push( e ); + result += 1; + } + else if( Config.debug ) + _.assert( 0, 'Elements must not be repeated' ); + + } + + visited.pop(); + } + + /* */ + + function containerReplace( src, index ) + { + for( let e of src ) + { + if( _.longLike( e ) || _.set.like( e ) ) + { + index = containerReplace( e, index ); + } + else if( _.longLeftIndex( dstArray, e ) === -1 ) + { + dstArray.splice( index, 0, e ); + result += 1; + index += 1; + } + } + return index; + } + +} + +// function arrayFlattenedOnceStrictly( dstArray, insArray, evaluator1, evaluator2 ) +// { +// +// _.assert( arguments.length && arguments.length <= 4 ); +// _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); +// +// let oldLength = dstArray.length; +// _.arrayRemoveDuplicates( dstArray ); +// let newLength = dstArray.length; +// if( Config.debug ) +// _.assert( oldLength === newLength, 'Elements in dstArray must not be repeated' ); +// +// +// if( arguments.length === 1 ) +// { +// for( let i = dstArray.length-1; i >= 0; --i ) +// if( _.longLike( dstArray[ i ] ) ) +// { +// let insArray = dstArray[ i ]; +// dstArray.splice( i, 1 ); +// onLongOnce( insArray, i ); +// } +// return dstArray; +// } +// +// let result = 0; +// +// if( _.longLike( insArray ) ) +// { +// for( let i = 0, len = insArray.length; i < len; i++ ) +// { +// _.assert( insArray[ i ] !== undefined, 'The Array should have no undefined' ); +// if( _.longLike( insArray[ i ] ) ) +// { +// let c = _.arrayFlattenedOnceStrictly( dstArray, insArray[ i ], evaluator1, evaluator2 ); +// result += c; +// } +// else +// { +// let index = _.longLeftIndex( dstArray, insArray[ i ], evaluator1, evaluator2 ); +// if( Config.debug ) +// _.assert( index === -1, 'Elements must not be repeated' ); +// +// if( index === -1 ) +// { +// dstArray.push( insArray[ i ] ); +// result += 1; +// } +// } +// } +// } +// else +// { +// _.assert( insArray !== undefined, 'The Array should have no undefined' ); +// let index = _.longLeftIndex( dstArray, insArray, evaluator1, evaluator2 ); +// if( Config.debug ) +// _.assert( index === -1, 'Elements must not be repeated' ); +// +// if( index === -1 ) +// { +// dstArray.push( insArray ); +// result += 1; +// } +// } +// +// return result; +// +// /* */ +// +// function onLongOnce( insArray, insIndex ) +// { +// for( let i = 0, len = insArray.length; i < len; i++ ) +// { +// if( _.longLike( insArray[ i ] ) ) +// onLongOnce( insArray[ i ], insIndex ) +// else if( _.longLeftIndex( dstArray, insArray[ i ] ) === -1 ) +// dstArray.splice( insIndex++, 0, insArray[ i ] ); +// else if( Config.debug ) +// _.assert( _.longLeftIndex( dstArray, insArray[ i ] ) === -1, 'Elements must not be repeated' ); +// } +// } +// } + +// + +function arrayFlattenDefined( dstArray, insArray ) +{ + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + arrayFlattenedDefined.apply( this, arguments ); + + return dstArray; +} + +// + +function arrayFlattenDefinedOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + if( dstArray === null ) + { + dstArray = []; + arguments[ 0 ] = dstArray; + } + + arrayFlattenedDefinedOnce.apply( this, arguments ); + return dstArray; +} + +// + +function arrayFlattenDefinedOnceStrictly( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + arrayFlattenedDefinedOnceStrictly.apply( this, arguments ); + return dstArray; +} + +// + +function arrayFlattenedDefined( dstArray, src ) +{ + let result = 0; + let length = dstArray.length; + let visited = []; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.object.isBasic( this ) ); + _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + + if( arguments.length === 1 ) + { + for( let i = 0 ; i < dstArray.length ; i++ ) + { + let e = dstArray[ i ]; + + if( e === undefined ) + { + dstArray.splice( i, 1 ); + i -= 1; + } + else if( _.longLike( e ) || _.set.like( e ) ) + { + dstArray.splice( i, 1 ); + if( e !== dstArray ) + i = containerReplace( e, i ); + i -= 1; + } + else + { + result += 1; + } + } + + return result; + } + + if( _.longHas( dstArray, dstArray ) ) + { + let i = _.longLeftIndex( dstArray, dstArray ); + + while( i !== -1 ) + { + dstArray.splice( i, 1 ); + i = _.longLeftIndex( dstArray, dstArray ); + } + } + + if( _.longLike( src ) || _.set.like( src ) ) + { + containerAppend( src ); + } + else if( src !== undefined ) + { + dstArray.push( src ); + result += 1; + } + + return result; + + /* */ + + function containerAppend( src ) + { + if( _.longHas( visited, src ) ) + return; + visited.push( src ); + + let count; + if( src === dstArray ) + count = length; + else + count = src.length; + + for( let e of src ) + { + if( count < 1 ) + break; + count--; + + if( _.longLike( e ) || _.set.like( e ) ) + { + containerAppend( e ) + } + else + { + if( e !== undefined ) + { + dstArray.push( e ); + result += 1; + } + } + } + + visited.pop(); + } + + /* */ + + function containerReplace( src, index ) + { + for( let e of src ) + { + if( _.longLike( e ) || _.set.like( e ) ) + { + index = containerReplace( e, index ); + } + else + { + if( e !== undefined ) + { + dstArray.splice( index, 0, e ); + result += 1; + index += 1; + } + } + } + return index; + } + +} + +// function arrayFlattenedDefined( dstArray, insArray ) +// { +// +// _.assert( arguments.length >= 1 ); +// _.assert( _.object.isBasic( this ) ); +// _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); +// +// if( arguments.length === 1 ) +// { +// for( let i = dstArray.length-1; i >= 0; --i ) +// if( _.longLike( dstArray[ i ] ) ) +// { +// let insArray = dstArray[ i ]; +// dstArray.splice( i, 1 ); +// onLong( insArray, i ); +// } +// return dstArray; +// } +// +// let result = 0; +// +// for( let a = 1 ; a < arguments.length ; a++ ) +// { +// let insArray = arguments[ a ]; +// +// if( _.longLike( insArray ) ) +// { +// for( let i = 0, len = insArray.length; i < len; i++ ) +// { +// if( _.longLike( insArray[ i ] ) ) +// { +// let c = _.arrayFlattenedDefined( dstArray, insArray[ i ] ); +// result += c; +// } +// else +// { +// // _.assert( insArray[ i ] !== undefined, 'The Array should have no undefined' ); +// if( insArray[ i ] !== undefined ) +// { +// dstArray.push( insArray[ i ] ); +// result += 1; +// } +// } +// } +// } +// else +// { +// _.assert( insArray !== undefined, 'The Array should have no undefined' ); +// if( insArray !== undefined ) +// { +// dstArray.push( insArray ); +// result += 1; +// } +// } +// +// } +// +// return result; +// +// /* */ +// +// function onLong( insArray, insIndex ) +// { +// for( let i = 0, len = insArray.length; i < len; i++ ) +// { +// if( _.longLike( insArray[ i ] ) ) +// onLong( insArray[ i ], insIndex ) +// else +// dstArray.splice( insIndex++, 0, insArray[ i ] ); +// } +// } +// +// } + +// + +function arrayFlattenedDefinedOnce( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result = 0; + let length = dstArray.length; + let visited = []; + + _.assert( arguments.length && arguments.length <= 4 ); + _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + + if( arguments.length === 1 ) + { + _.arrayRemoveDuplicates( dstArray ); + + for( let i = 0 ; i < dstArray.length ; i++ ) + { + let e = dstArray[ i ]; + if( e === undefined ) + { + dstArray.splice( i, 1 ); + i -= 1; + } + else if( _.longLike( e ) || _.set.like( e ) ) + { + dstArray.splice( i, 1 ); + if( e !== dstArray ) + i = containerReplace( e, i ); + i -= 1; + } + else + { + result += 1; + } + } + + return result; + } + + if( _.longHas( dstArray, dstArray ) ) + { + let i = _.longLeftIndex( dstArray, dstArray ); + + while( i !== -1 ) + { + dstArray.splice( i, 1 ); + i = _.longLeftIndex( dstArray, dstArray ); + } + } + + if( _.longLike( insArray ) || _.set.like( insArray ) ) + { + containerAppend( insArray ); + } + else if( insArray !== undefined ) + { + if( _.longLeftIndex( dstArray, insArray, evaluator1, evaluator2 ) === -1) + { + dstArray.push( insArray ); + result += 1; + } + } + + return result; + + /* */ + + function containerAppend( src ) + { + if( _.longHas( visited, src ) ) + return; + visited.push( src ); + + let count; + if( src === dstArray ) + count = length; + else + count = src.length; + + + for( let e of src ) + { + if( count < 1 ) + break; + count--; + + if( _.longLike( e ) || _.set.like( e ) ) + { + containerAppend( e ) + } + else if( e !== undefined ) + { + if( _.longLeftIndex( dstArray, e, evaluator1, evaluator2 ) === -1 ) + { + dstArray.push( e ); + result += 1; + } + } + } + + visited.pop(); + } + + /* */ + + function containerReplace( src, index ) + { + for( let e of src ) + { + if( _.longLike( e ) || _.set.like( e ) ) + { + index = containerReplace( e, index ); + } + else if( e !== undefined ) + { + if( _.longLeftIndex( dstArray, e ) === -1 ) + { + dstArray.splice( index, 0, e ); + result += 1; + index += 1; + } + } + } + return index; + } +} + +// function arrayFlattenedDefinedOnce( dstArray, insArray, evaluator1, evaluator2 ) +// { +// +// _.assert( arguments.length && arguments.length <= 4 ); +// _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); +// +// if( arguments.length === 1 ) +// { +// _.arrayRemoveDuplicates( dstArray ); +// +// for( let i = dstArray.length-1; i >= 0; --i ) +// if( _.longLike( dstArray[ i ] ) ) +// { +// let insArray = dstArray[ i ]; +// dstArray.splice( i, 1 ); +// onLongOnce( insArray, i ); +// } +// return dstArray; +// } +// +// let result = 0; +// +// if( _.longLike( insArray ) ) +// { +// for( let i = 0, len = insArray.length; i < len; i++ ) +// { +// _.assert( insArray[ i ] !== undefined ); +// if( _.longLike( insArray[ i ] ) ) +// { +// let c = _.arrayFlattenedDefinedOnce( dstArray, insArray[ i ], evaluator1, evaluator2 ); +// result += c; +// } +// else +// { +// let index = _.longLeftIndex( dstArray, insArray[ i ], evaluator1, evaluator2 ); +// if( index === -1 ) +// { +// dstArray.push( insArray[ i ] ); +// result += 1; +// } +// } +// } +// } +// else if( insArray !== undefined ) +// { +// +// let index = _.longLeftIndex( dstArray, insArray, evaluator1, evaluator2 ); +// if( index === -1 ) +// { +// dstArray.push( insArray ); +// result += 1; +// } +// } +// +// return result; +// +// /* */ +// +// function onLongOnce( insArray, insIndex ) +// { +// for( let i = 0, len = insArray.length; i < len; i++ ) +// { +// if( _.longLike( insArray[ i ] ) ) +// onLongOnce( insArray[ i ], insIndex ) +// else if( _.longLeftIndex( dstArray, insArray[ i ] ) === -1 ) +// dstArray.splice( insIndex++, 0, insArray[ i ] ); +// } +// } +// +// } + +// + +function arrayFlattenedDefinedOnceStrictly( /* dstArray, insArray, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let insArray = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + let result = 0; + let visited = []; + + _.assert( arguments.length && arguments.length <= 4 ); + _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); + + let oldLength = dstArray.length; + _.arrayRemoveDuplicates( dstArray ); + let newLength = dstArray.length; + if( Config.debug ) + _.assert( oldLength === newLength, 'Elements in dstArray must not be repeated' ); + + if( arguments.length === 1 ) + { + for( let i = 0 ; i < dstArray.length ; i++ ) + { + let e = dstArray[ i ]; + if( e === undefined ) + { + dstArray.splice( i, 1 ); + i -= 1; + } + else if( _.longLike( e ) || _.set.like( e ) ) + { + dstArray.splice( i, 1 ); + if( e !== dstArray ) + i = containerReplace( e, i ); + i -= 1; + } + else + { + result += 1; + } + } + + return result; + } + + if( _.longHas( dstArray, dstArray ) ) + { + let i = _.longLeftIndex( dstArray, dstArray ); + + while( i !== -1 ) + { + dstArray.splice( i, 1 ); + i = _.longLeftIndex( dstArray, dstArray ); + } + } + + if( _.longLike( insArray ) || _.set.like( insArray ) ) + { + containerAppend( insArray ); + } + else if( insArray !== undefined ) + { + if( _.longLeftIndex( dstArray, insArray, evaluator1, evaluator2 ) === -1 ) + { + dstArray.push( insArray ); + result += 1; + } + else if( Config.debug ) + _.assert( 0, 'Elements must not be repeated' ); + } + + return result; + + /* */ + + function containerAppend( src ) + { + if( _.longHas( visited, src ) ) + return; + visited.push( src ); + + let count; + if( src === dstArray ) + count = oldLength; + else + count = src.length; + + + for( let e of src ) + { + if( count < 1 ) + break; + count--; + + if( _.longLike( e ) || _.set.like( e ) ) + { + containerAppend( e ) + } + else if( e !== undefined ) + { + if( _.longLeftIndex( dstArray, e, evaluator1, evaluator2 ) === -1 ) + { + dstArray.push( e ); + result += 1; + } + else if( Config.debug ) + _.assert( 0, 'Elements must not be repeated' ); + } + } + + visited.pop(); + } + + /* */ + + function containerReplace( src, index ) + { + for( let e of src ) + { + if( _.longLike( e ) || _.set.like( e ) ) + { + index = containerReplace( e, index ); + } + else if( e !== undefined ) + { + if( _.longLeftIndex( dstArray, e ) === -1 ) + { + dstArray.splice( index, 0, e ); + result += 1; + index += 1; + } + else if( Config.debug ) + _.assert( 0, 'Elements must not be repeated' ); + } + } + return index; + } + +} + +// function arrayFlattenedDefinedOnceStrictly( dstArray, insArray, evaluator1, evaluator2 ) +// { +// +// _.assert( arguments.length && arguments.length <= 4 ); +// _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); +// +// let oldLength = dstArray.length; +// _.arrayRemoveDuplicates( dstArray ); +// let newLength = dstArray.length; +// if( Config.debug ) +// _.assert( oldLength === newLength, 'Elements in dstArray must not be repeated' ); +// +// +// if( arguments.length === 1 ) +// { +// for( let i = dstArray.length-1; i >= 0; --i ) +// if( _.longLike( dstArray[ i ] ) ) +// { +// let insArray = dstArray[ i ]; +// dstArray.splice( i, 1 ); +// onLongOnce( insArray, i ); +// } +// return dstArray; +// } +// +// let result = 0; +// +// if( _.longLike( insArray ) ) +// { +// for( let i = 0, len = insArray.length; i < len; i++ ) +// { +// // _.assert( insArray[ i ] !== undefined ); +// if( insArray[ i ] === undefined ) +// { +// } +// else if( _.longLike( insArray[ i ] ) ) +// { +// let c = _.arrayFlattenedDefinedOnceStrictly( dstArray, insArray[ i ], evaluator1, evaluator2 ); +// result += c; +// } +// else +// { +// let index = _.longLeftIndex( dstArray, insArray[ i ], evaluator1, evaluator2 ); +// if( Config.debug ) +// _.assert( index === -1, 'Elements must not be repeated' ); +// if( index === -1 ) +// { +// dstArray.push( insArray[ i ] ); +// result += 1; +// } +// } +// } +// } +// else if( insArray !== undefined ) +// { +// +// let index = _.longLeftIndex( dstArray, insArray, evaluator1, evaluator2 ); +// if( Config.debug ) +// _.assert( index === -1, 'Elements must not be repeated' ); +// +// if( index === -1 ) +// { +// dstArray.push( insArray ); +// result += 1; +// } +// } +// +// return result; +// +// /* */ +// +// function onLongOnce( insArray, insIndex ) +// { +// for( let i = 0, len = insArray.length; i < len; i++ ) +// { +// if( _.longLike( insArray[ i ] ) ) +// onLongOnce( insArray[ i ], insIndex ) +// else if( _.longLeftIndex( dstArray, insArray[ i ] ) === -1 ) +// dstArray.splice( insIndex++, 0, insArray[ i ] ); +// else if( Config.debug ) +// _.assert( _.longLeftIndex( dstArray, insArray[ i ] ) === -1, 'Elements must not be repeated' ); +// } +// } +// } + +// -- +// array replace +// -- + +// + +function arrayReplace( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + _.assert( 3 <= arguments.length && arguments.length <= 5 ); + + let index = -1; + let result = 0; + + index = _.longLeftIndex( dstArray, ins, evaluator1, evaluator2 ); + + while( index !== -1 ) + { + dstArray.splice( index, 1, sub ); + result += 1; + index = _.longLeftIndex( dstArray, ins, evaluator1, evaluator2 ); + } + + return dstArray; +} + +/** + * The arrayReplaceOnce() routine returns the index of the (dstArray) array which will be replaced by (sub), + * if (dstArray) has the value (ins). + * + * It takes three arguments (dstArray, ins, sub), calls built in function(dstArray.indexOf(ins)), + * that looking for value (ins) in the (dstArray). + * If true, it replaces (ins) value of (dstArray) by (sub) and returns the index of the (ins). + * Otherwise, it returns (-1) index. + * + * @param { Array } dstArray - The source array. + * @param { * } ins - The value to find. + * @param { * } sub - The value to replace. + * + * @example + * _.arrayReplaceOnce( [ 2, 4, 6, 8, 10 ], 12, 14 ); + * // returns -1 + * + * @example + * _.arrayReplaceOnce( [ 1, undefined, 3, 4, 5 ], undefined, 2 ); + * // returns 1 + * + * @example + * _.arrayReplaceOnce( [ 'Petre', 'Mikle', 'Oleg', 'Dmitry' ], 'Dmitry', 'Bob' ); + * // returns 3 + * + * @example + * _.arrayReplaceOnce( [ true, true, true, true, false ], false, true ); + * // returns 4 + * + * @returns { number } Returns the index of the (dstArray) array which will be replaced by (sub), + * if (dstArray) has the value (ins). + * @function arrayReplaceOnce + * @throws { Error } Will throw an Error if (dstArray) is not an array. + * @throws { Error } Will throw an Error if (arguments.length) is less than three. + * @namespace Tools + */ + +function arrayReplaceOnce( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + arrayReplacedOnce.apply( this, arguments ); + return dstArray; +} + +// + +function arrayReplaceOnceStrictly( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + let result; + if( Config.debug ) + { + result = arrayReplacedOnce.apply( this, arguments ); + _.assert( result >= 0, () => 'Array does not have element ' + _.entity.exportStringDiagnosticShallow( ins ) ); + result = arrayReplacedOnce.apply( this, arguments ); + _.assert( result < 0, () => 'The element ' + _.entity.exportStringDiagnosticShallow( ins ) + 'is several times in dstArray' ); + } + else + { + result = arrayReplacedOnce.apply( this, arguments ); + } + return dstArray; +} + +/* +function arrayReplaceOnceStrictly( dstArray, ins, sub, evaluator1, evaluator2 ) +{ + let result = arrayReplacedOnce.apply( this, arguments ); + _.assert( result >= 0, () => 'Array does not have element ' + _.entity.exportStringDiagnosticShallow( ins ) ); + return dstArray; +} +*/ + +// + +function arrayReplaced( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + _.assert( 3 <= arguments.length && arguments.length <= 5 ); + + let index = -1; + let result = 0; + + index = _.longLeftIndex( dstArray, ins, evaluator1, evaluator2 ); + + while( index !== -1 ) + { + dstArray.splice( index, 1, sub ); + result += 1; + index = _.longLeftIndex( dstArray, ins, evaluator1, evaluator2 ); + } + + return result; +} + +// + +function arrayReplacedOnce( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + _.assert( 3 <= arguments.length && arguments.length <= 5 ); + + if( _.longLike( ins ) ) + { + _.assert( _.longLike( sub ) ); + _.assert( ins.length === sub.length ); + } + + let index = -1; + + index = _.longLeftIndex( dstArray, ins, evaluator1, evaluator2 ); + + if( index >= 0 ) + dstArray.splice( index, 1, sub ); + + return index; +} + +// + +function arrayReplacedOnceStrictly( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + let result; + if( Config.debug ) + { + result = arrayReplacedOnce.apply( this, arguments ); + _.assert( result >= 0, () => 'Array does not have element ' + _.entity.exportStringDiagnosticShallow( ins ) ); + let newResult = arrayReplacedOnce.apply( this, arguments ); + _.assert( newResult < 0, () => 'The element ' + _.entity.exportStringDiagnosticShallow( ins ) + 'is several times in dstArray' ); + } + else + { + result = arrayReplacedOnce.apply( this, arguments ); + } + + return result; +} + +// + +function arrayReplaceElement( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + _.assert( 3 <= arguments.length && arguments.length <= 5 ); + + let index = -1; + let result = 0; + + index = _.longLeftIndex( dstArray, ins, evaluator1, evaluator2 ); + + while( index !== -1 ) + { + dstArray.splice( index, 1, sub ); + result += 1; + index = _.longLeftIndex( dstArray, ins, evaluator1, evaluator2 ); + } + + return dstArray; +} + +// + +function arrayReplaceElementOnce( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + arrayReplacedElementOnce.apply( this, arguments ); + return dstArray; +} + +// + +function arrayReplaceElementOnceStrictly( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + let result; + if( Config.debug ) + { + result = arrayReplacedElementOnce.apply( this, arguments ); + _.assert( result !== undefined, () => 'Array does not have element ' + _.entity.exportStringDiagnosticShallow( ins ) ); + result = arrayReplacedElementOnce.apply( this, arguments ); + _.assert( result === undefined, () => 'The element ' + _.entity.exportStringDiagnosticShallow( ins ) + 'is several times in dstArray' ); + } + else + { + result = arrayReplacedElementOnce.apply( this, arguments ); + } + return dstArray; +} + +// + +function arrayReplacedElement( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + _.assert( 3 <= arguments.length && arguments.length <= 5 ); + + let index = -1; + let result = 0; + + index = _.longLeftIndex( dstArray, ins, evaluator1, evaluator2 ); + + while( index !== -1 ) + { + dstArray.splice( index, 1, sub ); + result += 1; + index = _.longLeftIndex( dstArray, ins, evaluator1, evaluator2 ); + } + + return result; +} + +// + +function arrayReplacedElementOnce( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + _.assert( 3 <= arguments.length && arguments.length <= 5 ); + + if( _.longLike( ins ) ) + { + _.assert( _.longLike( sub ) ); + _.assert( ins.length === sub.length ); + } + + let index = -1; + + index = _.longLeftIndex( dstArray, ins, evaluator1, evaluator2 ); + + if( index >= 0 ) + dstArray.splice( index, 1, sub ); + else + return undefined; + + return ins; +} + +// + +function arrayReplacedElementOnceStrictly( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + let result; + if( Config.debug ) + { + result = arrayReplacedElementOnce.apply( this, arguments ); + _.assert( result !== undefined, () => 'Array does not have element ' + _.entity.exportStringDiagnosticShallow( ins ) ); + let newResult = arrayReplacedElementOnce.apply( this, arguments ); + _.assert( newResult === undefined, () => 'The element ' + _.entity.exportStringDiagnosticShallow( ins ) + 'is several times in dstArray' ); + } + else + { + result = arrayReplacedElementOnce.apply( this, arguments ); + } + + return result; +} + +/* +function arrayReplacedOnceStrictly( dstArray, ins, sub, evaluator1, evaluator2 ) +{ + let result = arrayReplacedOnce.apply( this, arguments ); + _.assert( result >= 0, () => 'Array does not have element ' + _.entity.exportStringDiagnosticShallow( ins ) ); + return result; +} +*/ + +// + +function arrayReplaceArray( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + arrayReplacedArray.apply( this, arguments ); + return dstArray; +} + +// + +function arrayReplaceArrayOnce( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + arrayReplacedArrayOnce.apply( this, arguments ); + return dstArray; +} + +// + +function arrayReplaceArrayOnceStrictly( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + let result; + if( Config.debug ) + { + let insArrayLength = ins.length; + result = arrayReplacedArrayOnce.apply( this, arguments ); + _.assert( result === insArrayLength, '{-dstArray-} should have each element of {-insArray-}' ); + _.assert( insArrayLength === sub.length, '{-subArray-} should have the same length {-insArray-} has' ); + + if( dstArray === ins ) + return dstArray; + + let newResult = arrayReplacedArrayOnce.apply( this, arguments ); + + _.assert( newResult === 0, () => 'The element ' + _.entity.exportStringDiagnosticShallow( ins ) + 'is several times in dstArray' ); + } + else + { + result = arrayReplacedArrayOnce.apply( this, arguments ); + } + + return dstArray; +} + +/* +function arrayReplaceArrayOnceStrictly( dstArray, ins, sub, evaluator1, evaluator2 ) +{ + let result = arrayReplacedArrayOnce.apply( this, arguments ); + _.assert( result === ins.length, '{-dstArray-} should have each element of {-insArray-}' ); + _.assert( ins.length === sub.length, '{-subArray-} should have the same length {-insArray-} has' ); + return dstArray; +} +*/ + +// + +function arrayReplacedArray( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + _.assert( 3 <= arguments.length && arguments.length <= 5 ); + _.assert( _.longLike( ins ) ); + _.assert( _.longLike( sub ) ); + _.assert( ins.length === sub.length, '{-subArray-} should have the same length {-insArray-} has' ); + + let result = 0; + let index = -1; + // let oldDstArray = dstArray.slice(); // Array with src values stored + if( dstArray === ins ) + ins = ins.slice(); + + for( let i = 0, len = ins.length; i < len; i++ ) + { + // let dstArray2 = oldDstArray.slice(); // Array modified for each ins element + index = _.longLeftIndex( dstArray, ins[ i ], evaluator1, evaluator2 ); + while( index !== -1 ) + { + let subValue = sub[ i ]; + let insValue = ins[ i ]; + if( subValue === undefined ) + { + dstArray.splice( index, 1 ); + // dstArray2.splice( index, 1 ); + } + else + { + dstArray.splice( index, 1, subValue ); + // dstArray2.splice( index, 1, subValue ); + } + + result += 1; + + // if( dstArray === ins ) + // break; + + if( subValue === insValue ) + break; + + index = _.longLeftIndex( dstArray, insValue, evaluator1, evaluator2 ); + } + } + + return result; +} + +// + +function arrayReplacedArrayOnce( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + _.assert( _.longLike( ins ) ); + _.assert( _.longLike( sub ) ); + _.assert( ins.length === sub.length, '{-subArray-} should have the same length {-insArray-} has' ); + _.assert( 3 <= arguments.length && arguments.length <= 5 ); + + let index = -1; + let result = 0; + + //let oldDstArray = dstArray.slice(); // Array with src values stored + for( let i = 0, len = ins.length; i < len; i++ ) + { + index = _.longLeftIndex( dstArray, ins[ i ], evaluator1, evaluator2 ); + if( index >= 0 ) + { + let subValue = sub[ i ]; + if( subValue === undefined ) + dstArray.splice( index, 1 ); + else + dstArray.splice( index, 1, subValue ); + result += 1; + } + } + + return result; +} + +// + +function arrayReplacedArrayOnceStrictly( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + let result; + if( Config.debug ) + { + let insArrayLength = ins.length + result = arrayReplacedArrayOnce.apply( this, arguments ); + _.assert( result === insArrayLength, '{-dstArray-} should have each element of {-insArray-}' ); + _.assert( insArrayLength === sub.length, '{-subArray-} should have the same length {-insArray-} has' ); + + if( dstArray === ins ) + return result; + + let newResult = arrayReplacedArrayOnce.apply( this, arguments ); + _.assert( newResult === 0, () => 'One element of ' + _.entity.exportStringDiagnosticShallow( ins ) + 'is several times in dstArray' ); + } + else + { + result = arrayReplacedArrayOnce.apply( this, arguments ); + } + + return result; +} + +// + +function arrayReplaceArrays( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + arrayReplacedArrays.apply( this, arguments ); + return dstArray; +} + +// + +function arrayReplaceArraysOnce( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + arrayReplacedArraysOnce.apply( this, arguments ); + return dstArray; +} + +// + +function arrayReplaceArraysOnceStrictly( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + let result; + if( Config.debug ) + { + let expected = 0; + for( let i = ins.length - 1; i >= 0; i-- ) + { + if( _.longLike( ins[ i ] ) ) + expected += ins[ i ].length; + else + expected += 1; + } + + result = arrayReplacedArraysOnce.apply( this, arguments ); + + _.assert( result === expected, '{-dstArray-} should have each element of {-insArray-}' ); + _.assert( ins.length === sub.length, '{-subArray-} should have the same length {-insArray-} has' ); + + if( dstArray === ins ) + return dstArray; + + let newResult = arrayReplacedArrayOnce.apply( this, arguments ); + _.assert( newResult === 0, () => 'One element of ' + _.entity.exportStringDiagnosticShallow( ins ) + 'is several times in dstArray' ); + } + else + { + result = arrayReplacedArraysOnce.apply( this, arguments ); + } + + return dstArray; + +} + +// + +function arrayReplacedArrays( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + _.assert( 3 <= arguments.length && arguments.length <= 5 ); + _.assert( _.arrayIs( dstArray ), 'arrayReplacedArrays :', 'Expects array' ); + _.assert( _.longLike( sub ), 'arrayReplacedArrays :', 'Expects longLike entity' ); + _.assert( _.longLike( ins ), 'arrayReplacedArrays :', 'Expects longLike entity' ); + _.assert( ins.length === sub.length, '{-subArray-} should have the same length {-insArray-} has' ); + + let result = 0; + + function _replace( /* dstArray, argument, subValue, evaluator1, evaluator2 */ ) + { + let dstArray = arguments[ 0 ]; + let argument = arguments[ 1 ]; + let subValue = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + // let dstArray2 = oldDstArray.slice(); + //let index = dstArray.indexOf( argument ); + let index = _.longLeftIndex( dstArray, argument, evaluator1, evaluator2 ); + + while( index !== -1 ) + { + // dstArray2.splice( index, 1, subValue ); + dstArray.splice( index, 1, subValue ); + result += 1; + if( subValue === argument ) + break; + index = _.longLeftIndex( dstArray, argument, evaluator1, evaluator2 ); + } + } + + let insCopy = Object.create( null ); + let subCopy = Object.create( null ); + + if( dstArray === ins ) + { + ins = ins.slice(); + } + else + { + for( let i = ins.length - 1; i >= 0; i-- ) + { + if( _.longLike( ins[ i ] ) ) + if( ins[ i ] === dstArray ) + insCopy[ i ] = ins[ i ].slice(); + + if( _.longLike( sub[ i ] ) ) + if( sub[ i ] === dstArray ) + subCopy[ i ] = sub[ i ].slice(); + } + } + + for( let a = 0, len = ins.length; a < len; a++ ) + { + if( _.longLike( ins[ a ] ) ) + { + let insArray = insCopy[ a ] || ins[ a ]; + let subArray = sub[ a ] || subCopy[ a ]; + + for( let i = 0, len2 = insArray.length; i < len2; i++ ) + _replace( dstArray, insArray[ i ], subArray[ i ], evaluator1, evaluator2 ); + } + else + { + _replace( dstArray, ins[ a ], sub[ a ], evaluator1, evaluator2 ); + } + } + + return result; +} + +// + +function arrayReplacedArraysOnce( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + _.assert( 3 <= arguments.length && arguments.length <= 5 ); + _.assert( _.arrayIs( dstArray ), 'arrayReplacedArrays :', 'Expects array' ); + _.assert( _.longLike( sub ), 'arrayReplacedArrays :', 'Expects longLike entity' ); + _.assert( _.longLike( ins ), 'arrayReplacedArrays :', 'Expects longLike entity' ); + _.assert( ins.length === sub.length, '{-subArray-} should have the same length {-insArray-} has' ); + + let result = 0; + // let oldDstArray = dstArray.slice(); // Array with src values stored + + function _replace( /* dstArray, argument, subValue, evaluator1, evaluator2 */ ) + { + let dstArray = arguments[ 0 ]; + let argument = arguments[ 1 ]; + let subValue = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + // let dstArray2 = oldDstArray.slice(); + //let index = dstArray.indexOf( argument ); + // let index = _.longLeftIndex( dstArray2, argument, evaluator1, evaluator2 ); + let index = _.longLeftIndex( dstArray, argument, evaluator1, evaluator2 ); + + if( index !== -1 ) + { + // dstArray2.splice( index, 1, subValue ); + dstArray.splice( index, 1, subValue ); + result += 1; + } + } + + for( let a = 0, len = ins.length; a < len ; a++ ) + { + if( _.longLike( ins[ a ] ) ) + { + let insArray = ins[ a ]; + let subArray = sub[ a ]; + + for( let i = 0, len2 = insArray.length; i < len2; i++ ) + _replace( dstArray, insArray[ i ], subArray[ i ], evaluator1, evaluator2 ); + } + else + { + _replace( dstArray, ins[ a ], sub[ a ], evaluator1, evaluator2 ); + } + } + + return result; +} + +// + +function arrayReplacedArraysOnceStrictly( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + let result; + if( Config.debug ) + { + result = arrayReplacedArraysOnce.apply( this, arguments ); + + let expected = 0; + for( let i = ins.length - 1; i >= 0; i-- ) + { + if( _.longLike( ins[ i ] ) ) + expected += ins[ i ].length; + else + expected += 1; + } + + _.assert( result === expected, '{-dstArray-} should have each element of {-insArray-}' ); + _.assert( ins.length === sub.length, '{-subArray-} should have the same length {-insArray-} has' ); + + if( dstArray === ins ) + return result; + + let newResult = arrayReplacedArrayOnce.apply( this, arguments ); + _.assert( newResult === 0, () => 'The element ' + _.entity.exportStringDiagnosticShallow( ins ) + 'is several times in dstArray' ); + } + else + { + result = arrayReplacedArraysOnce.apply( this, arguments ); + } + + return result; + +} + +// + +/** + * The arrayUpdate() routine adds a value (sub) to an array (dstArray) or replaces a value (ins) of the array (dstArray) by (sub), + * and returns the last added index or the last replaced index of the array (dstArray). + * + * It creates the variable (index) assigns and calls to it the function(arrayReplaceOnce( dstArray, ins, sub ). + * [arrayReplaceOnce( dstArray, ins, sub )]{@link wTools.arrayReplaceOnce}. + * Checks if (index) equal to the -1. + * If true, it adds to an array (dstArray) a value (sub), and returns the last added index of the array (dstArray). + * Otherwise, it returns the replaced (index). + * + * @see wTools.arrayReplaceOnce + * + * @param { Array } dstArray - The source array. + * @param { * } ins - The value to change. + * @param { * } sub - The value to add or replace. + * + * @example + * let add = _.arrayUpdate( [ 'Petre', 'Mikle', 'Oleg' ], 'Dmitry', 'Dmitry' ); + * // returns 3 + * console.log( add ); + * // log [ 'Petre', 'Mikle', 'Oleg', 'Dmitry' ] + * + * @example + * let add = _.arrayUpdate( [ 1, 2, 3, 4, 5 ], 6, 6 ); + * // returns 5 + * console.log( add ); + * // log [ 1, 2, 3, 4, 5, 6 ] + * + * @example + * let replace = _.arrayUpdate( [ true, true, true, true, false ], false, true ); + * // returns 4 + * console.log( replace ); + * // log [ true, true true, true, true ] + * + * @returns { number } Returns the last added or the last replaced index. + * @function arrayUpdate + * @throws { Error } Will throw an Error if (dstArray) is not an array-like. + * @throws { Error } Will throw an Error if (arguments.length) is less or more than three. + * @namespace Tools + */ + +function arrayUpdate( /* dstArray, ins, sub, evaluator1, evaluator2 */ ) +{ + let dstArray = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let sub = arguments[ 2 ]; + let evaluator1 = arguments[ 3 ]; + let evaluator2 = arguments[ 4 ]; + + let index = arrayReplacedOnce.apply( this, arguments ); + + if( index === -1 ) + { + dstArray.push( sub ); + index = dstArray.length - 1; + } + + return index; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + + // array checker + + constructorLikeArray, + + arrayFromCoercing, /* aaa : check coverage */ /* Dmytro : coverage extended */ + arrayFromStr, + + // arrayAs, + // arrayAsShallowing, + + // array transformer + + // arraySlice, + // arrayEmpty, + arrayExtendAppending, + arrayExtendPrepending, + + arrayBut, + arrayButInplace, /* !!! : use instead of arrayBut, arrayButInplace */ + arrayBut_, /* qqq : for Dmytro : use in wTools */ + arrayShrink, + arrayShrinkInplace, /* !!! : use instead of arrayShrink, arrayShrinkInplace */ + arrayShrink_, /* qqq : for Dmytro : use in wTools */ + arrayGrow, + arrayGrowInplace, /* !!! : use instead of arrayGrow, arrayGrowInplace */ + arrayGrow_, /* qqq : for Dmytro : use in wTools */ + arrayRelength, + arrayRelengthInplace, /* !!! : use instead of arrayRelength, arrayRelengthInplace */ + arrayRelength_, /* qqq : for Dmytro : use in wTools */ + + // array prepend on l3 + + // array append on l3 + + // array remove + + arrayRemove, + arrayRemoveOnce, + arrayRemoveOnceStrictly, + arrayRemoved, + arrayRemovedOnce, + arrayRemovedOnceStrictly, + + arrayRemoveElement, + arrayRemoveElementOnce, + arrayRemoveElementOnceStrictly, + arrayRemovedElement, /* !!! : use instead of arrayRemovedElement */ + arrayRemovedElement_, + arrayRemovedElementOnce, /* !!! : use instead of arrayRemovedElementOnce */ + arrayRemovedElementOnce_, + arrayRemovedElementOnceStrictly, /* !!! : use instead of arrayRemovedElementOnceStrictly */ + arrayRemovedElementOnceStrictly_, + + arrayRemoveArray, + arrayRemoveArrayOnce, + arrayRemoveArrayOnceStrictly, + arrayRemovedArray, + arrayRemovedArrayOnce, + arrayRemovedArrayOnceStrictly, + + arrayRemoveArrays, + arrayRemoveArraysOnce, + arrayRemoveArraysOnceStrictly, + arrayRemovedArrays, + arrayRemovedArraysOnce, + arrayRemovedArraysOnceStrictly, + + arrayRemoveDuplicates, + + // array flatten + + arrayFlatten, + arrayFlattenOnce, + arrayFlattenOnceStrictly, + arrayFlattened, + arrayFlattenedOnce, + arrayFlattenedOnceStrictly, + + arrayFlattenDefined, + arrayFlattenDefinedOnce, + arrayFlattenDefinedOnceStrictly, + arrayFlattenedDefined, + arrayFlattenedDefinedOnce, + arrayFlattenedDefinedOnceStrictly, + + // array replace + + arrayReplace, + arrayReplaceOnce, + arrayReplaceOnceStrictly, + arrayReplaced, + arrayReplacedOnce, + arrayReplacedOnceStrictly, + + arrayReplaceElement, + arrayReplaceElementOnce, + arrayReplaceElementOnceStrictly, + arrayReplacedElement, + arrayReplacedElementOnce, + arrayReplacedElementOnceStrictly, + + arrayReplaceArray, + arrayReplaceArrayOnce, + arrayReplaceArrayOnceStrictly, + arrayReplacedArray, + arrayReplacedArrayOnce, + arrayReplacedArrayOnceStrictly, + + arrayReplaceArrays, + arrayReplaceArraysOnce, + arrayReplaceArraysOnceStrictly, + arrayReplacedArrays, + arrayReplacedArraysOnce, + arrayReplacedArraysOnceStrictly, + + arrayUpdate, + + // to replace + + /* + | routine | makes new dst container | saves dst container | + | ---------------- | ---------------------------------------- | ------------------------------------------------------- | + | arrayBut_ | _.arrayBut_( null, src, range ) | _.arrayBut_( src ) | + | | | _.arrayBut_( src, range ) | + | | | _.arrayBut_( dst, dst, range ) | + | | | _.arrayBut_( dst, src ) | + | | | _.arrayBut_( dst, src, range ) | + | --------------- | ---------------------------------------- | ------------------------------------------------------- | + | arrayShrink_ | _.arrayShrink_( null, src, range ) | _.arrayShrink_( src ) | + | | | _.arrayShrink_( src, range ) | + | | | _.arrayShrink_( dst, dst, range ) | + | | | _.arrayShrink_( dst, src ) | + | | | _.arrayShrink_( dst, src, range ) | + | --------------- | ---------------------------------------- | ------------------------------------------------------- | + | arrayGrow_ | _.arrayGrow_( null, src, range ) | _.arrayGrow_( src ) | + | | | _.arrayGrow_( src, range ) | + | | | _.arrayGrow_( dst, dst, range ) | + | | | _.arrayGrow_( dst, src ) | + | | | _.arrayGrow_( dst, src, range ) | + | --------------- | ---------------------------------------- | ------------------------------------------------------- | + | arrayRelength_ | _.arrayRelength_( null, src, range ) | _.arrayRelength_( src ) | + | | | _.arrayRelength_( src, range ) | + | | | _.arrayRelength_( dst, dst, range ) | + | | | _.arrayRelength_( dst, src ) | + | | | _.arrayRelength_( dst, src, range ) | + | ---------------- | ---------------------------------------- | ------------------------------------------------------- | + */ + +} + +_.props.supplement( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Array.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Array_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Array_s */ })(); + +/* */ /* begin of file ArraySet_s */ ( function ArraySet_s() { function ArraySet_s_naked() { ( function _l5_ArraySet_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.arraySet = _.arraySet || Object.create( null ); + +// -- +// array set +// -- + +// /** +// * Returns new array that contains difference between two arrays: ( src1 ) and ( src2 ). +// * If some element is present in both arrays, this element and all copies of it are ignored. +// * @param { longIs } src1 - source array; +// * @param { longIs} src2 - array to compare with ( src1 ). +// * +// * @example +// * _.arraySet.diff_( null, [ 1, 2, 3 ], [ 4, 5, 6 ] ); +// * // returns [ 1, 2, 3, 4, 5, 6 ] +// * +// * @example +// * _.arraySet.diff_( null, [ 1, 2, 4 ], [ 1, 3, 5 ] ); +// * // returns [ 2, 4, 3, 5 ] +// * +// * @returns { Array } Array with unique elements from both arrays. +// * @function arraySetDiff +// * @throws { Error } If arguments count is not 2. +// * @throws { Error } If one or both argument(s) are not longIs entities. +// * @namespace Tools +// */ +// +// function arraySetDiff( src1, src2 ) +// { +// let result = []; +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// _.assert( _.longIs( src1 ) ); +// _.assert( _.longIs( src2 ) ); +// +// for( let i = 0 ; i < src1.length ; i++ ) +// { +// if( src2.indexOf( src1[ i ] ) === -1 ) +// result.push( src1[ i ] ); +// } +// +// for( let i = 0 ; i < src2.length ; i++ ) +// { +// if( src1.indexOf( src2[ i ] ) === -1 ) +// result.push( src2[ i ] ); +// } +// +// return result; +// } + +// + +function _has( /* src, e, onEvaluate1, onEvaluate2 */ ) +{ + let src = arguments[ 0 ]; + let e = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + _.assert( onEvaluate2 === undefined || _.routine.is( onEvaluate2 ) ); + + let fromIndex = 0; + if( _.number.is( onEvaluate1 ) ) + { + fromIndex = onEvaluate1; + onEvaluate1 = onEvaluate2; + onEvaluate2 = undefined; + } + + if( _.routine.is( onEvaluate1 ) ) + { + if( onEvaluate1.length === 2 ) + { + _.assert( !onEvaluate2 ); + + for( let el of src ) + { + if( fromIndex === 0 ) + { + if( onEvaluate1( el, e ) ) + return true; + } + else + { + fromIndex -= 1; + } + } + + return false; + } + else if( onEvaluate1.length === 1 ) + { + _.assert( !onEvaluate2 || onEvaluate2.length === 1 ); + + if( onEvaluate2 ) + e = onEvaluate2( e ); + else + e = onEvaluate1( e ); + + for( let el of src ) + { + if( fromIndex === 0 ) + { + if( onEvaluate1( el ) === e ) + return true; + } + else + { + fromIndex -= 1; + } + } + + return false; + } + else _.assert( 0 ); + } + else if( onEvaluate1 === undefined || onEvaluate1 === null ) + { + if( _.longLike( src ) ) + return src.includes( e ); + else if( _.set.like( src ) ) + return src.has( e ); + } + else _.assert( 0 ); +} + +// + +/* qqq : for junior : should work +_.arraySet.diff_( null, hashMap1.keys(), hashMap2.keys() ) +*/ +/* qqq : reimplement. dst should be map. first discuss */ +function diff_( /* dst, src1, src2, onEvaluate1, onEvaluate2 */ ) +{ + let dst = arguments[ 0 ]; + let src1 = arguments[ 1 ]; + let src2 = arguments[ 2 ]; + let onEvaluate1 = arguments[ 3 ]; + let onEvaluate2 = arguments[ 4 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 5 ); + _.assert( _.longIs( dst ) || _.set.is( dst ) || dst === null ); + _.assert( _.longIs( src1 ) || _.set.is( src1 ) ); + _.assert( _.longIs( src2 ) || _.set.is( src2 ) || _.routine.is( src2 ) || src2 === undefined ); + + if( dst === null ) + dst = new src1.constructor(); + + if( _.routine.is( src2 ) || src2 === undefined ) + { + onEvaluate2 = onEvaluate1; + onEvaluate1 = src2; + src2 = src1; + src1 = dst; + } + + let temp = []; + if( dst === src1 ) + { + if( _.longLike( dst ) ) + { + for( let e of src2 ) + if( _.longLeftIndex( dst, e, onEvaluate1, onEvaluate2 ) === -1 ) + temp.push( e ); + for( let i = dst.length - 1; i >= 0; i-- ) + if( _has( src2, dst[ i ], onEvaluate1, onEvaluate2 ) ) + dst.splice( i, 1 ) + for( let i = 0; i < temp.length; i++ ) + dst.push( temp[ i ] ); + } + else if( _.set.like( dst ) ) + { + for( let e of src2 ) + if( !_has( dst, e, onEvaluate1, onEvaluate2 ) ) + temp.push( e ); + for( let e of dst ) + if( _has( src2, e, onEvaluate1, onEvaluate2 ) ) + dst.delete( e ); + for( let i = 0; i < temp.length; i++ ) + dst.add( temp[ i ] ); + } + } + else if( dst === src2 ) + { + if( _.longLike( dst ) ) + { + for( let e of src1 ) + if( _.longLeftIndex( dst, e, onEvaluate1, onEvaluate2 ) === -1 ) + temp.push( e ); + for( let i = dst.length - 1; i >= 0; i-- ) + if( _has( src1, dst[ i ], onEvaluate1, onEvaluate2 ) ) + dst.splice( i, 1 ) + for( let i = 0; i < temp.length; i++ ) + dst.push( temp[ i ] ); + } + else if( _.set.like( dst ) ) + { + for( let e of src1 ) + if( !_has( dst, e, onEvaluate1, onEvaluate2 ) ) + temp.push( e ); + for( let e of dst ) + if( _has( src1, e, onEvaluate1, onEvaluate2 ) ) + dst.delete( e ); + for( let i = 0; i < temp.length; i++ ) + dst.add( temp[ i ] ); + } + } + else + { + if( _.longLike( dst ) ) + { + for( let e of src1 ) + if( !_has( src2, e, onEvaluate1, onEvaluate2 ) ) + dst.push( e ); + for( let e of src2 ) + if( !_has( src1, e, onEvaluate1, onEvaluate2 ) ) + dst.push( e ); + } + else if( _.set.like( dst ) ) + { + for( let e of src1 ) + if( !_has( src2, e, onEvaluate1, onEvaluate2 ) ) + dst.add( e ); + for( let e of src2 ) + if( !_has( src1, e, onEvaluate1, onEvaluate2 ) ) + dst.add( e ); + } + } + + return dst; +} + +// // +// +// /** +// * Returns new array that contains elements from ( src ) that are not present in ( but ). +// * All copies of ignored element are ignored too. +// * @param { longIs } src - source array; +// * @param { longIs} but - array of elements to ignore. +// * +// * @example +// * _.arraySetBut( [ 1, 1, 1 ], [ 1 ] ); +// * // returns [] +// * +// * @example +// * _.arraySetBut( [ 1, 1, 2, 2, 3, 3 ], [ 1, 3 ] ); +// * // returns [ 2, 2 ] +// * +// * @returns { Array } Source array without elements from ( but ). +// * @function arraySetBut +// * @throws { Error } If arguments count is not 2. +// * @throws { Error } If one or both argument(s) are not longIs entities. +// * @namespace Tools +// */ +// +// function arraySetBut( dst ) +// { +// let args = _.longSlice( arguments ); +// +// if( dst === null ) +// if( args.length > 1 ) +// { +// dst = _.longSlice( args[ 1 ] ); +// args.splice( 1, 1 ); +// } +// else +// { +// return []; +// } +// +// args[ 0 ] = dst; +// +// _.assert( arguments.length >= 1, 'Expects at least one argument' ); +// for( let a = 0 ; a < args.length ; a++ ) +// _.assert( _.longIs( args[ a ] ) ); +// +// for( let i = dst.length-1 ; i >= 0 ; i-- ) +// { +// for( let a = 1 ; a < args.length ; a++ ) +// { +// let but = args[ a ]; +// if( but.indexOf( dst[ i ] ) !== -1 ) +// { +// dst.splice( i, 1 ); +// break; +// } +// } +// } +// +// return dst; +// } + +// + +function but_( /* dst, src1, src2, onEvaluate1, onEvaluate2 */ ) +{ + let dst = arguments[ 0 ]; + let src1 = arguments[ 1 ]; + let src2 = arguments[ 2 ]; + let onEvaluate1 = arguments[ 3 ]; + let onEvaluate2 = arguments[ 4 ]; + + if( arguments.length === 1 ) + { + if( dst === null ) + return []; + else if( _.longLike( dst ) || _.set.like( dst ) ) + return dst; + else + _.assert( 0 ); + } + + if( ( dst === null && _.routine.is( src2 ) ) || ( dst === null && src2 === undefined ) ) + { + if( _.longLike( src1 ) ) + return _.longSlice( src1 ) + else if( _.set.like( src1 ) ) + return new Set( src1 ) + _.assert( 0 ); + } + + _.assert( 2 <= arguments.length && arguments.length <= 5 ); + _.assert( _.longIs( dst ) || _.set.is( dst ) || dst === null ); + _.assert( _.longIs( src1 ) || _.set.is( src1 ) ); + _.assert( _.longIs( src2 ) || _.set.is( src2 ) || _.routine.is( src2 ) || src2 === undefined ); + + + if( dst === null ) + dst = new src1.constructor(); + + if( _.routine.is( src2 ) || src2 === undefined ) + { + onEvaluate2 = onEvaluate1; + onEvaluate1 = src2; + src2 = src1; + src1 = dst; + } + + if( dst === src1 ) + { + if( _.longLike( dst ) ) + { + for( let i = dst.length - 1; i >= 0; i-- ) + if( _has( src2, dst[ i ], onEvaluate1, onEvaluate2 ) ) + dst.splice( i, 1 ); + } + else if( _.set.like( dst ) ) + { + for( let e of dst ) + if( _has( src2, e, onEvaluate1, onEvaluate2 ) ) + dst.delete( e ); + } + } + else + { + if( _.longLike( dst ) ) + { + for( let e of src1 ) + if( !_has( src2, e, onEvaluate1, onEvaluate2 ) ) + dst.push( e ); + } + else if( _.set.like( dst ) ) + { + for( let e of src1 ) + if( !_has( src2, e, onEvaluate1, onEvaluate2 ) ) + dst.add( e ); + } + } + + return dst; +} + +// // +// +// /** +// * Returns array that contains elements from ( src ) that exists at least in one of arrays provided after first argument. +// * If element exists and it has copies, all copies of that element will be included into result array. +// * @param { longIs } src - source array; +// * @param { ...longIs } - sequence of arrays to compare with ( src ). +// * +// * @example +// * _.arraySetIntersection( [ 1, 2, 3 ], [ 1 ], [ 3 ] ); +// * // returns [ 1, 3 ] +// * +// * @example +// * _.arraySetIntersection( [ 1, 1, 2, 2, 3, 3 ], [ 1 ], [ 2 ], [ 3 ], [ 4 ] ); +// * // returns [ 1, 1, 2, 2, 3, 3 ] +// * +// * @returns { Array } Array with elements that are a part of at least one of the provided arrays. +// * @function arraySetIntersection +// * @throws { Error } If one of arguments is not an longIs entity. +// * @namespace Tools +// */ +// +// function arraySetIntersection( dst ) +// { +// +// let first = 1; +// if( dst === null ) +// if( arguments.length > 1 ) +// { +// dst = _.longSlice( arguments[ 1 ] ); +// first = 2; +// } +// else +// { +// return []; +// } +// +// _.assert( arguments.length >= 1, 'Expects at least one argument' ); +// _.assert( _.longIs( dst ) ); +// for( let a = 1 ; a < arguments.length ; a++ ) +// _.assert( _.longIs( arguments[ a ] ) ); +// +// for( let i = dst.length-1 ; i >= 0 ; i-- ) +// { +// +// for( let a = first ; a < arguments.length ; a++ ) +// { +// let ins = arguments[ a ]; +// if( ins.indexOf( dst[ i ] ) === -1 ) +// { +// dst.splice( i, 1 ); +// break; +// } +// } +// +// } +// +// return dst; +// } + +// + +function intersection_( /* dst, src1, src2, onEvaluate1, onEvaluate2 */ ) +{ + let dst = arguments[ 0 ]; + let src1 = arguments[ 1 ]; + let src2 = arguments[ 2 ]; + let onEvaluate1 = arguments[ 3 ]; + let onEvaluate2 = arguments[ 4 ]; + + if( arguments.length === 1 ) + { + if( dst === null ) + return []; + else if( _.longIs( dst ) || _.set.is( dst ) ) + return dst; + else + _.assert( 0 ); + } + if( ( dst === null && _.routine.is( src2 ) ) || ( dst === null && src2 === undefined ) ) + { + if( _.longIs( src1 ) ) + return _.longSlice( src1 ) + else if( _.set.is( src1 ) ) + return new Set( src1 ) + _.assert( 0 ); + } + + _.assert( 2 <= arguments.length && arguments.length <= 5 ); + _.assert( _.longIs( dst ) || _.set.is( dst ) || dst === null ); + _.assert( _.longIs( src1 ) || _.set.is( src1 ) ); + _.assert( _.longIs( src2 ) || _.set.is( src2 ) || _.routine.is( src2 ) || src2 === undefined ); + + + if( dst === null ) + dst = new src1.constructor(); + + if( _.routine.is( src2 ) || src2 === undefined ) + { + onEvaluate2 = onEvaluate1; + onEvaluate1 = src2; + src2 = src1; + src1 = dst; + } + + if( dst === src1 ) + { + if( _.longLike( dst ) ) + { + for( let i = dst.length - 1; i >= 0; i-- ) + if( !_has( src2, dst[ i ], onEvaluate1, onEvaluate2 ) ) + dst.splice( i, 1 ); + } + else if( _.set.like( dst ) ) + { + for( let e of dst ) + if( !_has( src2, e, onEvaluate1, onEvaluate2 ) ) + dst.delete( e ); + } + } + else + { + if( _.longLike( dst ) ) + { + for( let e of src1 ) + if( _has( src2, e, onEvaluate1, onEvaluate2 ) ) + dst.push( e ); + } + else if( _.set.like( dst ) ) + { + for( let e of src1 ) + if( _has( src2, e, onEvaluate1, onEvaluate2 ) ) + dst.add( e ); + } + } + + return dst; +} + +// // +// +// function arraySetUnion( dst ) +// { +// let args = _.longSlice( arguments ); +// +// if( dst === null ) +// if( arguments.length > 1 ) +// { +// dst = []; +// // dst = _.longSlice( args[ 1 ] ); +// // args.splice( 1, 1 ); +// } +// else +// { +// return []; +// } +// +// _.assert( arguments.length >= 1, 'Expects at least one argument' ); +// _.assert( _.longIs( dst ) ); +// for( let a = 1 ; a < args.length ; a++ ) +// _.assert( _.longIs( args[ a ] ) ); +// +// for( let a = 1 ; a < args.length ; a++ ) +// { +// let ins = args[ a ]; +// for( let i = 0 ; i < ins.length ; i++ ) +// { +// if( dst.indexOf( ins[ i ] ) === -1 ) +// dst.push( ins[ i ] ) +// } +// } +// +// return dst; +// } + +// + +function union_( /* dst, src1, src2, onEvaluate1, onEvaluate2 */ ) +{ + let dst = arguments[ 0 ]; + let src1 = arguments[ 1 ]; + let src2 = arguments[ 2 ]; + let onEvaluate1 = arguments[ 3 ]; + let onEvaluate2 = arguments[ 4 ]; + + if( arguments.length === 1 ) + { + if( dst === null ) + return []; + else if( _.longIs( dst ) || _.set.is( dst ) ) + return dst; + else + _.assert( 0 ); + } + + _.assert( 2 <= arguments.length && arguments.length <= 5 ); + _.assert( _.longIs( dst ) || _.set.is( dst ) || dst === null ); + _.assert( _.longIs( src1 ) || _.set.is( src1 ) ); + _.assert( _.longIs( src2 ) || _.set.is( src2 ) || _.routine.is( src2 ) || src2 === undefined ); + + + if( dst === null ) + dst = new src1.constructor(); + + if( _.routine.is( src2 ) || src2 === undefined ) + { + onEvaluate2 = onEvaluate1; + onEvaluate1 = src2; + src2 = src1; + src1 = dst; + } + + if( dst === src1 ) + { + if( _.longLike( dst ) ) + { + for( let e of src2 ) + if( !_has( dst, e, onEvaluate1, onEvaluate2 ) ) + dst.push( e ); + } + else if( _.set.like( dst ) ) + { + for( let e of src2 ) + if( !_has( dst, e, onEvaluate1, onEvaluate2 ) ) + dst.add( e ); + } + } + else if( dst === src2 ) + { + if( _.longLike( dst ) ) + { + for( let e of src1 ) + if( !_has( dst, e, onEvaluate1, onEvaluate2 ) ) + dst.push( e ); + } + else if( _.set.like( dst ) ) + { + for( let e of src1 ) + if( !_has( dst, e, onEvaluate1, onEvaluate2 ) ) + dst.add( e ); + } + } + else + { + if( _.longLike( dst ) ) + { + for( let e of src1 ) + if( !_has( dst, e, onEvaluate1, onEvaluate2 ) ) + dst.push( e ); + for( let e of src2 ) + if( !_has( dst, e, onEvaluate1, onEvaluate2 ) ) + dst.push( e ); + } + else if( _.set.like( dst ) ) + { + for( let e of src1 ) + if( !_has( dst, e, onEvaluate1, onEvaluate2 ) ) + dst.add( e ); + for( let e of src2 ) + if( !_has( dst, e, onEvaluate1, onEvaluate2 ) ) + dst.add( e ); + } + } + + return dst; +} + +// + +/* +function arraySetContainAll( src ) +{ + let result = []; + + _.assert( _.longIs( src ) ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + + _.assert( _.longIs( arguments[ a ] ) ); + + if( src.length > arguments[ a ].length ) + return false; + + for( let i = 0 ; i < src.length ; i++ ) + { + + throw _.err( 'Not tested' ); + if( arguments[ a ].indexOf( src[ i ] ) !== -1 ) + { + throw _.err( 'Not tested' ); + return false; + } + + } + + } + + return true; +} +*/ + +// // +// +// /** +// * The arraySetContainAll() routine returns true, if at least one of the following arrays (arguments[...]), +// * contains all the same values as in the {-srcMap-} array. +// * +// * @param { longIs } src - The source array. +// * @param { ...longIs } arguments[...] - The target array. +// * +// * @example +// * _.arraySetContainAll( [ 1, 'b', 'c', 4 ], [ 1, 2, 3, 4, 5, 'b', 'c' ] ); +// * // returns true +// * +// * @example +// * _.arraySetContainAll( [ 'abc', 'def', true, 26 ], [ 1, 2, 3, 4 ], [ 26, 'abc', 'def', true ] ); +// * // returns false +// * +// * @returns { boolean } Returns true, if at least one of the following arrays (arguments[...]), +// * contains all the same values as in the {-srcMap-} array. +// * If length of the {-srcMap-} is more than the next argument, it returns false. +// * Otherwise, it returns false. +// * @function arraySetContainAll +// * @throws { Error } Will throw an Error if {-srcMap-} is not an array-like. +// * @throws { Error } Will throw an Error if (arguments[...]) is not an array-like. +// * @namespace Tools +// */ +// +// function arraySetContainAll( src ) +// { +// _.assert( _.longIs( src ) ); +// for( let a = 1 ; a < arguments.length ; a++ ) +// _.assert( _.longIs( arguments[ a ] ) ); +// +// for( let a = 1 ; a < arguments.length ; a++ ) +// { +// let ins = arguments[ a ]; +// +// for( let i = 0 ; i < ins.length ; i++ ) +// { +// if( src.indexOf( ins[ i ] ) === -1 ) +// return false; +// } +// +// } +// +// return true; +// } + +// + +function containAll_( /* src1, src2, onEvaluate1, onEvaluate2 */ ) +{ + let src1 = arguments[ 0 ]; + let src2 = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + _.assert( _.arrayIs( src2 ) || _.set.is( src2 ) ); + + let result = true; + if( _.arrayIs( src1 ) ) + { + for( let e of src2 ) + if( _.longLeftIndex( src1, e, onEvaluate1, onEvaluate2 ) === -1 ) + result = false; + } + else if( _.set.is( src1 ) ) + { + let startFrom = 0; + if( _.number.is( onEvaluate1 ) ) + { + startFrom = onEvaluate1; + onEvaluate1 = onEvaluate2; + onEvaluate2 = undefined; + } + + if( !src1.size && ( src2.length || src2.size ) ) + return false; + + for( let e of src2 ) + { + if( result === false ) + { + break; + } + else + { + let from = startFrom; + result = undefined; + setElementsCheck( from, e ); + } + } + return result === undefined ? true : result; + } + else + { + _.assert( 0, '{-src1-} should be instance of Array or Set' ); + } + + return result; + + /* */ + + function setElementsCheck( from, e ) + { + for( let el of src1 ) + { + if( from === 0 ) + { + if( _.entity.equal( el, e, onEvaluate1, onEvaluate2 ) ) + { + result = true; + break; + } + else + { + result = false + } + } + else + { + from--; + } + } + } +} + +// // +// +// /** +// * The arraySetContainAny() routine returns true, if at least one of the following arrays (arguments[...]), +// * contains the first matching value from {-srcMap-}. +// * +// * @param { longIs } src - The source array. +// * @param { ...longIs } arguments[...] - The target array. +// * +// * @example +// * _.arraySetContainAny( [ 33, 4, 5, 'b', 'c' ], [ 1, 'b', 'c', 4 ], [ 33, 13, 3 ] ); +// * // returns true +// * +// * @example +// * _.arraySetContainAny( [ 'abc', 'def', true, 26 ], [ 1, 2, 3, 4 ], [ 26, 'abc', 'def', true ] ); +// * // returns true +// * +// * @example +// * _.arraySetContainAny( [ 1, 'b', 'c', 4 ], [ 3, 5, 'd', 'e' ], [ 'abc', 33, 7 ] ); +// * // returns false +// * +// * @returns { Boolean } Returns true, if at least one of the following arrays (arguments[...]), +// * contains the first matching value from {-srcMap-}. +// * Otherwise, it returns false. +// * @function arraySetContainAny +// * @throws { Error } Will throw an Error if {-srcMap-} is not an array-like. +// * @throws { Error } Will throw an Error if (arguments[...]) is not an array-like. +// * @namespace Tools +// */ +// +// function arraySetContainAny( src ) +// { +// _.assert( _.longIs( src ) ); +// for( let a = 1 ; a < arguments.length ; a++ ) +// _.assert( _.longIs( arguments[ a ] ) ); +// +// if( src.length === 0 ) +// return true; +// +// for( let a = 1 ; a < arguments.length ; a++ ) +// { +// let ins = arguments[ a ]; +// +// let i; +// for( i = 0 ; i < ins.length ; i++ ) +// { +// if( src.indexOf( ins[ i ] ) !== -1 ) +// break; +// } +// +// if( i === ins.length ) +// return false; +// +// } +// +// return true; +// } + +// + +function containAny_( /* src1, src2, onEvaluate1, onEvaluate2 */ ) +{ + let src1 = arguments[ 0 ]; + let src2 = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + _.assert( _.arrayIs( src2 ) || _.set.is( src2 ) ); + + if( _.arrayIs( src1 ) ) + { + for( let e of src2 ) + if( _.longLeftIndex( src1, e, onEvaluate1, onEvaluate2 ) !== -1 ) + return true; + } + else if( _.set.is( src1 ) ) + { + let startFrom = 0; + if( _.number.is( onEvaluate1 ) ) + { + startFrom = onEvaluate1; + onEvaluate1 = onEvaluate2; + onEvaluate2 = undefined; + } + + for( let e of src2 ) + { + let from = startFrom; + for( let el of src1 ) + { + if( from === 0 ) + { + if( _.entity.equal( el, e, onEvaluate1, onEvaluate2 ) ) + return true; + } + else + { + from--; + } + } + } + } + else + { + _.assert( 0, '{-src1-} should be instance of Array or Set' ); + } + + return false; +} + +// // +// +// function arraySetContainNone( src ) +// { +// _.assert( _.longIs( src ) ); +// +// for( let a = 1 ; a < arguments.length ; a++ ) +// { +// +// _.assert( _.longIs( arguments[ a ] ) ); +// +// for( let i = 0 ; i < src.length ; i++ ) +// { +// +// if( arguments[ a ].indexOf( src[ i ] ) !== -1 ) +// { +// return false; +// } +// +// } +// +// } +// +// return true; +// } + +// + +function containNone_( /* src1, src2, onEvaluate1, onEvaluate2 */ ) +{ + let src1 = arguments[ 0 ]; + let src2 = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + _.assert( _.arrayIs( src2 ) || _.set.is( src2 ) ); + + if( _.arrayIs( src1 ) ) + { + for( let e of src2 ) + if( _.longLeftIndex( src1, e, onEvaluate1, onEvaluate2 ) !== -1 ) + return false; + } + else if( _.set.is( src1 ) ) + { + let startFrom = 0; + if( _.number.is( onEvaluate1 ) ) + { + startFrom = onEvaluate1; + onEvaluate1 = onEvaluate2; + onEvaluate2 = undefined; + } + + for( let e of src2 ) + { + let from = startFrom; + for( let el of src1 ) + { + if( from === 0 ) + { + if( _.entity.equal( el, e, onEvaluate1, onEvaluate2 ) ) + return false; + } + else + { + from--; + } + } + } + } + else + { + _.assert( 0, '{-src1-} should be instance of Array or Set' ); + } + + return true; +} + +// + +function containSetsAll( /* src1, src2, onEvaluate1, onEvaluate2 */ ) +{ + let src1 = arguments[ 0 ]; + let src2 = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + _.assert( _.arrayIs( src1 ) || _.set.is( src1 ) ); + _.assert( _.arrayIs( src2 ) || _.set.is( src2 ) ); + + for( let e of src2 ) + if( containAll_( src1, e, onEvaluate1, onEvaluate2 ) === false ) + return false; + + return true; +} + +// + +function containSetsAny( /* src1, src2, onEvaluate1, onEvaluate2 */ ) +{ + let src1 = arguments[ 0 ]; + let src2 = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + _.assert( _.arrayIs( src1 ) || _.set.is( src1 ) ); + _.assert( _.arrayIs( src2 ) || _.set.is( src2 ) ); + + for( let e of src2 ) + if( containAny_( src1, e, onEvaluate1, onEvaluate2 ) === true ) + return true; + + return false; +} + +// + +function containSetsNone( /* src1, src2, onEvaluate1, onEvaluate2 */ ) +{ + let src1 = arguments[ 0 ]; + let src2 = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + _.assert( _.arrayIs( src1 ) || _.set.is( src1 ) ); + _.assert( _.arrayIs( src2 ) || _.set.is( src2 ) ); + + for( let e of src2 ) + if( containNone_( src1, e, onEvaluate1, onEvaluate2 ) === false ) + return false; + + return true; +} + +// + +/** + * Returns true if ( ins1 ) and ( ins2) arrays have same length and elements, elements order doesn't matter. + * Inner arrays of arguments are not compared and result of such combination will be false. + * @param { longIs } ins1 - source array; + * @param { longIs} ins2 - array to compare with. + * + * @example + * _.arraySet.identical( [ 1, 2, 3 ], [ 4, 5, 6 ] ); + * // returns false + * + * @example + * _.arraySet.identical( [ 1, 2, 4 ], [ 4, 2, 1 ] ); + * // returns true + * + * @returns { Boolean } Result of comparison as boolean. + * @function identical + * @throws { Error } If one of arguments is not an ArrayLike entity. + * @throws { Error } If arguments length is not 2. + * @namespace Tools + */ + +function identical( ins1, ins2 ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.longIs( ins1 ) ); + _.assert( _.longIs( ins2 ) ); + + if( ins1.length !== ins2.length ) + return false; + + let result = _.arraySet.diff_( null, ins1, ins2 ); + + return result.length === 0; +} + +// + +function left( /* arr, ins, fromIndex, onEvaluate1, onEvaluate2 */ ) +{ + let arr = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let fromIndex = arguments[ 2 ]; + let onEvaluate1 = arguments[ 3 ]; + let onEvaluate2 = arguments[ 4 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 5 ); + + if( _.set.like( arr ) ) + { + let result = Object.create( null ); + result.index = -1; + let index = 0; + let from = 0; + + if( _.routine.is( fromIndex ) ) + { + onEvaluate2 = onEvaluate1; + onEvaluate1 = fromIndex; + } + else if( _.number.is( fromIndex ) ) + { + from = fromIndex; + } + + for( let e of arr ) + { + if( from === 0 ) + { + if( _.entity.equal( e, ins, onEvaluate1, onEvaluate2 ) ) + { + result.index = index; + result.element = e; + break; + } + } + else + { + from--; + } + index++; + } + + return result; + } + else if( _.longLike( arr ) ) + { + return _.longLeft.apply( this, arguments ); + } + else + _.assert( 0 ); + +} + +// + +function right( /* arr, ins, fromIndex, onEvaluate1, onEvaluate2 */ ) +{ + let arr = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let fromIndex = arguments[ 2 ]; + let onEvaluate1 = arguments[ 3 ]; + let onEvaluate2 = arguments[ 4 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 5 ); + + if( _.set.like( arr ) ) + { + let result = Object.create( null ); + result.index = -1; + let to = arr.size; + let index = 0; + + if( _.routine.is( fromIndex ) ) + { + onEvaluate2 = onEvaluate1; + onEvaluate1 = fromIndex; + } + else if( _.number.is( fromIndex ) ) + { + to = fromIndex; + } + else if( fromIndex !== undefined ) + _.assert( 0 ); + + for( let e of arr ) + { + if( index < to ) + { + if( _.entity.equal( e, ins, onEvaluate1, onEvaluate2 ) ) + { + result.index = index; + result.element = e; + } + } + index += 1; + } + + return result; + } + else if( _.longLike( arr ) ) + { + return _.longRight.apply( this, arguments ); + } + else + _.assert( 0 ); + +} + +// -- +// implementation +// -- + +let ToolsExtension = +{ + + // array set + + // arraySetDiff, /* !!! : use instead of arraySetDiff */ + arraySetDiff_ : diff_, + // arraySetBut, /* !!! : use instead of arraySetBut */ + arraySetBut_ : but_, + // arraySetIntersection, /* !!! : use instead of arraySetIntersection */ + arraySetIntersection_ : intersection_, + // arraySetUnion, /* !!! : use instead of arraySetUnion */ + arraySetUnion_ : union_, + + // arraySetContainAll, /* !!! : use instead of arraySetContainAll */ + arraySetContainAll_ : containAll_, + // arraySetContainAny, /* !!! : use instead of arraySetContainAny */ + arraySetContainAny_ : containAny_, + // arraySetContainNone, /* !!! : use instead of arraySetContainNone */ + arraySetContainNone_ : containNone_, + arraySetContainSetsAll : containSetsAll, + arraySetContainSetsAny : containSetsAny, + arraySetContainSetsNone : containSetsNone, + arraySetIdentical : identical, + + arraySetLeft : left, + arraySetRight : right, + + // to replace + + /* + | routine | makes new dst container | saves dst container | + | ----------------------- | --------------------------------------------- | --------------------------------------------- | + | arraySetDiff_ | _.arraySet.diff_( null ) | _.arraySet.diff_( src1, src2 ) | + | | _.arraySet.diff_( null, src1 ) | _.arraySet.diff_( src1, src1, src2 ) | + | | _.arraySet.diff_( null, src1, src2 ) | _.arraySet.diff_( src2, src1, src2 ) | + | | | _.arraySet.diff_( dst, src1, src2 ) | + | ----------------------- | --------------------------------------------- | --------------------------------------------- | + | arraySetBut_ | _.arraySet.but_( null ) | _.arraySet.but_( src1 ) | + | | _.arraySet.but_( null, src1 ) | _.arraySet.but_( src1, src2 ) | + | | _.arraySet.but_( null, src1, src2 ) | _.arraySet.but_( src1, src1, src2 ) | + | | | _.arraySet.but_( src2, src1, src2 ) | + | | | _.arraySet.but_( dst, src1, src2 ) | + | ----------------------- | --------------------------------------------- | --------------------------------------------- | + | arraySetIntersection_ | _.arraySet.intersection_( null ) | _.arraySet.intersection_( src1 ) | + | | _.arraySet.intersection_( null, src1 ) | _.arraySet.intersection_( src1, src2 ) | + | | _.arraySet.intersection_( null, src1, src2 ) | _.arraySet.intersection_( src1, src1, src2 ) | + | | | _.arraySet.intersection_( src2, src1, src2 ) | + | | | _.arraySet.intersection_( dst, src1, src2 ) | + | ----------------------- | --------------------------------------------- | --------------------------------------------- | + | arraySetUnion_ | _.arraySet.union_( null ) | _.arraySet.union_( src1 ) | + | | _.arraySet.union_( null, src1 ) | _.arraySet.union_( src1, src2 ) | + | | _.arraySet.union_( null, src1, src2 ) | _.arraySet.union_( src1, src1, src2 ) | + | | | _.arraySet.union_( src2, src1, src2 ) | + | | | _.arraySet.union_( dst, src1, src2 ) | + | ----------------------- | --------------------------------------------- | --------------------------------------------- | + + */ + +} + +// + +let Extension = +{ + + // array set + + // arraySetDiff, /* !!! : use instead of arraySetDiff */ + diff_, + // arraySetBut, /* !!! : use instead of arraySetBut */ + but_, + // arraySetIntersection, /* !!! : use instead of arraySetIntersection */ + intersection_, + // arraySetUnion, /* !!! : use instead of arraySetUnion */ + union_, + + // arraySetContainAll, /* !!! : use instead of arraySetContainAll */ + containAll_, + // arraySetContainAny, /* !!! : use instead of arraySetContainAny */ + containAny_, + // arraySetContainNone, /* !!! : use instead of arraySetContainNone */ + containNone_, + containSetsAll, + containSetsAny, + containSetsNone, + identical, + + left, + right, + + // to replace + +} + +Object.assign( Self, Extension ); +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/ArraySet.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ArraySet_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ArraySet_s */ })(); + +/* */ /* begin of file Auxiliary_s */ ( function Auxiliary_s() { function Auxiliary_s_naked() { ( function _l5_Auxiliary_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// extension +// -- + +var AuxiliaryExtension = +{ + +} + +Object.assign( _.aux, AuxiliaryExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Auxiliary.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Auxiliary_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Auxiliary_s */ })(); + +/* */ /* begin of file BigInt_s */ ( function BigInt_s() { function BigInt_s_naked() { ( function _l5_BigInt_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +function from( src ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + if( _.strIs( src ) ) + return BigInt( src ); + if( _.number.is( src ) ) + return BigInt( src ); + _.assert( _.bigInt.is( src ), 'Cant convert' ) + return src; +} + +// + +function bigIntsFrom( src ) +{ + if( _.number.is( src ) ) + { + return BigInt( src ); + } + else if( _.bigInt.is( src ) ) + { + return src; + } + else if( _.longIs( src ) ) + { + let result = []; + for( let i = 0 ; i < src.length ; i++ ) + result[ i ] = _.bigInt.from( src[ i ] ); + return result + } + else _.assert( 0, 'Cant convert' ); +} + +// -- +// bigInt extension +// -- + +let BigIntExtension = +{ + from, +} + +Object.assign( _.bigInt, BigIntExtension ); + +// -- +// bigInts extension +// -- + +let BigIntsExtension = +{ + from : bigIntsFrom +} + +Object.assign( _.bigInts, BigIntsExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + bigIntFrom : from, + bigIntsFrom, +} + +Object.assign( _, ToolsExtension ); + +// + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/BigInt.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, BigInt_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file BigInt_s */ })(); + +/* */ /* begin of file Blank_s */ ( function Blank_s() { function Blank_s_naked() { ( function _l5_Blank_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +// + +let BlankExtension = +{ + +} + +Object.assign( _.blank, BlankExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Blank.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Blank_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Blank_s */ })(); + +/* */ /* begin of file Bool_s */ ( function Bool_s() { function Bool_s_naked() { ( function _l5_Bool_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// bool +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +// + +let BoolExtension = +{ +} + +Object.assign( _.bool, BoolExtension ); + +// + +let BoolsExtension = +{ +} + +Object.assign( _.bool.s, BoolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Bool.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Bool_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Bool_s */ })(); + +/* */ /* begin of file Buffer_s */ ( function Buffer_s() { function Buffer_s_naked() { ( function _l5_Buffer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// buffer checker +// -- + +// -- +// extension +// -- + +let BufferExtension = +{ +} + +Object.assign( _.buffer, BufferExtension ); + +// + +let ToolsExtension = +{ +} + +_.props.supplement( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Buffer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Buffer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Buffer_s */ })(); + +/* */ /* begin of file Constructible_s */ ( function Constructible_s() { function Constructible_s_naked() { ( function _l5_Constructible_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.constructible = _.constructible || Object.create( null ); + +// -- +// dichotomy +// -- + +// -- +// extension +// -- + +let Extension = +{ +} + +// + +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Constructible.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Constructible_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Constructible_s */ })(); + +/* */ /* begin of file Container_s */ ( function Container_s() { function Container_s_naked() { ( function _l5_Container_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// extension +// -- + +let ContainerExtension = +{ + +} + +_.props.supplement( _.container, ContainerExtension ); + +// + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Container.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Container_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Container_s */ })(); + +/* */ /* begin of file Countable_s */ ( function Countable_s() { function Countable_s_naked() { ( function _l5_Countable_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// +// -- + +// -- +// extension +// -- + +var Extension = +{ +} + +// + +Object.assign( _.countable, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Countable.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Countable_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Countable_s */ })(); + +/* */ /* begin of file Ct_s */ ( function Ct_s() { function Ct_s_naked() { ( function _l5_Ct_s_() +{ + +'use strict'; + +// + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// extension +// -- + +let Extension = +{ +} + +_.props.supplement( _.ct, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Ct.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Ct_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Ct_s */ })(); + +/* */ /* begin of file Date_s */ ( function Date_s() { function Date_s_naked() { ( function _l5_Date_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.date = _.date || Object.create( null ); + +// -- +// dichotomy +// -- + +/** + * The routine dateToStr() converts Date object {-date-} to formatted string. + * The format is : YYYY.MM.DD + * + * @example + * let date = new Date(); + * console.log( _.time.dateToStr( date ) ); + * // log : '2020.10.20' + * + * @param { Date } date - The date to convert. + * @returns { String } - Returns date in string format. + * @function dateToStr + * @namespace wTools.time + * @extends Tools + */ + +function toStr( date ) +{ + debugger; + let y = date.getFullYear(); + let m = date.getMonth() + 1; + let d = date.getDate(); + if( m < 10 ) m = '0' + m; + if( d < 10 ) d = '0' + d; + let result = [ y, m, d ].join( '.' ); + return result; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + dateToStr : toStr +} + +// + +let Extension = +{ + toStr, +} + +// + +Object.assign( _, ToolsExtension ); +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Date.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Date_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Date_s */ })(); + +/* */ /* begin of file Diagnostic_s */ ( function Diagnostic_s() { function Diagnostic_s_naked() { ( function _l5_Diagnostic_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.diagnostic = _.diagnostic || Object.create( null ); + +// -- +// diagnostic +// -- + +// -- +// try +// -- + +function tryCatch( routine ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.routine.is( routine ) ) + try + { + return routine(); + } + catch( err ) + { + throw _._err({ args : [ err ] }); + } +} + +// + +function tryCatchBrief( routine ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.routine.is( routine ) ) + + try + { + return routine(); + } + catch( err ) + { + throw _._err({ args : [ err ], brief : 1 }); + } +} + +// // +// +// function tryCatchDebug( routine ) +// { +// _.assert( arguments.length === 1 ); +// _.assert( _.routine.is( routine ) ) +// try +// { +// return routine(); +// } +// catch( err ) +// { +// throw _._err({ args : [ err ], debugging : 1 }); +// } +// } + +// -- +// declare +// -- + +let ToolsExtension = +{ + + tryCatch, + tryCatchBrief, + +} + +Object.assign( _, ToolsExtension ); + +// + +let Extension = +{ + +} + +// + +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Diagnostic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Diagnostic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Diagnostic_s */ })(); + +/* */ /* begin of file Entity_s */ ( function Entity_s() { function Entity_s_naked() { ( function _l5_Entity_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// exporter +// -- + +function exportStringDiagnosticShallow( src, opts ) +{ + let result = ''; + _.assert( arguments.length === 1 || arguments.length === 2 ); + result = _.entity.exportStringDiagnosticShallow( src ); + return result; +} + +// + +/* xxx : qqq : for junior : take into account throwing cases */ +/* qqq : for junior : optimize. ask how to */ +function _exportStringShallow( src, o ) +{ + + _.assert( arguments.length === 2 ); + _.assert( _.number.is( o.widthLimit ) && o.widthLimit >= 0 ); + _.assert( _.number.is( o.heightLimit ) && o.heightLimit >= 0 ); + _.assert( o.src === undefined ) + _.assert( o.format === 'string.diagnostic' || o.format === 'string.code' ); + + let result = ''; + let method = o.format === 'string.diagnostic' ? 'exportStringDiagnosticShallow' : 'exportStringCodeShallow'; + + try + { + + let namespace = this.namespaceForExporting( src ); + if( namespace === null ) + { + _.assert( 0, 'not tested' ); + namespace = _.blank; + } + + result = namespace[ method ]( src ); + result = _.strShort_({ src : result, widthLimit : o.widthLimit, heightLimit : o.heightLimit }).result; + + } + catch( err ) + { + debugger; + throw err; + } + + return result; +} + +_exportStringShallow.defaults = +{ + format : null, + widthLimit : 0, + heightLimit : 0, +} + +// + +function exportStringCodeShallow( src, o ) /* */ +{ + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects one or two arguments' ); + + o = _.routine.options_( exportStringCodeShallow, o || null ); + o.format = o.format || exportStringCodeShallow.defaults.format; + + return _.entity._exportStringShallow( src, o ); +} + +exportStringCodeShallow.defaults = +{ + format : 'string.code', /* [ 'string.diagnostic', 'string.code' ] */ /* qqq for junior : implement and cover */ + widthLimit : 0, /* qqq for junior : implement and cover, use strShort_ */ + heightLimit : 0, /* qqq for junior : implement and cover */ +} + +// + +function exportStringDiagnosticShallow( src, o ) /* */ +{ + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects one or two arguments' ); + o = _.aux.supplement( o || null, exportStringDiagnosticShallow.defaults ); + o.format = o.format || exportStringDiagnosticShallow.defaults.format; + return _.entity._exportStringShallow( src, o ); +} + +exportStringDiagnosticShallow.defaults = +{ + format : 'string.diagnostic', /* [ 'string.diagnostic', 'string.code' ] */ /* qqq for junior : implement and cover */ + widthLimit : 0, /* qqq for junior : implement and cover, use strShort_ */ + heightLimit : 0, /* qqq for junior : implement and cover */ +} + +// -- +// +// -- + +function cloneDeep( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( !src || _.primitive.is( src ) ) + { + return src; + } + else if( _.replicate ) + { + debugger; + return _.replicate({ src }); + } + else if( _.routine.is( src[ _.class.cloneDeepSymbol ] ) ) /* aaa2 : cover */ /* Dmytro : coverage extended for objects with method under symbol cloneShallowSymbol */ + { + return src[ _.class.cloneDeepSymbol ](); + } + else if( _.routine.is( src.cloneDeep ) ) /* aaa2 : cover */ /* Dmytro : coverage extended for objects with method cloneShallow */ + { + return src.cloneDeep(); + } + else if( _.arrayIs( src ) ) + { + return Array.from( src ); + } + else if( _.longLike( src ) ) + { + let toolsNamespace = this.Tools ? this.Tools : this; + return toolsNamespace.long.make( src ); + } + else if( _.hashMap.like( src ) || _.set.like( src ) ) + { + return new src.constructor( src ); + } + else if( _.aux.is( src ) ) + { + return _.aux.cloneShallow( src ); + } + else if( _.routine.is( src.constructor ) ) /* aaa2 : cover */ /* Dmytro : coverage extended for entities with constructor */ + { + return new src.constructor( src ); + } + else _.assert( 0, `Not clear how to make a new element of \`${_.entity.strType( src )}\` with \`_.entity.cloneDeep()\`` ); + +} + +// + +/** + * Copies entity( src ) into( dst ) or returns own copy of( src ).Result depends on several moments: + * -If( src ) is a Object - returns clone of( src ) using ( onRecursive ) callback function if its provided; + * -If( dst ) has own 'copy' routine - copies( src ) into( dst ) using this routine; + * -If( dst ) has own 'set' routine - sets the fields of( dst ) using( src ) passed to( dst.set ); + * -If( src ) has own 'clone' routine - returns clone of( src ) using ( src.clone ) routine; + * -If( src ) has own 'slice' routine - returns result of( src.slice ) call; + * -Else returns a copy of entity( src ). + * + * @param {object} dst - Destination object. + * @param {object} src - Source object. + * @param {routine} onRecursive - The callback function to copy each [ key, value ]. + * @see {@link wTools.mapCloneAssigning} Check this function for more info about( onRecursive ) callback. + * @returns {object} Returns result of entities copy operation. + * + * @example + * let dst = { set : function( src ) { this.str = src.src } }; + * let src = { src : 'string' }; + * _.entity.assign2( dst, src ); + * console.log( dst.str ) + * // log "string" + * + * @example + * let dst = { copy : function( src ) { for( let i in src ) this[ i ] = src[ i ] } } + * let src = { src : 'string', num : 123 } + * _._.entity.assign2( dst, src ); + * console.log( dst ) + * // log Object { src: "string", num: 123 } + * + * @example + * _._.entity.assign2( null, new String( 'string' ) ); + * // returns 'string' + * + * @function assign + * @throws {exception} If( arguments.length ) is not equal to 3 or 2. + * @throws {exception} If( onRecursive ) is not a Routine. + * @namespace Tools.entity + * + */ + +function assign2( dst, src, onRecursive ) +{ + let result; + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( arguments.length < 3 || _.routine.is( onRecursive ) ); + + if( src === null ) + { + + result = src; + + } + else if( dst && _.routine.is( dst.copy ) ) + { + + dst.copy( src ); + + } + else if( src && _.routine.is( src.clone ) ) + { + + if( dst instanceof src.constructor ) + { + throw _.err( 'not tested' ); + result = src.clone( dst ); + } + else if( _.primitive.is( dst ) || _.longIs( dst ) ) + { + result = src.clone(); + } + else _.assert( 0, 'unknown' ); + + } + else if( src && _.routine.is( src.slice ) ) + { + + result = src.slice(); + + } + else if( dst && _.routine.is( dst.set ) ) + { + + dst.set( src ); + + } + else if( _.object.isBasic( src ) ) + { + + if( onRecursive ) + { + result = _.mapCloneAssigning + ({ + srcMap : src, + dstMap : _.primitive.is( dst ) ? Object.create( null ) : dst, + onField : onRecursive + }); + } + else + { + result = _.mapCloneAssigning({ srcMap : src }); + } + + } + else + { + + result = src; + + } + + return result; +} + +// + +/** + * Short-cut for _.entity.assign2 function. Copies specified( name ) field from + * source container( srcContainer ) into( dstContainer ). + * + * @param {object} dstContainer - Destination object. + * @param {object} srcContainer - Source object. + * @param {string} name - Field name. + * @param {mapCloneAssigning.onField} onRecursive - The callback function to copy each [ key, value ]. + * @see {@link wTools.mapCloneAssigning} Check this function for more info about( onRecursive ) callback. + * @returns {object} Returns result of entities copy operation. + * + * @example + * let dst = {}; + * let src = { a : 'string' }; + * let name = 'a'; + * _.entity.assign2FieldFromContainer( dst, src, name ); + * console.log( dst.a === src.a ); + * // log true + * + * @example + * let dst = {}; + * let src = { a : 'string' }; + * let name = 'a'; + * function onRecursive( dstContainer, srcContainer, key ) + * { + * _.assert( _.strIs( key ) ); + * dstContainer[ key ] = srcContainer[ key ]; + * }; + * _.entity.assign2FieldFromContainer( dst, src, name, onRecursive ); + * console.log( dst.a === src.a ); + * // log true + * + * @function assignFieldFromContainer + * @throws {exception} If( arguments.length ) is not equal to 3 or 4. + * @namespace Tools.entity + * + */ + +function assign2FieldFromContainer( /* dstContainer, srcContainer, name, onRecursive */ ) +{ + let dstContainer = arguments[ 0 ]; + let srcContainer = arguments[ 1 ]; + let name = arguments[ 2 ]; + let onRecursive = arguments[ 3 ]; + let result; + + _.assert( _.strIs( name ) || _.symbol.is( name ) ); + _.assert( arguments.length === 3 || arguments.length === 4 ); + + let dstValue = Object.hasOwnProperty.call( dstContainer, name ) ? dstContainer[ name ] : undefined; + let srcValue = srcContainer[ name ]; + + if( onRecursive ) + result = _.entity.assign2( dstValue, srcValue, onRecursive ); + else + result = _.entity.assign2( dstValue, srcValue ); + + if( result !== undefined ) + dstContainer[ name ] = result; + + return result; +} + +// + +/** + * Short-cut for _.entity.assign2 function. Assigns value of( srcValue ) to container( dstContainer ) field specified by( name ). + * + * @param {object} dstContainer - Destination object. + * @param {object} srcValue - Source value. + * @param {string} name - Field name. + * @param {mapCloneAssigning.onField} onRecursive - The callback function to copy each [ key, value ]. + * @see {@link wTools.mapCloneAssigning} Check this function for more info about( onRecursive ) callback. + * @returns {object} Returns result of entity field assignment operation. + * + * @example + * let dstContainer = { a : 1 }; + * let srcValue = 15; + * let name = 'a'; + * _.entity.assign2Field( dstContainer, srcValue, name ); + * console.log( dstContainer.a ); + * // log 15 + * + * @function assignField + * @throws {exception} If( arguments.length ) is not equal to 3 or 4. + * @namespace Tools + * + */ + +function assign2Field( /* dstContainer, srcValue, name, onRecursive */ ) +{ + let dstContainer = arguments[ 0 ]; + let srcValue = arguments[ 1 ]; + let name = arguments[ 2 ]; + let onRecursive = arguments[ 3 ]; + + let result; + + _.assert( _.strIs( name ) || _.symbol.is( name ) ); + _.assert( arguments.length === 3 || arguments.length === 4 ); + + let dstValue = dstContainer[ name ]; + + if( onRecursive ) + { + throw _.err( 'not tested' ); + result = _.entity.assign2( dstValue, srcValue, onRecursive ); + } + else + { + result = _.entity.assign2( dstValue, srcValue ); + } + + if( result !== undefined ) + dstContainer[ name ] = result; + + return result; +} + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + +} + +// + +Object.assign( _, ToolsExtension ); + +// -- +// entity extension +// -- + +let EntityExtension = +{ + + // exporter + + exportStringDiagnosticShallow, + + _exportStringShallow, + exportString : exportStringDiagnosticShallow, + exportStringCodeShallow, + exportStringDiagnosticShallow, + + // etc + + cloneDeep, + + assign2, /* xxx : refactor */ + assign2FieldFromContainer, /* dubious */ + assign2Field, /* dubious */ + +} + +// + +Object.assign( _.entity, EntityExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Entity.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Entity_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Entity_s */ })(); + +/* */ /* begin of file Err_s */ ( function Err_s() { function Err_s_naked() { ( function _l5_Err_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// extension +// -- + +let Extension = +{ +} + +Object.assign( _.error, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Err.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Err_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Err_s */ })(); + +/* */ /* begin of file Escape_s */ ( function Escape_s() { function Escape_s_naked() { ( function _l5_Escape_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// extension +// -- + +var Extension = +{ +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Escape.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Escape_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Escape_s */ })(); + +/* */ /* begin of file Event_s */ ( function Event_s() { function Event_s_naked() { ( function _l5_Event_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// extension +// -- + +let Extension = +{ +} + +Object.assign( _.event, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Event.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Event_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Event_s */ })(); + +/* */ /* begin of file Functional_s */ ( function Functional_s() { function Functional_s_naked() { ( function _l5_Functional_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// scalar +// -- + +/** + * Produce a single array from all arguments if cant return single argument as a scalar. + * If {-scalarAppend-} gets a single argument it returns the argument as is. + * If {-scalarAppend-} gets an argument and one or more undefined it returns the argument as is. + * If {-scalarAppend-} gets more than one or less than one defined arguments then it returns array having all defined arguments. + * If some argument is a Long ( for example array ) then each element of the Long is treated as an argument, not recursively. + * + * @function scalarAppend. + * @namespace Tools + */ + +function scalarAppend( dst, src ) +{ + + _.assert( arguments.length === 2 ); + + if( dst === undefined ) + { + if( _.longIs( src ) ) + { + dst = []; + } + else + { + if( src === undefined ) + return []; + else + return src; + } + } + + if( _.longIs( dst ) ) + { + + if( !_.arrayIs( dst ) ) + dst = _.array.from( dst ); + + if( src === undefined ) + {} + else if( _.longIs( src ) ) + _.arrayAppendArray( dst, src ); + else + dst.push( src ); + + } + else + { + + if( src === undefined ) + {} + else if( _.longIs( src ) ) + dst = _.arrayAppendArray( [ dst ], src ); + else + dst = [ dst, src ]; + + } + + return dst; +} + +// + +function scalarAppendOnce( dst, src ) +{ + + _.assert( arguments.length === 2 ); + + if( dst === undefined ) + { + if( _.longIs( src ) ) + { + dst = []; + } + else + { + if( src === undefined ) + return []; + else + return src; + } + } + + if( _.longIs( dst ) ) + { + + if( !_.arrayIs( dst ) ) + dst = _.array.from( dst ); + + if( src === undefined ) + {} + else if( _.longIs( src ) ) + _.arrayAppendArrayOnce( dst, src ); + else + _.arrayAppendElementOnce( dst, src ); + + } + else + { + + if( src === undefined ) + {} + else if( _.longIs( src ) ) + dst = _.arrayAppendArrayOnce( [ dst ], src ); + else + dst = _.arrayAppendElementOnce( [ dst ], src ); + + } + + return dst; +} + +// + +function scalarPrepend( dst, src ) +{ + + _.assert( arguments.length === 2 ); + + if( dst === undefined ) + { + if( _.longIs( src ) ) + { + dst = []; + } + else + { + if( src === undefined ) + return []; + else + return src; + } + } + + if( _.longIs( dst ) ) + { + + if( !_.arrayIs( dst ) ) + dst = _.array.from( dst ); + + if( src === undefined ) + {} + else if( _.longIs( src ) ) + _.arrayPrependArray( dst, src ); + else + dst.splice( 0, 0, src ); + + } + else + { + + if( src === undefined ) + {} + else if( _.longIs( src ) ) + dst = _.arrayPrependArray( [ dst ], src ); + else + dst = [ src, dst ]; + + } + + return dst; +} + +// + +function scalarPrependOnce( dst, src ) +{ + + _.assert( arguments.length === 2 ); + + if( dst === undefined ) + { + if( _.longIs( src ) ) + { + dst = []; + } + else + { + if( src === undefined ) + return []; + else + return src; + } + } + + if( _.longIs( dst ) ) + { + + if( !_.arrayIs( dst ) ) + dst = _.array.from( dst ); + + if( src === undefined ) + {} + else if( _.longIs( src ) ) + _.arrayPrependArrayOnce( dst, src ); + else + _.arrayPrependElementOnce( dst, src ); + + } + else + { + + if( src === undefined ) + {} + else if( _.longIs( src ) ) + dst = _.arrayPrependArrayOnce( [ dst ], src ); + else + dst = _.arrayPrependElementOnce( [ dst ], src ); + + } + + return dst; +} + +/** + * The scalarToVector() routine returns a new array + * which containing the static elements only type of Number. + * + * It takes two arguments (dst) and (length) + * checks if the (dst) is a Number, If the (length) is greater than or equal to zero. + * If true, it returns the new array of static (dst) numbers. + * Otherwise, if the first argument (dst) is an Array, + * and its (dst.length) is equal to the (length), + * it returns the original (dst) Array. + * Otherwise, it throws an Error. + * + * @param { ( Number | Array ) } dst - A number or an Array. + * @param { Number } length - The length of the new array. + * + * @example + * _.scalarToVector( 3, 7 ); + * // returns [ 3, 3, 3, 3, 3, 3, 3 ] + * + * @example + * _.scalarToVector( [ 3, 7, 13 ], 3 ); + * // returns [ 3, 7, 13 ] + * + * @returns { Number[] | Array } - Returns the new array of static numbers or the original array. + * @function scalarToVector + * @throws { Error } If missed argument, or got less or more than two arguments. + * @throws { Error } If type of the first argument is not a number or array. + * @throws { Error } If the second argument is less than 0. + * @throws { Error } If (dst.length) is not equal to the (length). + * @namespace Tools + */ + +// function arrayFromNumber( dst, length ) +function scalarToVector( dst, length ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + // _.assert( _.number.is( dst ) || _.arrayIs( dst ), 'Expects array of number as argument' ); + _.assert( dst !== undefined, 'Expects array or scalar' ); + _.assert( length >= 0 ); + + if( _.arrayIs( dst ) ) + { + _.assert( dst.length === length, () => 'Expects array of length ' + length + ' but got ' + dst.length ); + } + else + { + dst = _.longFill( [], dst, [ 0, length ] ); + } + + return dst; +} + +// + +function scalarFrom( src ) +{ + if( _.longIs( src ) && src.length === 1 ) + return src[ 0 ]; + return src; +} + +// + +function scalarFromOrNull( src ) +{ + if( _.longIs( src ) ) + { + if( src.length === 1 ) + return src[ 0 ]; + else if( src.length === 0 ) + return null; + } + return src; +} + +// -- +// multiplier +// -- + +function dup( ins, times, result ) +{ + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.number.is( times ) || _.longIs( times ), 'dup expects times as number or array' ); + + if( _.number.is( times ) ) + { + if( !result ) + result = new Array( times ); + for( let t = 0 ; t < times ; t++ ) + result[ t ] = ins; + return result; + } + else if( _.longIs( times ) ) + { + _.assert( times.length === 2 ); + let l = times[ 1 ] - times[ 0 ]; + if( !result ) + result = new Array( times[ 1 ] ); + for( let t = 0 ; t < l ; t++ ) + result[ times[ 0 ] + t ] = ins; + return result; + } + else _.assert( 0, 'unexpected' ); + +} + +// + +function multiple( src, times ) +{ + _.assert( arguments.length === 2 ); + if( _.argumentsArray.like( src ) ) + _.assert( src.length === times, () => 'Vector should have ' + times + ' elements, but have ' + src.length ); + else + src = _.dup( src, times ); + return src; +} + +// + +function multipleAll( dsts ) +{ + let length; + + _.assert( arguments.length === 1 ); + + for( let d = 0 ; d < dsts.length ; d++ ) + if( _.arrayIs( dsts[ d ] ) ) + { + length = dsts[ d ].length; + break; + } + + if( length === undefined ) + return dsts; + + for( let d = 0 ; d < dsts.length ; d++ ) + dsts[ d ] = _.multiple( dsts[ d ], length ); + + return dsts; +} + +// -- +// entity iterator +// -- + +function entityEach( src, onEach ) +{ + + _.assert( arguments.length === 2 ); + _.assert( onEach.length <= 3 ); + _.assert( _.routine.is( onEach ) ); + + /* */ + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) ) + { + + for( let k = 0 ; k < src.length ; k++ ) + { + onEach( src[ k ], k, src ); + } + + } + else if( _.aux.is( src ) ) + { + + for( let k in src ) + { + onEach( src[ k ], k, src ); + } + + } + else + { + onEach( src, undefined, undefined ); + } + + /* */ + + return src; +} + +// + +function entityEachOwn( src, onEach ) +{ + + _.assert( arguments.length === 2 ); + _.assert( onEach.length <= 3 ); + _.assert( _.routine.is( onEach ) ); + + /* */ + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) ) + { + + for( let k = 0 ; k < src.length ; k++ ) + { + onEach( src[ k ], k, src ); + } + + } + else if( _.aux.is( src ) || _.object.like( src ) ) + { + + for( let k in src ) + { + if( !Object.hasOwnProperty.call( src, k ) ) + continue; + onEach( src[ k ], k, src ); + } + + } + else + { + onEach( src, undefined, undefined ); + } + + /* */ + + return src; +} + +// + +/* + +LongLike / Aux / HashMapLike / SetLike + + +_.only( Array::dst, Map::src ); +_.only( Array::dst, Set::src ); + +*/ + +/** + * The routine entityOnly() provides the filtering of elements of destination container + * {-dst-} by checking values in the source container {-src-}. The routine checks values + * with the same keys in both containers. If a received {-src-} element has falsy value, then + * element with the same key deletes from the {-dst-} container. + * + * If {-dst-} container is null, routine makes new container with type of {-src-} container, and fill it obtained values. + * If {-src-} is undefined, routine filters {-dst-} container obtaining values from {-dst-}. + * Note: containers should have same type. + * + * Also, {-dst-} and {-src-} might be not iteratable element, for example, primitive. + * If {-dst-} is not iteratable, then routine check value of {-src-}. + * + * @param { ArrayLike|Set|Map|Object|* } dst - Container or another single element for filtering. + * If {-dst-} is null, then makes new container of {-src-} type. + * @param { ArrayLike|Set|Map|Object|* } src - Container or another single element for filtering. + * If {-src-} is undefined, then {-dst-} filters by its own values. + * @param { Function } onEach - The callback that obtain value for every {-src-} element. The + * callback accepts three parameters - element, key, source container. + * + * @example + * _.entityOnly( 'str', 1 ); + * // returns 'str' + * + * @example + * _.entityOnly( 'str', 1, ( e, k, src ) => e - 1 ); + * // returns undefined + * + * @example + * let src = [ 1, 0, null, undefined, true ]; + * _.entityOnly( null, src ); + * // returns [ 1, true ] + * + * @example + * let src = [ 1, 0, null, undefined, true ]; + * _.entityOnly( null, src, ( e, k ) => k ); + * // returns [ 0, null, undefined, true ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * _.entityOnly( dst ); + * // returns [ true ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * _.entityOnly( dst, undefined, ( e, k ) => k ); + * // returns [ 0, null, undefined, true ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * let src = [ 1, 2, false, undefined, 0 ]; + * _.entityOnly( dst, src ); + * // returns [ '', 0, true ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * let src = [ 1, 2, false, undefined, 0 ]; + * _.entityOnly( dst, undefined, ( e, k ) => k ); + * // returns [ 0, null, undefined, true ] + * + * @returns { ArrayLike|Set|Map|Object|* } - Returns filtered container. + * If {-dst-} is not iteratable value, routine returns original {-dst-} or undefined. + * @function entityOnly + * @throws { Error } If arguments.length is less then one or more than three arguments. + * @throws { Error } If {-dst-} is not null or {-dst-} and {-src-} containers has different types. + * @throws { Error } If {-onEach-} is not undefined, not a routine, not selector. + * @throws { Error } If onEach.length is more then three. + * @throws { Error } If {-onEach-} is selector and it does not begin with '*\/'. + * @namespace Tools + */ + +function entityOnly( dst, src, onEach ) +{ + + if( arguments.length > 2 ) + onEach = arguments[ arguments.length-1 ]; + + if( src === undefined ) + src = dst; + + if( _.strIs( onEach ) ) + { + let selector = onEach; + /* xxx : qqq : for Dmytro : fix that. ask how to */ + _.assert( _.routine.is( _.select ) ); + _.assert( _.strBegins( selector, '*/' ), () => `Selector should begins with "*/", but "${selector}" does not` ); + selector = _.strRemoveBegin( selector, '*/' ); + onEach = function( e, k ) + { + return _.select( e, selector ); + } + } + + let dstTypeStr = typeStr( dst ); + let srcTypeStr = typeStr( src ); + + _.assert( dst === null || dstTypeStr === srcTypeStr ); + _.assert( arguments.length === 1 || arguments.length === 2 || arguments.length === 3 ); + _.assert( onEach === undefined || ( _.routine.is( onEach ) && onEach.length <= 3 ), 'Expects optional routine or selector {- onEach -}' ); + + /* */ + + /* + + let srcHas = null; + if ... + srcHas = srcHasMap; + else ... + srcHas = srcHasSet; + + */ + + /* */ + + if( dst === null ) + { + if( _.routine.is( onEach ) ) + { + if( srcTypeStr === 'set' ) + setWithRoutine(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithRoutine(); + else + withRoutine(); + } + else + { + if( srcTypeStr === 'set' ) + setWithoutRoutine(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithoutRoutine(); + else + withoutRoutine(); /* don't change the subroutine */ + } + } + else + { + if( _.routine.is( onEach ) ) + { + if( srcTypeStr === 'set' ) + setWithRoutineDeleting(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithRoutineDeleting(); + else + withRoutineDeleting(); + } + else + { + if( srcTypeStr === 'set' ) + setWithoutRoutineDeleting(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithoutRoutineDeleting(); + else + withoutRoutineDeleting(); + } + } + + /* */ + + return dst; + + /* */ + + function setWithRoutine() + { + dst = new Set( src ); + + for( let value of src ) + { + let res = onEach( value, undefined, src ); + if( !res ) + dst.delete( value ); + } + } + + /* */ + + function setWithoutRoutine() + { + dst = new Set( src ); + + let unnecessaries = [ null, 0, undefined, false, '' ]; + for( let key of unnecessaries ) + if( dst.has( key ) ) + dst.delete( key ); + } + + /* */ + + function hashMapWithRoutine() + { + dst = new HashMap( src ); + + for( let [ key, value ] of src ) + { + let res = onEach( value, key, src ); + if( !res ) + dst.delete( key ); + } + } + + /* */ + + function hashMapWithoutRoutine() + { + dst = new HashMap( src ); + + for( let [ key, value ] of dst ) + if( !value ) + dst.delete( key ); + } + + /* */ + + function withRoutine() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) ) + { + + dst = []; + for( let k = 0 ; k < src.length ; k++ ) + { + let res = onEach( src[ k ], k, src ); + if( res ) + dst.push( src[ k ] ); + } + + } + else if( _.aux.is( src ) ) + { + + dst = Object.create( null ); + for( let k in src ) + { + let res = onEach( src[ k ], k, src ); + if( res ) + dst[ k ] = src[ k ]; + } + + } + else + { + let res = onEach( src, undefined, undefined ); + if( res ) + dst = src; + else + dst = undefined; + } + + } + + /* */ + + function withoutRoutine() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) ) + { + + dst = []; + for( let k = 0 ; k < src.length ; k++ ) + { + let res = src[ k ]; + if( res ) + dst.push( src[ k ] ); + } + + } + else if( _.aux.is( src ) ) + { + + dst = Object.create( null ); + for( let k in src ) + { + let res = src[ k ]; + if( res ) + dst[ k ] = src[ k ]; + } + + } + else + { + let res = src; + if( res ) + dst = res; + else + dst = undefined; + } + + } + + /* */ + + function setWithRoutineDeleting() + { + for( let value of src ) + { + let res = onEach( value, undefined, src ); + if( !res ) + dst.delete( value ); + } + } + + /* */ + + function setWithoutRoutineDeleting() + { + let unnecessaries = [ null, 0, undefined, false, '' ]; + for( let key of unnecessaries ) + { + if( src.has( key ) ) + dst.delete( key ); + } + } + + /* */ + + function hashMapWithRoutineDeleting() + { + for( let [ key, value ] of src ) + { + let res = onEach( value, key, src ) + if( !res ) + dst.delete( key ); + } + } + + /* */ + + function hashMapWithoutRoutineDeleting() + { + for( let [ key, value ] of src ) + if( !value ) + dst.delete( key ); + } + + /* */ + + function withRoutineDeleting() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( dst ) ) + { + + for( let k = dst.length - 1; k >= 0; k-- ) + { + let res = onEach( src[ k ], k, src ); + if( !res ) + dst.splice( k, 1 ); + } + + } + else if( _.aux.is( dst ) ) + { + + for( let k in dst ) + { + let res = onEach( src[ k ], k, src ); + if( !res ) + delete dst[ k ]; + } + + } + else + { + let res = onEach( src, undefined, undefined ); + if( !res ) + dst = undefined; + } + + } + + /* */ + + function withoutRoutineDeleting() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( dst ) ) + { + + for( let k = dst.length - 1; k >= 0; k-- ) + { + let res = src[ k ]; + if( !res ) + dst.splice( k, 1 ); + } + } + else if( _.aux.is( dst ) ) + { + + for( let k in dst ) + { + let res = src[ k ]; + if( !res ) + delete dst[ k ]; + } + + } + else + { + let res = src; + if( !res ) + dst = undefined; + } + + } + + function typeStr( e ) + { + let type; + if( _.longIs( e ) ) + type = 'long'; + else if( _.aux.is( e ) ) + type = 'map'; + else if( _.set.is( e ) ) + type = 'set'; + else if( _.hashMap.is( e ) ) + type = 'hashMap'; + else + type = 'primitive'; + + return type; + } + +} + +// + +/** + * The routine entityBut() provides the filtering of elements of destination container + * {-dst-} by checking values in the source container {-src-}. The routine checks values + * with the same keys in both containers. If a received {-src-} element has not falsy value, then + * element with the same key deletes from the {-dst-} container. + * + * If {-dst-} container is null, routine makes new container with type of {-src-} container, and fill it obtained values. + * If {-src-} is undefined, routine filters {-dst-} container obtaining values from {-dst-}. + * Note: containers should have same type. + * + * Also, {-dst-} and {-src-} might be not iteratable element, for example, primitive. + * If {-dst-} is not iteratable, then routine check value of {-src-}. + * + * @param { ArrayLike|Set|Map|Object|* } dst - Container or another single element for filtering. + * If {-dst-} is null, then makes new container of {-src-} type. + * @param { ArrayLike|Set|Map|Object|* } src - Container or another single element for filtering. + * If {-src-} is undefined, then {-dst-} filters by its own values. + * @param { Function } onEach - The callback that obtain value for every {-src-} element. The + * callback accepts three parameters - element, key, source container. + * + * @example + * _.entityBut( 'str', 1 ) + * // returns undefined + * + * @example + * _.entityBut( 'str', 1, ( e, k, src ) => e - 1 ) + * // returns 'str' + * + * @example + * let src = [ 1, 0, null, undefined, true ]; + * _.entityBut( null, src ); + * // returns [ 0, null, undefined ] + * + * @example + * let src = [ 1, 0, null, undefined, true ]; + * _.entityBut( null, src, ( e, k ) => k ); + * // returns [ 1 ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * _.entityBut( dst ); + * // returns [ '', 0, null, undefined ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * _.entityBut( dst, undefined, ( e, k ) => k ); + * // returns [ '' ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * let src = [ 1, 2, false, undefined, 0 ] + * _.entityBut( dst, src ); + * // returns [ null, undefined ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * let src = [ 1, 2, false, undefined, 0 ] + * _.entityBut( dst, undefined, ( e, k ) => k ); + * // returns [ '' ] + * + * @returns { ArrayLike|Set|Map|Object|* } - Returns filtered container. + * If {-dst-} is not iteratable value, routine returns original {-dst-} or undefined. + * @function entityBut + * @throws { Error } If arguments.length is less then one or more than three arguments. + * @throws { Error } If {-dst-} is not null or {-dst-} and {-src-} containers has different types. + * @throws { Error } If {-onEach-} is not undefined, not a routine, not selector. + * @throws { Error } If onEach.length is more then three. + * @throws { Error } If {-onEach-} is selector and it does not begin with '*\/'. + * @namespace Tools + */ + +function entityBut( dst, src, onEach ) +{ + + if( arguments.length > 2 ) + onEach = arguments[ arguments.length-1 ]; + + if( src === undefined ) + src = dst; + + if( _.strIs( onEach ) ) + { + let selector = onEach; + _.assert( _.routine.is( _.select ) ); + _.assert( _.strBegins( selector, '*/' ), () => `Selector should begins with "*/", but "${selector}" does not` ); + selector = _.strRemoveBegin( selector, '*/' ); + onEach = function( e, k ) + { + return _.select( e, selector ); + } + } + + let dstTypeStr = typeStr( dst ); + let srcTypeStr = typeStr( src ); + + _.assert( dst === null || dstTypeStr === srcTypeStr ); + _.assert( arguments.length === 1 || arguments.length === 2 || arguments.length === 3 ); + _.assert( onEach === undefined || ( _.routine.is( onEach ) && onEach.length <= 3 ), 'Expects optional routine or selector {- onEach -}' ); + + /* */ + + if( dst === null ) + { + if( _.routine.is( onEach ) ) + { + if( srcTypeStr === 'set' ) + setWithRoutine(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithRoutine(); + else + withRoutine(); + } + else + { + if( srcTypeStr === 'set' ) + setWithoutRoutine(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithoutRoutine(); + else + withoutRoutine(); /* don't change the subroutine */ + } + } + else + { + if( _.routine.is( onEach ) ) + { + if( srcTypeStr === 'set' ) + setWithRoutineDeleting(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithRoutineDeleting(); + else + withRoutineDeleting(); + } + else + { + if( srcTypeStr === 'set' ) + setWithoutRoutineDeleting(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithoutRoutineDeleting(); + else + withoutRoutineDeleting(); + } + } + + /* */ + + return dst; + + /* */ + + function setWithRoutine() + { + dst = new Set( null ); + + for( let value of src ) + { + let res = onEach( value, undefined, src ); + if( !res ) + dst.add( value ); + } + } + + /* */ + + function setWithoutRoutine() + { + dst = new Set( null ); + + // Dmytro : it'll be faster, but can't keep order of elements + // let unnecessaries = [ undefined, 0, null, false, '' ]; + // for( let key of unnecessaries ) + // if( src.has( key ) ) + // dst.add( key ); + for( let e of src ) + if( !e ) + dst.add( e ); + } + + /* */ + + function hashMapWithRoutine() + { + dst = new HashMap( null ); + + for( let [ key, value ] of src ) + { + let res = onEach( value, key, src ); + if( !res ) + dst.set( key, value ); + } + } + + /* */ + + function hashMapWithoutRoutine() + { + dst = new HashMap( null ); + + for( let [ key, value ] of src ) + if( !value ) + dst.set( key, value ); + } + + /* */ + + function withRoutine() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) ) + { + + dst = []; + for( let k = 0 ; k < src.length ; k++ ) + { + let res = onEach( src[ k ], k, src ); + if( !res ) + dst.push( src[ k ] ); + } + + } + else if( _.aux.is( src ) ) + { + + dst = Object.create( null ); + for( let k in src ) + { + let res = onEach( src[ k ], k, src ); + if( !res ) + dst[ k ] = src[ k ]; + } + + } + else + { + let res = onEach( src, undefined, undefined ); + if( res ) + dst = undefined; + else + dst = src; + // if( !res ) + // dst = src; + // else + // dst = undefined; + } + + } + + /* */ + + function withoutRoutine() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) ) + { + + dst = []; + for( let k = 0 ; k < src.length ; k++ ) + { + let res = src[ k ]; + if( !res ) + dst.push( src[ k ] ); + } + + } + else if( _.aux.is( src ) ) + { + + dst = Object.create( null ); + for( let k in src ) + { + let res = src[ k ]; + if( !res ) + dst[ k ] = src[ k ]; + } + + } + else + { + let res = src; + if( res ) + dst = undefined; + else + dst = res; + // if( !res ) + // dst = res; + // else + // dst = undefined; + } + + } + + /* */ + + function setWithRoutineDeleting() + { + for( let value of src ) + { + let res = onEach( value, undefined, src ); + if( res ) + dst.delete( value ); + } + } + + /* */ + + function setWithoutRoutineDeleting() + { + for( let value of src ) + { + if( value ) + dst.delete( value ); + } + } + + /* */ + + function hashMapWithRoutineDeleting() + { + for( let [ key, value ] of src ) + { + let res = onEach( value, key, src ) + if( res ) + dst.delete( key ); + } + } + + /* */ + + function hashMapWithoutRoutineDeleting() + { + for( let [ key, value ] of src ) + if( value ) + dst.delete( key ); + } + + /* */ + + function withRoutineDeleting() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( dst ) ) + { + + for( let k = dst.length - 1; k >= 0; k-- ) + { + let res = onEach( src[ k ], k, src ); + if( res ) + dst.splice( k, 1 ); + } + + } + else if( _.aux.is( dst ) ) + { + + for( let k in dst ) + { + let res = onEach( src[ k ], k, src ); + if( res ) + delete dst[ k ]; + } + + } + else + { + let res = onEach( src, undefined, undefined ); + if( res ) + dst = undefined; + } + + } + + /* */ + + function withoutRoutineDeleting() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( dst ) ) + { + + for( let k = dst.length - 1; k >= 0; k-- ) + { + let res = src[ k ]; + if( res ) + dst.splice( k, 1 ); + } + + } + else if( _.aux.is( dst ) ) + { + + for( let k in dst ) + { + let res = src[ k ]; + if( res ) + delete dst[ k ]; + } + + } + else + { + let res = src; + if( res ) + dst = undefined; + else + dst = dst; + } + + } + + /* xxx */ + function typeStr( e ) + { + let type; + if( _.longIs( e ) ) + type = 'long'; + else if( _.aux.is( e ) ) + type = 'map'; + else if( _.set.is( e ) ) + type = 'set'; + else if( _.hashMap.is( e ) ) + type = 'hashMap'; + else + type = 'primitive'; + + return type; + } + +} + +// + +/** + * The routine entityAnd() provides the filtering of elements of destination container + * {-dst-} by checking values with the same keys in the {-dst-} and source {-src-} containers. + * If one of received values is falsy, then element with deletes from the {-dst-} container. + * + * If {-dst-} container is null, routine makes new container with type of {-src-} container, and fill it obtained values. + * If {-src-} is undefined, routine filters {-dst-} container obtaining values from {-dst-}. + * Note: containers should have same type. + * + * Also, {-dst-} and {-src-} might be not iteratable element, for example, primitive. + * If {-dst-} is not iteratable, then routine check value of {-src-}. + * + * @param { ArrayLike|Set|Map|Object|* } dst - Container or another single element for filtering. + * If {-dst-} is null, then makes new container of {-src-} type. + * @param { ArrayLike|Set|Map|Object|* } src - Container or another single element for filtering. + * If {-src-} is undefined, then {-dst-} filters by its own values. + * @param { Function } onEach - The callback that obtain value for every {-dst-} and {-src-} element + * with the same keys. The callback accepts three parameters - element, key, source container. + * + * @example + * _.entityAnd( 'str', 1 ); + * // returns 'str' + * + * @example + * _.entityAnd( 'str', 1, ( e, k, src ) => e - 1 ); + * // returns undefined + * + * @example + * let src = [ 1, 0, null, undefined, true ]; + * _.entityAnd( null, src ); + * // returns [ 1, true ] + * + * @example + * let src = [ 1, 0, null, undefined, true ]; + * _.entityAnd( null, src, ( e, k ) => k ); + * // returns [ 0, null, undefined, true ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * _.entityAnd( dst ); + * // returns [ true ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * _.entityAnd( dst, undefined, ( e, k ) => k ); + * // returns [ 0, null, undefined, true ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * let src = [ 1, 2, false, undefined, 0 ]; + * _.entityAnd( dst, src ); + * // returns [] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * let src = [ 1, 2, false, undefined, 0 ]; + * _.entityAnd( dst, undefined, ( e, k ) => k ); + * // returns [ 0, null, undefined, true ] + * + * @returns { ArrayLike|Set|Map|Object|* } - Returns filtered container. + * If {-dst-} is not iteratable value, routine returns original {-dst-} or undefined. + * @function entityAnd + * @throws { Error } If arguments.length is less then one or more than three arguments. + * @throws { Error } If {-dst-} is not null or {-dst-} and {-src-} containers has different types. + * @throws { Error } If {-onEach-} is not undefined, not a routine, not selector. + * @throws { Error } If onEach.length is more then three. + * @throws { Error } If {-onEach-} is selector and it does not begin with '*\/'. + * @namespace Tools + */ + +function entityAnd( dst, src, onEach ) +{ + + if( arguments.length > 2 ) + onEach = arguments[ arguments.length-1 ]; + + if( src === undefined ) + src = dst; + + if( _.strIs( onEach ) ) + { + let selector = onEach; + _.assert( _.routine.is( _.select ) ); + _.assert( _.strBegins( selector, '*/' ), () => `Selector should begins with "*/", but "${selector}" does not` ); + selector = _.strRemoveBegin( selector, '*/' ); + onEach = function( e, k ) + { + return _.select( e, selector ); + } + } + + let dstTypeStr = typeStr( dst ); + let srcTypeStr = typeStr( src ); + + _.assert( dst === null || dstTypeStr === srcTypeStr ); + _.assert( arguments.length === 1 || arguments.length === 2 || arguments.length === 3 ); + _.assert( onEach === undefined || ( _.routine.is( onEach ) && onEach.length <= 3 ), 'Expects optional routine or selector {- onEach -}' ); + + /* */ + + if( dst === null ) + { + if( _.routine.is( onEach ) ) + { + if( srcTypeStr === 'set' ) + setWithRoutine(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithRoutine(); + else + withRoutine(); + } + else + { + if( srcTypeStr === 'set' ) + setWithoutRoutine(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithoutRoutine(); + else + withoutRoutine(); /* don't change the subroutine */ + } + } + else + { + if( _.routine.is( onEach ) ) + { + if( srcTypeStr === 'set' ) + setWithRoutineDeleting(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithRoutineDeleting(); + else + withRoutineDeleting(); + } + else + { + if( srcTypeStr === 'set' ) + setWithoutRoutineDeleting(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithoutRoutineDeleting(); + else + withoutRoutineDeleting(); + } + } + + return dst; + + /* */ + + function setWithRoutine() + { + dst = new Set( null ); + + for( let value of src ) + { + let res = onEach( value, undefined, src ); + if( res ) + dst.add( value ); + } + } + + /* */ + + function setWithoutRoutine() + { + dst = new Set( src ); + + let unnecessaries = [ null, 0, undefined, false, '' ]; + for( let key of unnecessaries ) + if( src.has( key ) ) + dst.delete( key ); + } + + /* */ + + function hashMapWithRoutine() + { + dst = new HashMap( null ); + + for( let [ key, value ] of src ) + { + let res = onEach( value, key, src ); + if( res ) + dst.set( key, value ); + } + } + + /* */ + + function hashMapWithoutRoutine() + { + dst = new HashMap( null ); + + for( let [ key, value ] of src ) + if( value ) + dst.set( key, value ); + } + + /* */ + + function withRoutine() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) ) + { + + dst = []; + for( let k = 0; k < src.length; k++ ) + { + let res = onEach( src[ k ], k, src ); + if( res ) + dst.push( src[ k ] ); + } + + } + else if( _.aux.is( src ) ) + { + + dst = Object.create( null ); + for( let k in src ) + { + let res = onEach( src[ k ], k, src ); + if( res ) + dst[ k ] = src[ k ]; + } + + } + else + { + let res = onEach( src, undefined, undefined ); + if( res ) + dst = src; + else + dst = undefined; + } + + } + + /* */ + + function withoutRoutine() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) ) + { + + dst = []; + for( let k = 0; k < src.length; k++ ) + { + let res = src[ k ]; + if( res ) + dst.push( src[ k ] ); + } + + } + else if( _.aux.is( src ) ) + { + + dst = Object.create( null ); + for( let k in src ) + { + let res = src[ k ]; + if( res ) + dst[ k ] = src[ k ]; + } + + } + else + { + let res = src; + if( res ) + dst = src; + else + dst = undefined; + } + + } + + /* */ + + function setWithRoutineDeleting() + { + + for( let value of dst ) + { + let res1, res2; + let from = [ ... src ] + + res1 = onEach( value, undefined, dst ); + if( res1 && from.lastIndexOf( value ) !== -1 ) + res2 = onEach( value, undefined, from ); + else if( res1 ) + res2 = onEach( undefined, undefined, src ); + + if( !res1 || !res2 ) + dst.delete( value ); + } + } + + /* */ + + function setWithoutRoutineDeleting() + { + for( let value of dst ) + { + if( !value || !src.has( value ) ) + dst.delete( value ); + } + } + + /* */ + + function hashMapWithRoutineDeleting() + { + for( let [ key, value ] of dst ) + { + let res1, res2; + res1 = onEach( value, key, dst ) + if( res1 !== undefined && src.has( key ) ) + res2 = onEach( src.get( key ), key, src ); + + if( !res1 || !res2 ) + dst.delete( key ); + } + } + + /* */ + + function hashMapWithoutRoutineDeleting() + { + for( let [ key, value ] of dst ) + if( !value || !src.get( key ) ) + dst.delete( key ); + } + + /* */ + + function withRoutineDeleting() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( dst ) ) + { + + dst = _.arrayIs( dst ) ? dst : _.array.make( dst ); + for( let k = dst.length - 1; k >= 0; k-- ) + { + let res1, res2; + res1 = onEach( dst[ k ], k, dst ); + if( res1 ) + res2 = onEach( src[ k ], k, src ); + if( !res1 || !res2 ) + dst.splice( k, 1 ); + } + + } + else if( _.aux.is( dst ) ) + { + + for( let k in dst ) + { + let res1, res2; + res1 = onEach( dst[ k ], k, dst ); + if( res1 ) + res2 = onEach( src[ k ], k, src ); + if( !res1 || !res2 ) + delete dst[ k ]; + } + + } + else + { + let res1, res2; + res1 = onEach( dst, undefined, undefined ); + if( res1 ) + res2 = onEach( src, undefined, undefined ); + if( !res1 || !res2 ) + dst = undefined; + } + + } + + /* */ + + function withoutRoutineDeleting() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( dst ) ) + { + + dst = _.arrayIs( dst ) ? dst : _.array.make( dst ); + for( let k = dst.length - 1; k >= 0; k-- ) + { + let res1 = dst[ k ]; + let res2 = src[ k ]; + if( !res1 || !res2 ) + dst.splice( k, 1 ); + } + + } + else if( _.aux.is( dst ) ) + { + + for( let k in dst ) + { + let res1 = dst[ k ]; + let res2 = src[ k ]; + if( !res1 || !res2 ) + delete dst[ k ]; + } + + } + else + { + let res1 = dst; + let res2 = src; + if( !res1 || !res2 ) + dst = undefined; + } + + } + + function typeStr( e ) + { + let type; + if( _.longIs( e ) ) + type = 'long'; + else if( _.aux.is( e ) ) + type = 'map'; + else if( _.set.is( e ) ) + type = 'set'; + else if( _.hashMap.is( e ) ) + type = 'hashMap'; + else + type = 'primitive'; + + return type; + } + +} + +// + +/** + * The routine entityOr() provides the filtering of elements of destination container + * {-dst-} by checking values with the same keys in the {-dst-} and source {-src-} containers. + * If checking of {-dst-} element returs true, routine save {-dst-} element. + * If checking of {-dst-} element return false and checking of {-src-} element returns true, + * routine replace {-dst-} element by {-src-} element. + * Else, routine deletes {-dst-} element. + * + * If {-dst-} container is null, routine makes new container with type of {-src-} container, and fill it obtained values. + * If {-src-} is undefined, routine filters {-dst-} container obtaining values from {-dst-}. + * Note: containers should have same type. + * + * Also, {-dst-} and {-src-} might be not iteratable element, for example, primitive. + * If {-dst-} is not iteratable, then routine check value of {-src-}. + * + * @param { ArrayLike|Set|Map|Object|* } dst - Container or another single element for filtering. + * If {-dst-} is null, then makes new container of {-src-} type. + * @param { ArrayLike|Set|Map|Object|* } src - Container or another single element for filtering. + * If {-src-} is undefined, then {-dst-} filters by its own values. + * @param { Function } onEach - The callback that obtain value for every {-dst-} and {-src-} element + * with the same keys. The callback accepts three parameters - element, key, source container. + * + * @example + * _.entityOr( 'str', undefined ); + * // returns 'str' + * + * @example + * _.entityOr( false, 1, ( e, k, src ) => e - 1 ); + * // returns 1 + * + * @example + * let src = [ 1, 0, null, undefined, true ]; + * _.entityOr( null, src ); + * // returns [ 1, true ] + * + * @example + * let src = [ 1, 0, null, undefined, true ]; + * _.entityOr( null, src, ( e, k ) => k ); + * // returns [ 0, null, undefined, true ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * _.entityOr( dst ); + * // returns [ true ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * _.entityOr( dst, undefined, ( e, k ) => k ); + * // returns [ 0, null, undefined, true ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * let src = [ 1, 2, false, undefined, 0 ]; + * _.entityOr( dst, src ); + * // returns [ 1, 2, true ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * let src = [ 1, 2, false, undefined, 0 ]; + * _.entityOr( dst, undefined, ( e, k ) => k ); + * // returns [ 0, null, undefined, true ] + * + * @returns { ArrayLike|Set|Map|Object|* } - Returns filtered container. + * If {-dst-} is not iteratable value, routine returns original {-dst-} or undefined. + * @function entityOr + * @throws { Error } If arguments.length is less then one or more than three arguments. + * @throws { Error } If {-dst-} is not null or {-dst-} and {-src-} containers has different types. + * @throws { Error } If {-onEach-} is not undefined, not a routine, not selector. + * @throws { Error } If onEach.length is more then three. + * @throws { Error } If {-onEach-} is selector and it does not begin with '*\/'. + * @namespace Tools + */ + +function entityOr( dst, src, onEach ) +{ + + if( arguments.length > 2 ) + onEach = arguments[ arguments.length-1 ]; + + if( src === undefined ) + src = dst; + + if( _.strIs( onEach ) ) + { + let selector = onEach; + _.assert( _.routine.is( _.select ) ); + _.assert( _.strBegins( selector, '*/' ), () => `Selector should begins with "*/", but "${selector}" does not` ); + selector = _.strRemoveBegin( selector, '*/' ); + onEach = function( e, k ) + { + return _.select( e, selector ); + } + } + + let dstTypeStr = typeStr( dst ); + let srcTypeStr = typeStr( src ); + + _.assert( dst === null || dstTypeStr === srcTypeStr ); + _.assert( arguments.length === 1 || arguments.length === 2 || arguments.length === 3 ); + _.assert( onEach === undefined || ( _.routine.is( onEach ) && onEach.length <= 3 ), 'Expects optional routine or selector {- onEach -}' ); + + /* */ + + if( dst === null ) + { + if( _.routine.is( onEach ) ) + { + if( srcTypeStr === 'set' ) + setWithRoutine(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithRoutine(); + else + withRoutine(); + } + else + { + if( srcTypeStr === 'set' ) + setWithoutRoutine(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithoutRoutine(); + else + withoutRoutine(); /* don't change the subroutine */ + } + } + else + { + if( _.routine.is( onEach ) ) + { + if( srcTypeStr === 'set' ) + setWithRoutineDeleting(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithRoutineDeleting(); + else + withRoutineDeleting(); + } + else + { + if( srcTypeStr === 'set' ) + setWithoutRoutineDeleting(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithoutRoutineDeleting(); + else + withoutRoutineDeleting(); + } + } + + return dst; + + /* */ + + function setWithRoutine() + { + dst = new Set( null ); + + for( let value of src ) + { + let res = onEach( value, undefined, src ); + if( res ) + dst.add( value ); + } + } + + /* */ + + function setWithoutRoutine() + { + dst = new Set( src ); + + let unnecessaries = [ null, 0, undefined, false, '' ]; + for( let key of unnecessaries ) + if( src.has( key ) ) + dst.delete( key ); + } + + /* */ + + function hashMapWithRoutine() + { + dst = new HashMap( null ); + + for( let [ key, value ] of src ) + { + let res = onEach( value, key, src ); + if( res ) + dst.set( key, value ); + } + } + + /* */ + + function hashMapWithoutRoutine() + { + dst = new HashMap( null ); + + for( let [ key, value ] of src ) + if( value ) + dst.set( key, value ); + } + + /* */ + + function withRoutine() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) ) + { + + dst = []; + for( let k = 0; k < src.length; k++ ) + { + let res = onEach( src[ k ], k, src ); + if( res ) + dst.push( src[ k ] ); + } + + } + else if( _.aux.is( src ) ) + { + + dst = Object.create( null ); + for( let k in src ) + { + let res = onEach( src[ k ], k, src ); + if( res ) + dst[ k ] = src[ k ]; + } + + } + else + { + let res = onEach( src, undefined, undefined ); + if( res ) + dst = src; + else + dst = undefined; + } + + } + + /* */ + + function withoutRoutine() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) ) + { + + dst = []; + for( let k = 0; k < src.length; k++ ) + { + let res = src[ k ]; + if( res ) + dst.push( src[ k ] ); + } + + } + else if( _.aux.is( src ) ) + { + + dst = Object.create( null ); + for( let k in src ) + { + let res = src[ k ]; + if( res ) + dst[ k ] = src[ k ]; + } + + } + else + { + let res = src; + if( res ) + dst = src; + else + dst = undefined; + } + + } + + /* */ + + function setWithRoutineDeleting() + { + for( let key of dst ) + { + let res1, res2; + res1 = onEach( key, undefined, dst ); + if( !res1 && src.has( key ) ) + res2 = onEach( key, undefined, src ); + else + res2 = onEach( undefined, undefined, src ); + + if( !res1 && !res2 ) + dst.delete( key ); + } + } + + /* */ + + function setWithoutRoutineDeleting() + { + for( let value of dst ) + { + if( !value ) + dst.delete( value ); + } + } + + /* */ + + function hashMapWithRoutineDeleting() + { + for( let [ key, value ] of dst ) + { + let res1, res2 + res1 = onEach( value, key, dst ) + if( !res1 && src.has( key ) ) + res2 = onEach( src.get( key ), key, src ); + else + res2 = onEach( undefined, undefined, src ); + + if( res1 ) + dst.set( key, value ); + else if( res2 ) + dst.set( key, src.get( key ) ); + else + dst.delete( key ); + } + } + + /* */ + + function hashMapWithoutRoutineDeleting() + { + for( let [ key, value ] of dst ) + { + if( !value ) + { + let res = src.get( key ); + + if( res ) + dst.set( key, res ); + else + dst.delete( key ); + } + } + } + + /* */ + + function withRoutineDeleting() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( dst ) ) + { + + dst = _.arrayIs( dst ) ? dst : _.array.make( dst ); + for( let k = dst.length - 1; k >= 0; k-- ) + { + let res1, res2; + res1 = onEach( dst[ k ], k, dst ); + if( !res1 ) + res2 = onEach( src[ k ], k, src ); + + if( res1 ) + dst[ k ] = dst[ k ]; + else if( res2 ) + dst[ k ] = src[ k ]; + else + dst.splice( k, 1 ); + } + + } + else if( _.aux.is( dst ) ) + { + + for( let k in dst ) + { + let res1, res2; + res1 = onEach( dst[ k ], k, dst ); + if( !res1 ) + res2 = onEach( src[ k ], k, src ); + + if( res1 ) + dst[ k ] = dst[ k ]; + else if( res2 ) + dst[ k ] = src[ k ]; + else + delete dst[ k ]; + } + + } + else + { + let res1, res2; + res1 = onEach( dst, undefined, undefined ); + if( !res1 ) + res2 = onEach( src, undefined, undefined ); + + if( res1 ) + dst = dst; + else if( res2 ) + dst = src; + else + dst = undefined; + } + + } + + /* */ + + function withoutRoutineDeleting() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( dst ) ) + { + + dst = _.arrayIs( dst ) ? dst : _.array.make( dst ); + for( let k = dst.length - 1; k >= 0; k-- ) + { + let res1 = dst[ k ]; + let res2 = src[ k ]; + + if( res1 ) + dst[ k ] = dst[ k ]; + else if( res2 ) + dst[ k ] = src[ k ]; + else + dst.splice( k, 1 ); + } + + } + else if( _.aux.is( dst ) ) + { + + for( let k in dst ) + { + let res1 = dst[ k ]; + let res2 = src[ k ]; + + if( res1 ) + dst[ k ] = dst[ k ]; + else if( res2 ) + dst[ k ] = src[ k ]; + else + delete dst[ k ]; + } + + } + else + { + let res1 = dst; + let res2 = src; + + if( res1 ) + dst = dst; + else if( res2 ) + dst = src; + else + dst = undefined; + } + + } + + /* */ + + function typeStr( e ) + { + let type; + if( _.longIs( e ) ) + type = 'long'; + else if( _.aux.is( e ) ) + type = 'map'; + else if( _.set.is( e ) ) + type = 'set'; + else if( _.hashMap.is( e ) ) + type = 'hashMap'; + else + type = 'primitive'; + + return type; + } + +} + +// + +/** + * The routine entityXor() provides the filtering of elements of destination container + * {-dst-} by checking values with the same keys in the {-dst-} and source {-src-} containers. + * If both received values from {-dst-} and {-src-} has the same boolean value, then routine + * deletes {-dst-} element. + * Else routine sets in {-dst-} element, which received boolean value is true. + * + * If {-dst-} container is null, routine makes new container with type of {-src-} container, and fill it obtained values. + * If {-src-} is undefined, routine filters {-dst-} container obtaining values from {-dst-}. + * Note: containers should have same type. + * + * Also, {-dst-} and {-src-} might be not iteratable element, for example, primitive. + * If {-dst-} is not iteratable, then routine check value of {-src-}. + * + * @param { ArrayLike|Set|Map|Object|* } dst - Container or another single element for filtering. + * If {-dst-} is null, then makes new container of {-src-} type. + * @param { ArrayLike|Set|Map|Object|* } src - Container or another single element for filtering. + * If {-src-} is undefined, then {-dst-} filters by its own values. + * @param { Function } onEach - The callback that obtain value for every {-dst-} and {-src-} element + * with the same keys. The callback accepts three parameters - element, key, source container. + * + * @example + * _.entityXor( 'str', undefined ); + * // returns 'str' + * + * @example + * _.entityXor( 'str', 1, ( e, k, src ) => e - 1 ); + * // returns false + * + * @example + * let src = [ 1, 0, null, undefined, true ]; + * _.entityXor( null, src ); + * // returns [ 1, 0, null, undefined, true ] + * + * @example + * let src = [ 1, 0, null, undefined, true ]; + * _.entityXor( null, src, ( e, k ) => k ); + * // returns [ 0, null, undefined, true ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * _.entityXor( dst ); + * // returns [] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * _.entityXor( dst, undefined, ( e, k ) => k ); + * // returns [] + * + * @example + * let dst = [ '', 0, null, 1, true ]; + * let src = [ 1, 2, false, 1, 'str' ]; + * _.entityXor( dst, src ); + * // returns [ 1, 2 ] + * + * @example + * let dst = [ '', 0, null, undefined, true ]; + * let src = [ 1, 2, false, undefined, 0 ]; + * _.entityXor( dst, undefined, ( e, k ) => k ); + * // returns [] + * + * @returns { ArrayLike|Set|Map|Object|* } - Returns filtered container. + * If {-dst-} is not iteratable value, routine returns original {-dst-} or undefined. + * @function entityXor + * @throws { Error } If arguments.length is less then one or more than three arguments. + * @throws { Error } If {-dst-} is not null or {-dst-} and {-src-} containers has different types. + * @throws { Error } If {-onEach-} is not undefined, not a routine, not selector. + * @throws { Error } If onEach.length is more then three. + * @throws { Error } If {-onEach-} is selector and it does not begin with '*\/'. + * @namespace Tools + */ + +function entityXor( dst, src, onEach ) +{ + + if( arguments.length > 2 ) + onEach = arguments[ arguments.length-1 ]; + + if( src === undefined ) + src = dst; + + if( _.strIs( onEach ) ) + { + let selector = onEach; + _.assert( _.routine.is( _.select ) ); + _.assert( _.strBegins( selector, '*/' ), () => `Selector should begins with "*/", but "${selector}" does not` ); + selector = _.strRemoveBegin( selector, '*/' ); + onEach = function( e, k ) + { + return _.select( e, selector ); + } + } + + let dstTypeStr = typeStr( dst ); + let srcTypeStr = typeStr( src ); + + _.assert( dst === null || dstTypeStr === srcTypeStr ); + _.assert( arguments.length === 1 || arguments.length === 2 || arguments.length === 3 ); + _.assert( onEach === undefined || ( _.routine.is( onEach ) && onEach.length <= 3 ), 'Expects optional routine or selector {- onEach -}' ); + + /* */ + + if( dst === null ) + { + if( _.routine.is( onEach ) ) + { + if( srcTypeStr === 'set' ) + setWithRoutine(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithRoutine(); + else + withRoutine(); + } + else + { + if( srcTypeStr === 'set' ) + setWithoutRoutine(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithoutRoutine(); + else + withoutRoutine(); /* don't change the subroutine */ + } + } + else + { + if( _.routine.is( onEach ) ) + { + if( srcTypeStr === 'set' ) + setWithRoutineDeleting(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithRoutineDeleting(); + else + withRoutineDeleting(); + } + else + { + if( srcTypeStr === 'set' ) + setWithoutRoutineDeleting(); + else if( srcTypeStr === 'hashMap' ) + hashMapWithoutRoutineDeleting(); + else + withoutRoutineDeleting(); + } + } + + return dst; + + /* */ + + function setWithRoutine() + { + dst = new Set( null ); + + for( let value of src ) + { + let res1 = onEach( undefined, undefined, dst ); + let res2 = onEach( value, undefined, src ); + + if( ( res1 && !res2 ) || ( !res1 && res2 ) ) + dst.add( value ); + } + } + + /* */ + + function setWithoutRoutine() + { + dst = new Set( src ); + + let unnecessaries = [ null, 0, undefined, false, '' ]; + for( let e of unnecessaries ) + dst.delete( e ); + } + + /* */ + + function hashMapWithRoutine() + { + dst = new HashMap( null ); + + for( let [ key, value ] of src ) + { + let res1 = onEach( undefined, undefined, dst ); + let res2 = onEach( value, key, src ); + + if( ( res1 && !res2 ) || ( !res1 && res2 ) ) + dst.set( key, value ); + } + } + + /* */ + + function hashMapWithoutRoutine() + { + dst = new HashMap( src ); + + let unnecessaries = [ null, 0, undefined, false, '' ]; + for( let k of unnecessaries ) + { + if( !dst.get( k ) ) + dst.delete( k ); + } + } + + /* */ + + function withRoutine() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) ) + { + + dst = []; + for( let k = 0; k < src.length; k++ ) + { + let res1 = onEach( undefined, undefined, dst ); + let res2 = onEach( src[ k ], k, src ); + + if( ( res1 && !res2 ) || ( !res1 && res2 ) ) + dst.push( src[ k ] ); + } + + } + else if( _.aux.is( src ) ) + { + + dst = Object.create( null ); + for( let k in src ) + { + let res1 = onEach( undefined, undefined, dst ); + let res2 = onEach( src[ k ], k, src ); + + if( ( res1 && !res2 ) || ( !res1 && res2 ) ) + dst[ k ] = src[ k ]; + } + + } + else + { + let res1 = onEach( null ); + let res2 = onEach( src, undefined, undefined ); + if( ( res1 && !res2 ) || ( !res1 && res2 ) ) + dst = src; + else + dst = undefined; + } + + } + + /* */ + + function withoutRoutine() + { + + if( _.longIs( src ) ) + { + dst = []; + for( let e of src ) + if( e ) + dst.push( e ); + } + else if( _.aux.is( src ) ) + { + dst = Object.assign( Object.create( null ), src ); + let unnecessaries = [ null, 0, undefined, false, '' ]; + for( let k of unnecessaries ) + { + if( !dst[ k ] ) + delete dst[ k ]; + } + } + else + { + if( src === undefined ) + dst = undefined; + else + dst = src; + // if( src !== undefined ) + // dst = src; + // else + // dst = undefined; + } + + } + + /* */ + + function setWithRoutineDeleting() + { + for( let key of dst ) + { + let res = onEach( key, undefined, dst ); + if( !res ) + dst.delete( key ); + } + + for( let key of src ) + { + let res1, res2; + if( dst.has( key ) ) + res1 = onEach( key, key, dst ); + else + res1 = onEach( undefined, undefined, dst ); + res2 = onEach( key, key, src ); + + if( res1 && !res2 ) + {} + else if( !res1 && res2 ) + dst.add( key ); + else + dst.delete( key ); + } + } + + /* */ + + function setWithoutRoutineDeleting() + { + for( let key of dst ) + if( !key ) + dst.delete( key ); + for( let key of src ) + { + if( dst.has( key ) ) + dst.delete( key ); + else if( key ) + dst.add( key ); + } + } + + /* */ + + function hashMapWithRoutineDeleting() + { + for( let [ key, value ] of dst ) + { + let res = onEach( value, key, dst ) + if( !res ) + dst.delete( key ); + } + for( let [ key, value ] of src ) + { + let res1, res2 + if( dst.has( key ) ) + res1 = onEach( dst.get( key ), key, dst ); + else + res1 = onEach( undefined, undefined, dst ); + res2 = onEach( value, key, src ) + + if( res1 && !res2 ) + {} + else if( !res1 && res2 ) + dst.set( key, value ); + else + dst.delete( key ); + } + } + + /* */ + + function hashMapWithoutRoutineDeleting() + { + for( let [ key, value ] of dst ) + if( !value ) + dst.delete( key ); + for( let [ key, value ] of src ) + { + let res1 = dst.get( key ); + let res2 = value; + + if( res1 && !res2 ) + {} + else if( !res1 && res2 ) + dst.set( key, value ); + else + dst.delete( key ); + } + } + + /* */ + + function withRoutineDeleting() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( dst ) ) + { + + dst = _.arrayIs( dst ) ? dst : _.array.make( dst ); + for( let k = src.length - 1; k >= 0; k-- ) + { + let res1 = onEach( dst[ k ], k, dst ); + let res2 = onEach( src[ k ], k, src ); + + if( res1 && !res2 ) + {} + else if( !res1 && res2 ) + dst[ k ] = src[ k ]; + else + dst.splice( k, 1 ); + } + + } + else if( _.aux.is( dst ) ) + { + + for( let k in src ) + { + let res1 = onEach( dst[ k ], k, dst ); + let res2 = onEach( src[ k ], k, src ); + + if( res1 && !res2 ) + {} + else if( !res1 && res2 ) + dst[ k ] = src[ k ]; + else + delete dst[ k ]; + } + + } + else + { + let res1 = onEach( dst, undefined, undefined ); + let res2 = onEach( src, undefined, undefined ); + + if( res1 && !res2 ) + {} + else if( !res1 && res2 ) + dst = src; + else + dst = undefined; + } + + } + + /* */ + + function withoutRoutineDeleting() + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( dst ) ) + { + + dst = _.arrayIs( dst ) ? dst : _.array.make( dst ); + for( let k = src.length - 1; k >= 0; k-- ) + { + let res1 = dst[ k ]; + let res2 = src[ k ]; + + if( res1 && !res2 ) + {} + else if( !res1 && res2 ) + dst[ k ] = src[ k ]; + else + dst.splice( k, 1 ); + } + + } + else if( _.aux.is( dst ) ) + { + + for( let k in src ) + { + let res1 = dst[ k ]; + let res2 = src[ k ]; + + if( res1 && !res2 ) + {} + else if( !res1 && res2 ) + dst[ k ] = src[ k ]; + else + delete dst[ k ]; + } + + } + else + { + let res1 = dst; + let res2 = src; + + if( res1 && !res2 ) + {} + else if( !res1 && res2 ) + dst = src; + else + dst = undefined; + } + + } + + /* */ + + function typeStr( e ) + { + let type; + if( _.longIs( e ) ) + type = 'long'; + else if( _.aux.is( e ) ) + type = 'map'; + else if( _.set.is( e ) ) + type = 'set'; + else if( _.hashMap.is( e ) ) + type = 'hashMap'; + else + type = 'primitive'; + + return type; + } + +} + +// + +function entityAll( src, onEach ) +{ + let result = true; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( onEach === undefined || ( _.routine.is( onEach ) && onEach.length <= 3 ) ); + + /* */ + + if( _.routine.is( onEach ) ) + { + + /* qqq for junior : add branch for countable case */ + if( _.set.like( src ) ) + { + + for( let e of src ) + { + result = onEach( e, undefined, src ); + if( !result ) + return result; + } + + } + else if( _.hashMap.is( src ) ) + { + + for( let [ key, value ] of src ) + { + result = onEach( value, key, src ); + if( !result ) + return result; + } + + } + else if( _.longIs( src ) ) + { + + /* qqq for junior : add branch for countable case */ + for( let k = 0 ; k < src.length ; k++ ) + { + result = onEach( src[ k ], k, src ); + if( !result ) + return result; + } + + } + else if( _.aux.is( src ) ) + { + + for( let k in src ) + { + result = onEach( src[ k ], k, src ); + if( !result ) + return result; + } + + } + else + { + result = onEach( src, undefined, undefined ); + if( !result ) + return result; + } + + } + else + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) || _.set.like( src ) ) + { + + for( let e of src ) + { + result = e; + if( !result ) + return result; + } + + } + else if( _.hashMap.is( src ) ) + { + + for( let [ key, value ] of src ) + { + result = value; + if( !result ) + return result; + } + + } + else if( _.aux.is( src ) ) + { + + for( let k in src ) + { + result = src[ k ]; + if( !result ) + return result; + } + + } + else + { + result = src; + if( !result ) + return result; + } + + } + + /* */ + + return true; +} + +// + +function entityAny( src, onEach ) +{ + let result = undefined; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( onEach === undefined || ( _.routine.is( onEach ) && onEach.length <= 3 ) ); + + /* */ + + if( _.routine.is( onEach ) ) + { + + /* qqq for junior : add branch for countable case */ + if( _.set.like( src ) ) + { + + for( let e of src ) + { + result = onEach( e, undefined, src ); + if( result ) + return result; + + } + + } + else if( _.hashMap.is( src ) ) + { + + for( let [ key, value ] of src ) + { + result = onEach( value, key, src ); + if( result ) + return result; + + } + + } + else if( _.longIs( src ) ) + { + + /* qqq for junior : add branch for countable case */ + for( let k = 0 ; k < src.length ; k++ ) + { + result = onEach( src[ k ], k, undefined ); + if( result ) + return result; + } + + } + else if( _.aux.is( src ) ) + { + + for( let k in src ) + { + result = onEach( src[ k ], k, undefined ); + if( result ) + return result; + } + + } + else + { + result = onEach( src, undefined, undefined ); + if( result ) + return result; + } + + } + else + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) || _.set.like( src ) ) + { + + for( let e of src ) + { + result = e; + if( result ) + return result; + } + + } + else if( _.hashMap.is( src ) ) + { + + for( let [ key, value ] of src ) + { + result = value; + if( result ) + return result; + } + + } + else if( _.aux.is( src ) ) + { + + for( let k in src ) + { + result = src[ k ]; + if( result ) + return result; + } + + } + else + { + result = src; + if( result ) + return result; + } + + } + + /* */ + + /* qqq : for Dmytro : should return undefined in such cases */ + // return false; + return undefined; +} + +// + +function entityNone( src, onEach ) +{ + let result = true; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( onEach === undefined || ( _.routine.is( onEach ) && onEach.length <= 3 ) ); + + /* */ + + if( _.routine.is( onEach ) ) + { + + /* qqq for junior : add branch for countable case */ + if( _.set.like( src ) ) + { + + for( let e of src ) + { + result = onEach( e, undefined, src ); + if( result ) + return !result; + } + + } + else if( _.hashMap.is( src ) ) + { + + for( let [ key, value ] of src ) + { + result = onEach( value, key, src ); + if( result ) + return !result; + } + + } + else if( _.longIs( src ) ) + { + + /* qqq for junior : add branch for countable case */ + for( let k = 0 ; k < src.length ; k++ ) + { + result = onEach( src[ k ], k, src ); + if( result ) + return !result; + } + + } + else if( _.aux.is( src ) ) + { + + for( let k in src ) + { + result = onEach( src[ k ], k, src ); + if( result ) + return !result; + } + + } + else + { + result = onEach( src, undefined, undefined ); + if( result ) + return !result; + } + + } + else + { + + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) || _.set.like( src ) ) + { + + for( let e of src ) + { + result = e; + if( result ) + return !result; + } + + } + else if( _.hashMap.is( src ) ) + { + + for( let [ key, value ] of src ) + { + result = value; + if( result ) + return !result; + } + + } + else if( _.aux.is( src ) ) + { + + for( let k in src ) + { + result = src[ k ]; + if( result ) + return !result; + } + + } + else + { + result = src; + if( result ) + return !result; + } + + } + + /* */ + + return true; +} + +// + +/** + * Returns generated function that takes single argument( e ) and can be called to check if object( e ) + * has at least one key/value pair that is represented in( condition ). + * If( condition ) is provided as routine, routine uses it to check condition. + * Generated function returns origin( e ) if conditions is true, else undefined. + * + * @param {object|function} condition - Map to compare with( e ) or custom function. + * @returns {function} Returns condition check function. + * + * @example + * let check = _._filter_functor( { a : 1, b : 1, c : 1 } ); + * check( { a : 1 } ); + * // returns Object {a: 1} + * + * @example + * function condition( src ){ return src.y === 1 } + * let check = _._filter_functor( condition ); + * check( { a : 2 } ); + * // returns false + * + * @function _filter_functor + * @throws {exception} If no argument provided. + * @throws {exception} If( condition ) is not a Routine or Object. + * @namespace Tools + */ + +function _filter_functor( condition, levels ) +{ + let result; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.routine.is( condition ) || _.object.isBasic( condition ) ); + + if( _.object.isBasic( condition ) ) + { + let template = condition; + condition = function condition( e, k, src ) + { + _.assert( arguments.length === 3 ); + if( e === template ) + return e; + if( !_.object.like( e ) ) + return; + let satisfied = _.objectSatisfy + ({ + template, + src : e, + levels + }); + if( satisfied ) + return e; + }; + } + + return condition; +} + +// + +/** + * Function that produces an elements for entityMap result + * @callback wTools.onEach + * @param {*} val - The current element being processed in the entity. + * @param {string|number} key - The index (if entity is array) or key of processed element. + * @param {Array|Object} src - The src passed to entityMap. + */ + +/** + * Creates new instance with same as( src ) type. Elements of new instance results of calling a provided ( onEach ) + * function on every element of src. If entity is array, the new array has the same length as source. + * + * @example + * let numbers = [ 3, 4, 6 ]; + * function sqrt( v ) + * { + * return v * v; + * }; + * + * _.container.map_( null, numbers, sqrt ); + * // returns [ 9, 16, 36 ] + * // numbers is still [ 3, 4, 6 ] + * + * @example + * function checkSidesOfTriangle( v, i, src ) + * { + * let sumOthers = 0, + * l = src.length, + * j; + * + * for( j = 0; j < l; j++ ) + * { + * if( i === j ) continue; + * sumOthers += src[ j ]; + * } + * return v < sumOthers; + * } + * + * _.container.map_( null, numbers, checkSidesOfTriangle ); + * // returns [ true, true, true ] + * + * @param {ArrayLike|ObjectLike} src - Entity, on each elements of which will be called ( onEach ) function. + * @param {wTools.onEach} onEach - Function that produces an element of the new entity. + * @returns {ArrayLike|ObjectLike} New entity. + * @thorws {Error} If number of arguments less or more than 2. + * @thorws {Error} If( src ) is not Array or ObjectLike. + * @thorws {Error} If( onEach ) is not function. + * @function entityMap + * @namespace Tools + */ + +// + +function map_( dst, src, onEach ) +{ + if( arguments.length === 2 ) + { + _.assert( arguments.length === 2, 'Expects three arguments' ); + onEach = src; + src = dst; + } + else + { + _.assert( arguments.length === 3, 'Expects three arguments' ); + } + _.assert( _.routine.is( onEach ) ); + + /* */ + + let result; + + if( dst === src ) + { + + result = src; + /* qqq for junior : add branch for countable case */ + if( _.longIs( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + { + let r = onEach( src[ s ], s, src ); + if( r !== undefined ) + result[ s ] = r; + } + } + else if( _.aux.is( src ) ) + { + for( let s in src ) + { + let r = onEach( src[ s ], s, src ); + if( r !== undefined ) + result[ s ] = r; + } + } + else + { + result = src; + let r = onEach( src, undefined, undefined ); + if( r !== undefined ) + result = r; + } + + } + else + { + + result = dst; + if( _.longIs( src ) ) + { + if( dst === null ) + result = _.entity.makeUndefined( src, src.length ); + else + _.assert( _.longIs( dst ), '{-dst-} container should be long like' ); + + /* qqq for junior : add branch for countable case */ + for( let s = 0 ; s < src.length ; s++ ) + { + let r = onEach( src[ s ], s, src ); + if( r !== undefined ) + result[ s ] = r; + } + } + else if( _.aux.is( src ) ) + { + if( dst === null ) + result = _.entity.makeUndefined( src ); + else + _.assert( _.aux.is( dst ), '{-dst-} container should be map like' ); + + for( let s in src ) + { + let r = onEach( src[ s ], s, src ); + if( r !== undefined ) + result[ s ] = r; + } + } + else + { + let r = onEach( src, undefined, undefined ); + if( r === undefined ) + return dst; + + if( _.longIs( dst ) ) + result = _.arrayAppendElement( dst, r ); + else if( _.aux.is( dst ) ) + result = _.props.extend( dst, r ); + else if( _.primitive.is( dst ) ) + result = r; + else + _.assert( 0, 'Not clear how to add result in destination container {-dst-}' ); + } + + } + + return result; +} + +// + +function filter_( dst, src, onEach ) +{ + + if( arguments.length === 2 ) + { + _.assert( arguments.length === 3, 'Expects three arguments' ); + onEach = src; + src = dst; + } + else + { + _.assert( arguments.length === 3, 'Expects two or three arguments' ); + } + onEach = _._filter_functor( onEach, 1 ); + + _.assert( _.routine.is( onEach ) ); + + /* */ + + let result; + + if( dst === src ) + { + + result = src; + if( _.longIs( src ) ) + { + /* qqq for junior : add branch for countable case */ + /* qqq : should be direct! check other cycles */ + for( let s = src.length - 1 ; s >= 0 ; s-- ) + { + let r = onEach.call( src, src[ s ], s, src ); + if( _.unrollIs( r ) ) + _.longBut_( result, s, r ); + else if( r === undefined ) + result.splice( s, 1 ); + else + result[ s ] = r; + // else if( r !== undefined ) + // result[ s ] = r; + // else + // result.splice( s, 1 ); + } + } + else if( _.aux.is( src ) ) + { + for( let s in src ) + { + let r = onEach.call( src, src[ s ], s, src ); + if( r === undefined ) + delete src[ s ]; + else + src[ s ] = r; + } + } + else + { + result = onEach.call( null, src, null, null ); + } + + } + else + { + + result = dst; + if( _.longIs( src ) ) + { + if( dst === null ) + { + if( _.argumentsArray.is( src ) ) + result = []; + else + result = _.long.make( src, 0 ); + } + else + { + _.assert( _.longIs( dst ), '{-dst-} container should be long like' ); + } + + let s, d; + /* qqq for junior : add branch for countable case */ + for( s = 0, d = 0 ; s < src.length ; s++ ) + { + let r = onEach.call( src, src[ s ], s, src ); + if( _.unrollIs( r ) ) + { + _.longBut_( result, d, r ); + d += r.length; + } + else if( r !== undefined ) + { + result[ d ] = r; + d += 1; + } + } + } + else if( _.aux.is( src ) ) + { + if( dst === null ) + result = _.entity.makeUndefined( src ); + else + _.assert( _.aux.is( dst ), '{-dst-} container should be map like' ); + + for( let s in src ) + { + let r = onEach.call( src, src[ s ], s, src ); + if( r !== undefined ) + result[ s ] = r; + } + } + else + { + let r = onEach.call( null, src, null, null ); + + if( r !== undefined ) + { + if( _.longIs( dst ) ) + result = _.arrayAppendElement( dst, r ); + else if( _.aux.is( dst ) ) + result = _.props.extend( dst, r ); + else if( _.primitive.is( dst ) ) + result = r; + else + _.assert( 0, 'Not clear how to add result in destination container {-dst-}' ); + } + } + + } + + return result; +} + +// + +function entityFirst( src, onEach ) +{ + let result; + + onEach = _._filter_functor( onEach, 1 ); + + _.assert( arguments.length === 2 ); + _.assert( _.routine.is( onEach ) ); + + /* */ + + if( _.longIs( src ) ) + { + + /* qqq for junior : add branch for countable case */ + for( let s = 0 ; s < src.length ; s++ ) + { + let r = onEach.call( src, src[ s ], s, src ); + if( r !== undefined ) + return r; + } + + } + else if( _.aux.is( src ) ) + { + + for( let s in src ) + { + let r = onEach.call( src, src[ s ], s, src ); + if( r !== undefined ) + return r; + } + + } + else + { + + result = onEach.call( null, src, null, null ); + + } + + /* */ + + return result; +} + +// + +function entityLast( src, onEach ) +{ + let result; + + onEach = _._filter_functor( onEach, 1 ); + + _.assert( arguments.length === 2 ); + _.assert( _.routine.is( onEach ) ); + // _.assert( src !== undefined, 'Expects src' ); + + /* */ + + if( _.longIs( src ) ) + { + + /* qqq for junior : add branch for countable case */ + for( let s = src.length - 1 ; s >= 0 ; s-- ) + { + let r = onEach.call( src, src[ s ], s, src ); + if( r !== undefined ) + return r; + } + + } + else if( _.aux.is( src ) ) + { + + for( let s in src ) + { + let r = onEach.call( src, src[ s ], s, src ); + if( r !== undefined ) + result = r; + } + + } + else + { + + result = onEach.call( null, src, null, null ); + + } + + /* */ + + return result; +} + +// + +/** + * The result of _most routine object. + * @typedef {Object} wTools.entityMostResult + * @property {Number} index - Index of found element. + * @property {String|Number} key - If the search was on map, the value of this property sets to key of found element. + * Else if search was on array - to index of found element. + * @property {Number} value - The found result of onEvaluate, if onEvaluate don't set, this value will be same as element. + * @property {Number} element - The appropriate element for found value. + */ + +/** + * Returns object( wTools.entityMostResult ) that contains min or max element of entity, it depends on( returnMax ). + * + * @param {ArrayLike|Object} src - Source entity. + * @param {Function} onEvaluate - ( onEach ) function is called for each element of( src ).If undefined routine uses it own function. + * @param {Boolean} returnMax - If true - routine returns maximum, else routine returns minimum value from entity. + * @returns {wTools.entityMostResult} Object with result of search. + * + * @example + * _._most([ 1, 3, 3, 9, 10 ], undefined, 0 ); + * // returns { index: 0, key: 0, value: 1, element: 1 } + * + * @example + * _._most( [ 1, 3, 3, 9, 10 ], undefined, 1 ); + * // returns { index: 4, key: 4, value: 10, element: 10 } + * + * @example + * _._most( { a : 1, b : 2, c : 3 }, undefined, 0 ); + * // returns { index: 4, key: 4, value: 10, element: 10 } + * + * @private + * @function _most + * @throws {Exception} If( arguments.length ) is not equal 3. + * @throws {Exception} If( onEvaluate ) function is not implemented. + * @namespace Tools + */ + +// + +function _most( o ) +{ + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + _.assert( _.mapIs( o ), 'Expect map, but got ' + _.entity.strType( o ) ); + _.routine.options( _most, o ); + + if( !o.onEach ) + o.onEach = _most.defaults.onEach; + + if( !o.onEvaluate ) + { + _.assert( o.returnMax !== null, 'o.returnMax should has value' ); + if( o.returnMax ) + o.onEvaluate = ( a, b ) => a - b > 0; + else + o.onEvaluate = ( a, b ) => b - a > 0; + } + + _.assert( 1 <= o.onEach.length && o.onEach.length <= 3 ); + _.assert( o.onEvaluate.length === 1 || o.onEvaluate.length === 2 ); + + let result = { index : -1, key : undefined, value : undefined, element : undefined }; + + /* qqq for junior : add branch for countable case */ + if( _.longIs( o.src ) ) + { + if( o.src.length === 0 ) + return result; + + let s = 0; + if( o.onEvaluate.length === 1 ) + for( ; s < o.src.length; s++ ) + { + let value = o.onEach( o.src[ s ], s, o.src ); + if( o.onEvaluate( value ) ) + { + result.value = value; + result.key = s; + break; + } + } + else + { + result.key = s; + result.value = o.onEach( o.src[ s ], s, o.src ); + } + + /* qqq for junior : add branch for countable case */ + for( ; s < o.src.length; s++ ) + resultValue( o.src[ s ], s, o.src ); + result.index = result.key; + result.element = o.src[ result.key ]; + } + else if( _.aux.is( o.src ) ) + { + let index = 0; + if( o.onEvaluate.length === 1 ) + { + for( let s in o.src ) + { + if( result.value === undefined ) + { + let value = o.onEach( o.src[ s ], s, o.src ); + if( o.onEvaluate( value ) ) + { + result.value = value; + result.index = index; + result.key = s; + } + } + else + { + if( resultValue( o.src[ s ], s, o.src ) ) + result.index = index; + } + + index++; + + } + result.element = o.src[ result.key ]; + } + else + { + for( let s in o.src ) + { + result.index = 0; + result.key = s; + result.value = o.onEach( o.src[ s ], s, o.src ); + break; + } + + for( let s in o.src ) + { + if( resultValue( o.src[ s ], s, o.src ) ) + result.index = index; + + index++; + } + result.element = o.src[ result.key ]; + } + + } + else + _.assert( 0 ); + + return result; + + /* */ + + function resultValue( e, k, s ) + { + let value = o.onEach( e, k, s ); + if( o.onEvaluate.length === 1 ) + { + if( o.onEvaluate( value ) === o.onEvaluate( result.value ) ) + { + result.key = k; + result.value = value; + return true; + } + } + else if( o.onEvaluate( value, result.value ) ) + { + result.key = k; + result.value = value; + return true; + } + + return false; + } + +} + +_most.defaults = +{ + src : null, + onEach : ( e ) => e, + onEvaluate : null, + returnMax : null +} + +// + +/** + * Short-cut for _most() routine. Returns object( wTools.entityMostResult ) with smallest value from( src ). + * + * @param {ArrayLike|Object} src - Source entity. + * @param {Function} onEvaluate - ( onEach ) function is called for each element of( src ).If undefined routine uses it own function. + * @returns {wTools.entityMostResult} Object with result of search. + * + * @example + * let obj = { a : 25, b : 16, c : 9 }; + * _.entityMin( obj, Math.sqrt ); + * // returns { index : 2, key : 'c', value 3: , element : 9 }; + * + * @see wTools.onEach + * @see wTools.entityMostResult + * @function entityMin + * @throws {Exception} If missed arguments. + * @throws {Exception} If passed extra arguments. + * @namespace Tools + */ + +function entityMin( src, onEach ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + return _most + ({ + src, + onEach : onEach || null, + returnMax : 0 + }); +} + +// + +/** + * Short-cut for _most() routine. Returns object( wTools.entityMostResult ) with biggest value from( src ). + * + * @param {ArrayLike|Object} src - Source entity. + * @param {Function} onEvaluate - ( onEach ) function is called for each element of( src ).If undefined routine uses it own function. + * @returns {wTools.entityMostResult} Object with result of search. + * + * @example + * let obj = { a: 25, b: 16, c: 9 }; + * _.entityMax( obj ); + * // returns { index: 0, key: "a", value: 25, element: 25 }; + * + * @see wTools.onEach + * @see wTools.entityMostResult + * @function entityMax + * @throws {Exception} If missed arguments. + * @throws {Exception} If passed extra arguments. + * @namespace Tools + */ + +function entityMax( src, onEach ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + return _most + ({ + src, + onEach : onEach || null, + returnMax : 1 + }); +} + +// -- +// extension +// -- + +let ContainerExtension = +{ + + // scalar + + scalarAppend, + scalarPrepend, + scalarAppendOnce, + scalarPrependOnce, + + scalarToVector, + scalarFrom, + scalarFromOrNull, + + // multiplier + + dup, + multiple, + multipleAll, + + // entity iterator + + each : entityEach, + eachOwn : entityEachOwn, + + /* qqq : for Dmytro : implementations with dst-null convention? */ + only : entityOnly, + but : entityBut, + and : entityAnd, + or : entityOr, + xor : entityXor, + + all : entityAll, + any : entityAny, + none : entityNone, + + _filter_functor, + + map_, + filter_, + first : entityFirst, + last : entityLast, + + // + + _most, + min : entityMin, + max : entityMax, + +} + +_.props.supplement( _.container, ContainerExtension ); + +// + +let ToolsExtension = +{ + + // scalar + + scalarAppend, + scalarPrepend, + scalarAppendOnce, + scalarPrependOnce, + + scalarToVector, + scalarFrom, + scalarFromOrNull, + + // multiplier + + dup, + multiple, + multipleAll, + + // entity iterator + + entityEach, + each : entityEach, + entityEachOwn, + eachOwn : entityEachOwn, + + // entityEachKey, + // eachKey : entityEachKey, + + entityOnly, + only : entityOnly, + entityBut, + but : entityBut, + entityAnd, + and : entityAnd, + entityOr, + or : entityOr, + entityXor, + xor : entityXor, + + entityAll, + all : entityAll, + entityAny, + any : entityAny, + entityNone, + none : entityNone, + + _filter_functor, + + // entityMap, + // map : entityMap,/* !!! : use instead of entityMap */ + // container.map_, + map_, + // entityFilter, + // filter : entityFilter, /* !!! : use instead of entityFilter */ + // container.filter_, + filter_, + // entityFirst, + // first : entityFirst, + // entityLast, + // last : entityLast, + + // + + _most, + _entityMost : _most, + entityMin, + min : entityMin, + entityMax, + max : entityMax, + +} + +_.props.supplement( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Functional.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Functional_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Functional_s */ })(); + +/* */ /* begin of file Fuzzy_s */ ( function Fuzzy_s() { function Fuzzy_s_naked() { ( function _l5_Fuzzy_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.fuzzy = _.fuzzy || Object.create( null ); + +// -- +// fuzzy +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +// + +let Extension = +{ + +} + +Object.assign( _, ToolsExtension ); +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Fuzzy.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Fuzzy_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Fuzzy_s */ })(); + +/* */ /* begin of file Global_s */ ( function Global_s() { function Global_s_naked() { ( function _l5_Global_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.global = _.global || Object.create( null ); +const __ = _realGlobal_.wTools; +__.global = __.global || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +var Extension = +{ + +} + +// + +_.props.supplement( _.global, Extension ); +_.props.supplement( __.global, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Global.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Global_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Global_s */ })(); + +/* */ /* begin of file HashMap_s */ ( function HashMap_s() { function HashMap_s_naked() { ( function _l5_HashMap_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +function extend( dst, src ) +{ + _.assert( arguments.length === 2 ); + _.assert( dst === null || _.hashMap.like( dst ) || _.aux.is( dst ) ); + _.assert( _.hashMapLike( src ) || _.aux.is( src ) ); + + if( dst === null ) + dst = new HashMap; + + if( dst === src ) + return dst; + + if( _.hashMap.like( dst ) ) + { + if( _.hashMapLike( src ) ) + { + for( let [ k, e ] of src ) + dst.set( k, e ); + } + else + { + for( let k in src ) + { + dst.set( k, src[ k ] ); + } + } + } + else + { + if( _.hashMap.like( src ) ) + { + for( let [ k, e ] of src ) + { + _.assert( _.strIs( k ) ); + dst[ k ] = e; + } + } + else + { + for( let k in src ) + { + dst[ k ] = src[ k ]; + } + } + } + + return dst; +} + +// // +// +// function fromMap( dstMap, srcMap ) +// { +// if( arguments.length === 1 ) +// { +// srcMap = arguments[ 0 ]; +// dstMap = null; +// } +// +// _.assert( arguments.length === 1 || arguments.length === 2 ); +// _.assert( !_.primitive.is( srcMap ) ); +// _.assert( dstMap === null || _.hashMapIs( dstMap ) ); +// +// if( dstMap === null ) +// dstMap = new HashMap; +// +// for( let k in srcMap ) +// { +// dstMap.set( k, srcMap[ k ] ); +// } +// +// return dstMap; +// } + +// -- +// extension +// -- + +let ToolsExtension = +{ + hashMapExtend : extend, +} + +// + +let Extension = +{ + + extend, /* qqq : cover */ + // fromMap, /* qqq : cover */ + +} + +Object.assign( _, ToolsExtension ); +Object.assign( _.hashMap, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/HashMap.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, HashMap_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file HashMap_s */ })(); + +/* */ /* begin of file Interval_s */ ( function Interval_s() { function Interval_s_naked() { ( function _l5_Interval_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _global_.wTools; + +// -- +// range +// -- + +// -- +// implementation +// -- + +let Extension = +{ +} + +// + +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Interval.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Interval_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Interval_s */ })(); + +/* */ /* begin of file Intervalc_s */ ( function Intervalc_s() { function Intervalc_s_naked() { ( function _l5_Intervalc_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// dichotomy +// -- + +function isEmpty( cinterval ) +{ + _.assert( arguments.length === 1 ); + if( !_.intervalIs( cinterval ) ) + return false; + return cinterval[ 0 ] === cinterval[ 1 ] + 1; +} + +// + +function isPopulated( cinterval ) +{ + _.assert( arguments.length === 1 ); + if( !_.intervalIs( cinterval ) ) + return false; + return cinterval[ 0 ] !== cinterval[ 1 ] + 1; +} + +// + +function has( cinterval, src ) +{ + + // if( _.longIs( src ) ) + // src = src.length; + + _.assert( arguments.length === 2 ); + _.assert( _.intervalIs( cinterval ) ); + // _.assert( _.number.is( src ) || _.intervalIs( src ) ); + + if( _.intervalIs( src ) ) + { + if( src[ 0 ] < cinterval[ 0 ] ) + return false; + if( src[ 1 ] > cinterval[ 1 ] ) + return false; + } + else if( _.number.is( src ) ) + { + if( src < cinterval[ 0 ] ) + return false; + if( src > cinterval[ 1 ] ) + return false; + } + else + { + _.assert( 0, 'Expects number or interval {-src-}.' ); + } + + return true; +} + +// + +// function inInclusive( cinterval, srcNumber ) +// { +// +// if( _.longIs( srcNumber ) ) +// srcNumber = srcNumber.length; +// +// _.assert( arguments.length === 2 ); +// _.assert( _.intervalIs( cinterval ) ); +// _.assert( _.number.is( srcNumber ) ); +// +// if( srcNumber < cinterval[ 0 ] ) +// return false; +// if( srcNumber >= cinterval[ 1 ] + 1 ) +// return false; +// +// return true; +// } +// +// // +// +// function inExclusive( cinterval, srcNumber ) +// { +// if( _.longIs( srcNumber ) ) +// srcNumber = srcNumber.length; +// +// _.assert( arguments.length === 2 ); +// _.assert( _.intervalIs( cinterval ) ); +// _.assert( _.number.is( srcNumber ) ); +// +// if( srcNumber <= cinterval[ 0 ] ) +// return false; +// if( srcNumber > cinterval[ 1 ] + 1 ) +// return false; +// +// return true; +// } +// +// // +// +// function inInclusiveLeft( cinterval, srcNumber ) +// { +// if( _.longIs( srcNumber ) ) +// srcNumber = srcNumber.length; +// +// _.assert( arguments.length === 2 ); +// _.assert( _.intervalIs( cinterval ) ); +// _.assert( _.number.is( srcNumber ) ); +// +// if( srcNumber < cinterval[ 0 ] ) +// return false; +// if( srcNumber >= cinterval[ 1 ] + 1 ) +// return false; +// +// return true; +// } +// +// // +// +// function inInclusiveRight( cinterval, srcNumber ) +// { +// if( _.longIs( srcNumber ) ) +// srcNumber = srcNumber.length; +// +// _.assert( arguments.length === 2 ); +// _.assert( _.intervalIs( cinterval ) ); +// _.assert( _.number.is( srcNumber ) ); +// +// if( srcNumber < cinterval[ 0 ] ) +// return false; +// if( srcNumber >= cinterval[ 1 ] + 1 ) +// return false; +// +// return true; +// } + +// + +function sureIn( src, cinterval ) +{ + _.assert( arguments.length >= 2 ); + if( _.longIs( src ) ) + src = src.length; + // let args = _.unroll.from + // ([ + // _.cinterval.has( cinterval, src ), + // () => 'Out of cinterval' + _.rangeToStr( cinterval ), _.unrollSelect( arguments, 2 ) + // ]); + // debugger + let args = + [ + _.cinterval.has( cinterval, src ) + ,() => 'Out of cinterval' + _.rangeToStr( cinterval ) + , Array.prototype.slice.call( arguments, 2 ) + ]; + _.sure.apply( _, args ); + return true; +} + +// + +function assertIn( src, cinterval ) +{ + _.assert( arguments.length >= 2 ); + if( _.longIs( src ) ) + src = src.length; + let args = + [ + _.cinterval.has( cinterval, src ) + ,() => 'Out of cinterval' + _.rangeToStr( cinterval ) + , Array.prototype.slice.call( arguments, 2 ) + ]; + // let args = _.unroll.from + // ([ + // _.cinterval.has( cinterval, src ), + // () => 'Out of cinterval' + _.rangeToStr( cinterval ), _.unrollSelect( arguments, 2 ) + // ]); + _.assert.apply( _, args ); + return true; +} + +// -- +// maker +// -- + +function fromLeft( cinterval ) +{ + _.assert( arguments.length === 1 ); + + if( _.number.is( cinterval ) ) + return [ cinterval, Infinity ]; + + _.assert( _.longIs( cinterval ) ); + + if( cinterval.length === 1 ) + cinterval = [ cinterval[ 0 ], Infinity ]; + else + _.assert( cinterval.length === 2 ); + + if( !_.number.is( cinterval[ 0 ] ) ) + { + _.assert( cinterval[ 0 ] === undefined ); + cinterval[ 0 ] = 0; + } + if( !_.number.is( cinterval[ 1 ] ) ) + { + _.assert( cinterval[ 1 ] === undefined ); + cinterval[ 1 ] = Infinity; + } + + return cinterval; +} + +// + +function fromRight( cinterval ) +{ + _.assert( arguments.length === 1 ); + + if( _.number.is( cinterval ) ) + return [ 0, cinterval ]; + + _.assert( _.longIs( cinterval ) ); + + if( cinterval.length === 1 ) + cinterval = [ cinterval[ 0 ], Infinity ]; + else + _.assert( cinterval.length === 2 ); + + if( !_.number.is( cinterval[ 0 ] ) ) + { + _.assert( cinterval[ 0 ] === undefined ); + cinterval[ 0 ] = 0; + } + if( !_.number.is( cinterval[ 1 ] ) ) + { + _.assert( cinterval[ 1 ] === undefined ); + cinterval[ 1 ] = Infinity; + } + + return cinterval; +} + +// + +function fromSingle( cinterval ) +{ + _.assert( arguments.length === 1 ); + + if( _.number.is( cinterval ) ) + return [ cinterval, cinterval ]; + + _.assert( _.longIs( cinterval ) ); + _.assert( cinterval.length === 1 || cinterval.length === 2 ); + + if( cinterval[ 0 ] === undefined ) + { + if( cinterval[ 1 ] === undefined ) + return [ 0, 0 ]; + + _.assert( _.number.is( cinterval[ 1 ] ) ); + return [ cinterval[ 1 ], cinterval[ 1 ] ]; + } + + _.assert( _.number.is( cinterval[ 0 ] ) ); + + if( cinterval[ 1 ] === undefined ) + return [ cinterval[ 0 ], cinterval[ 0 ] ]; + + _.assert( _.number.is( cinterval[ 1 ] ) ); + + return cinterval; +} + +// + +function clamp( dstRange, clampRange ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.intervalIs( dstRange ) ); + + if( _.number.is( clampRange ) ) + { + dstRange[ 0 ] = clampRange; + dstRange[ 1 ] = clampRange; + } + else + { + _.assert( _.intervalIs( clampRange ) ); + + if( dstRange[ 0 ] < clampRange[ 0 ] ) + dstRange[ 0 ] = clampRange[ 0 ]; + else if( dstRange[ 0 ] > clampRange[ 1 ] ) + dstRange[ 0 ] = clampRange[ 1 ]; + + if( dstRange[ 1 ] < clampRange[ 0 ] ) + dstRange[ 1 ] = clampRange[ 0 ]; + else if( dstRange[ 1 ] > clampRange[ 1 ] ) + dstRange[ 1 ] = clampRange[ 1 ]; + } + + return dstRange; +} + +// + +function countElements( cinterval, increment ) +{ + + _.assert( _.intervalIs( cinterval ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( increment === undefined ) + increment = 1; + + _.assert( _.number.is( increment ), 'Increment should has a number value' ); + + if( increment ) + { + let result = ( cinterval[ 1 ] - cinterval[ 0 ] + 1 ) / increment; + if( result > 0 ) + { + if( result < 1 ) + return 1; + return Math.floor( result ); + } + else if( result < 0 ) + { + if( result > -1 ) + return -1; + return Math.ceil( result ); + } + } + + return 0; +} + +// + +// function firstGet( cinterval, options ) +function firstGet( cinterval ) +{ + + _.assert( arguments.length === 1 ); + + // _.assert( arguments.length === 1 || arguments.length === 2 ); + // if( options ) + // { + // _.assert( _.aux.is( options ) ); + // if( options.increment === undefined ) + // options.increment = 1; + // } + + if( _.longIs( cinterval ) ) + { + _.assert( _.intervalIs( cinterval ) ); + return cinterval[ 0 ]; + } + else if( _.mapIs( cinterval ) ) /* xxx : remove? */ + { + return cinterval.first; + } + _.assert( 0, 'unexpected type of cinterval', _.entity.strType( cinterval ) ); +} + +// + +// function lastGet( cinterval, options ) +function lastGet( cinterval ) +{ + + _.assert( arguments.length === 1 ); + + // _.assert( arguments.length === 1 || arguments.length === 2 ); + // if( options ) + // { + // _.assert( _.object.like( options ) ); + // if( options.increment === undefined ) + // options.increment = 1; + // } + + if( _.longIs( cinterval ) ) + { + _.assert( _.intervalIs( cinterval ) ); + return cinterval[ 1 ]; + } + else if( _.mapIs( cinterval ) ) + { + return cinterval.last; + } + _.assert( 0, 'unexpected type of cinterval', _.entity.strType( cinterval ) ); + +} + +// + +function toStr( range ) +{ + _.assert( _.intervalIs( range ) ); + _.assert( arguments.length === 1 ); + return range[ 0 ] + '..' + range[ 1 ]; +} + +// -- +// define +// -- + +class Crange +{ + static[ Symbol.hasInstance ]( instance ) + { + return is( instance ); + } +} + +let Handler = +{ + construct( original, args ) + { + return Crange.fromLeft( ... args ); + } +}; + +const Self = new Proxy( Crange, Handler ); +Self.original = Crange; + +// -- +// implementation +// -- + +let Extension = +{ + + // dichotomy + + is : _.intervalIs, + isValid : _.intervalIsValid, + defined : _.intervalIsValid, + isEmpty, + isPopulated, + + // inInclusive, + // inExclusive, + // inInclusiveLeft, + // inInclusiveRight, + // has : inInclusiveLeft, + has, + + sureIn, + assertIn, + + // maker + + fromLeft, + fromRight, + fromSingle, + + clamp, + countElements, + firstGet, + lastGet, + + toStr, + +} + +// + +_.props.supplement( Self, Extension ); +_.assert( _.cinterval !== undefined ); +_.props.supplement( Self, _.cinterval ); +_.cinterval = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Intervalc.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Intervalc_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Intervalc_s */ })(); + +/* */ /* begin of file Intervall_s */ ( function Intervall_s() { function Intervall_s_naked() { ( function _l5_Intervall_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// dichotomy +// -- + +function isEmpty( linterval ) +{ + _.assert( arguments.length === 1 ); + if( !_.intervalIs( linterval ) ) + return false; + return linterval[ 1 ] === 0; +} + +// + +function isPopulated( linterval ) +{ + _.assert( arguments.length === 1 ); + if( !_.intervalIs( linterval ) ) + return false; + return linterval[ 1 ] !== 0; +} + +// + +function has( linterval, src ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.intervalIs( linterval ) ); + + if( _.intervalIs( src ) ) + { + if( src[ 0 ] < linterval[ 0 ] ) + return false; + if( src[ 1 ] > linterval[ 1 ] ) + return false; + } + else if( _.number.is( src ) ) + { + if( src < linterval[ 0 ] ) + return false; + if( src > linterval[ 0 ] + linterval[ 1 ] ) + return false; + } + else + { + _.assert( 0, 'Expects interval or number {-src-}.' ); + } + + return true; +} + +// + +function sureIn( src, linterval ) +{ + _.assert( arguments.length >= 2 ); + if( _.longIs( src ) ) + src = src.length; + // let args = _.unroll.from([ _.linterval.has( linterval, src ), () => 'Out of linterval' + _.rangeToStr( linterval ), _.unrollSelect( arguments, 2 ) ]); + // debugger; + let args = + [ + _.linterval.has( linterval, src ) + ,() => 'Out of linterval' + _.rangeToStr( linterval ) + , Array.prototype.slice.call( arguments, 2 ) + ]; + _.sure.apply( _, args ); + return true; +} + +// + +function assertIn( src, linterval ) +{ + _.assert( arguments.length >= 2 ); + if( _.longIs( src ) ) + src = src.length; + // let args = _.unroll.from([ _.linterval.has( linterval, src ), () => 'Out of linterval' + _.rangeToStr( linterval ), _.unrollSelect( arguments, 2 ) ]); + // debugger; + let args = + [ + _.linterval.has( linterval, src ) + ,() => 'Out of linterval' + _.rangeToStr( linterval ) + , Array.prototype.slice.call( arguments, 2 ) + ]; + _.assert.apply( _, args ); + return true; +} + +// -- +// maker +// -- + +function fromSingle( linterval ) +{ + _.assert( arguments.length === 1 ); + + if( _.number.is( linterval ) ) + return [ linterval, 1 ]; + + _.assert( _.longIs( linterval ) ); + _.assert( linterval.length === 1 || linterval.length === 2 ); + + if( linterval[ 0 ] === undefined ) + { + if( linterval[ 1 ] === undefined ) + return [ 0, 1 ]; + + _.assert( linterval[ 1 ] === 1, 'Expects length of 1' ); + return [ 0, 1 ]; + } + + _.assert( _.number.is( linterval[ 0 ] ) ); + + if( linterval[ 1 ] === undefined ) + return [ linterval[ 0 ], 1 ]; + + _.assert( _.number.is( linterval[ 1 ] ) ); + + return linterval; +} + +// + +function clamp( dstRange, clampRange ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.intervalIs( dstRange ) ); + + if( _.number.is( clampRange ) ) + { + dstRange[ 0 ] = clampRange; + dstRange[ 1 ] = 0; + } + else + { + _.assert( _.intervalIs( clampRange ) ); + + if( dstRange[ 0 ] < 0 ) + dstRange[ 0 ] = 0; + else if( dstRange[ 0 ] > clampRange[ 0 ] ) + dstRange[ 0 ] = clampRange[ 0 ]; + + if( dstRange[ 1 ] < 0 ) + dstRange[ 1 ] = 0; + else if( dstRange[ 1 ] > clampRange[ 1 ] ) + dstRange[ 1 ] = clampRange[ 1 ]; + } + + return dstRange; +} + +// + +function countElements( linterval, increment ) +{ + + _.assert( _.intervalIs( linterval ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( increment === undefined ) + increment = 1; + + _.assert( _.number.is( increment ), 'Increment should has a number value' ); + + if( increment ) + { + let result = linterval[ 1 ] / increment; + if( result > 0 ) + { + if( result < 1 ) + return 1; + return Math.floor( result ); + } + else if( result < 0 ) + { + if( result > -1 ) + return -1; + return Math.ceil( result ); + } + } + + return 0; +} + +// + +function lastGet( linterval, options ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + + // options = options || Object.create( null ); /* Dmytro : I don't know why routine makes this side effect */ + // if( options.increment === undefined ) /* The creating of new map has no sense, improved below */ + // options.increment = 1; + + if( options ) + { + _.assert( _.object.like( options ) ); + if( options.increment === undefined ) + options.increment = 1; + } + + if( _.longIs( linterval ) ) + { + _.assert( _.intervalIs( linterval ) ); + return linterval[ 0 ] + linterval[ 1 ] - 1; + } + else if( _.mapIs( linterval ) ) + { + return linterval.last; + } + _.assert( 0, 'unexpected type of linterval', _.entity.strType( linterval ) ); + +} + +// -- +// define +// -- + +class Lrange +{ + static[ Symbol.hasInstance ]( instance ) + { + return is( instance ); + } +} + +let Handler = +{ + construct( original, args ) + { + return Lrange.fromLeft( ... args ); + } +}; + +const Self = new Proxy( Lrange, Handler ); +Self.original = Lrange; + +// -- +// implementation +// -- + +let Extension = +{ + + // dichotomy + + is : _.intervalIs, + isValid : _.intervalIsValid, + defined : _.intervalIsValid, + isEmpty, + isPopulated, + + has, + + sureIn, + assertIn, + + // maker + + fromLeft : _.cinterval.fromLeft, + fromRight : _.cinterval.fromRight, + fromSingle, + + clamp, + countElements, + firstGet : _.cinterval.firstGet, + lastGet, + + toStr : _.cinterval.toStr, + +} + +// + +_.props.supplement( Self, Extension ); +_.assert( _.linterval !== undefined ); +_.props.supplement( Self, _.linterval ); +_.linterval = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Intervall.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Intervall_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Intervall_s */ })(); + +/* */ /* begin of file Intervalo_s */ ( function Intervalo_s() { function Intervalo_s_naked() { ( function _l5_Intervalo_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// dichotomy +// -- + +function isEmpty( ointerval ) +{ + _.assert( arguments.length === 1 ); + if( !_.intervalIs( ointerval ) ) + return false; + return ointerval[ 0 ] === ointerval[ 1 ]; +} + +// + +function isPopulated( ointerval ) +{ + _.assert( arguments.length === 1 ); + if( !_.intervalIs( ointerval ) ) + return false; + return ointerval[ 0 ] !== ointerval[ 1 ]; +} + +// + +function has( ointerval, src ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.intervalIs( ointerval ) ); + + if( _.intervalIs( src ) ) + { + if( src[ 0 ] < ointerval[ 0 ] ) + return false; + if( src[ 1 ] > ointerval[ 1 ] ) + return false; + } + else if( _.number.is( src ) ) + { + if( src < ointerval[ 0 ] ) + return false; + if( src >= ointerval[ 1 ] ) + return false; + } + else + { + _.assert( 0, 'Expects interval or number {-src-}.' ); + } + + return true; +} + +// + +function sureIn( src, ointerval ) +{ + _.assert( arguments.length >= 2 ); + if( _.longIs( src ) ) + src = src.length; + // let args = _.unroll.from([ _.ointerval.has( ointerval, src ), () => 'Out of ointerval' + _.rangeToStr( ointerval ), _.unrollSelect( arguments, 2 ) ]); + // debugger; + let args = + [ + _.ointerval.has( ointerval, src ) + ,() => 'Out of ointerval' + _.rangeToStr( ointerval ) + , Array.prototype.slice.call( arguments, 2 ) + ]; + _.sure.apply( _, args ); + return true; +} + +// + +function assertIn( src, ointerval ) +{ + _.assert( arguments.length >= 2 ); + if( _.longIs( src ) ) + src = src.length; + // let args = _.unroll.from([ _.ointerval.has( ointerval, src ), () => 'Out of ointerval' + _.rangeToStr( ointerval ), _.unrollSelect( arguments, 2 ) ]); + // debugger; + let args = + [ + _.ointerval.has( ointerval, src ) + ,() => 'Out of ointerval' + _.rangeToStr( ointerval ) + , Array.prototype.slice.call( arguments, 2 ) + ]; + _.assert.apply( _, args ); + return true; +} + +// -- +// maker +// -- + +function fromSingle( ointerval ) +{ + _.assert( arguments.length === 1 ); + + if( _.number.is( ointerval ) ) + return [ ointerval, ointerval + 1 ]; + + _.assert( _.longIs( ointerval ) ); + _.assert( ointerval.length === 1 || ointerval.length === 2 ); + + if( ointerval[ 0 ] === undefined ) + { + if( ointerval[ 1 ] === undefined ) + return [ 0, 1 ]; + + _.assert( _.number.is( ointerval[ 1 ] ) ); + return [ ointerval[ 1 ] - 1, ointerval[ 1 ] ]; + } + + _.assert( _.number.is( ointerval[ 0 ] ) ); + + if( ointerval[ 1 ] === undefined ) + return [ ointerval[ 0 ], ointerval[ 0 ] + 1 ]; + + _.assert( _.number.is( ointerval[ 1 ] ) ); + + return ointerval; +} + +// + +function clamp( dstRange, clampRange ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.intervalIs( dstRange ) ); + + if( _.number.is( clampRange ) ) + { + dstRange[ 0 ] = clampRange; + dstRange[ 1 ] = clampRange; + } + else + { + _.assert( _.intervalIs( clampRange ) ); + + if( dstRange[ 0 ] < clampRange[ 0 ] ) + dstRange[ 0 ] = clampRange[ 0 ]; + else if( dstRange[ 0 ] > clampRange[ 1 ] ) + dstRange[ 0 ] = clampRange[ 1 ]; + + if( dstRange[ 1 ] < clampRange[ 0 ] ) + dstRange[ 1 ] = clampRange[ 0 ]; + else if( dstRange[ 1 ] > clampRange[ 1 ] ) + dstRange[ 1 ] = clampRange[ 1 ]; + } + + return dstRange; +} + +// + +function countElements( ointerval, increment ) +{ + + _.assert( _.intervalIs( ointerval ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( increment === undefined ) + increment = 1; + + _.assert( _.number.is( increment ), 'Increment should has a number value' ); + + if( increment ) + { + let result = ( ointerval[ 1 ] - ointerval[ 0 ] ) / increment; + if( result > 0 ) + { + if( result < 1 ) + return 1; + return Math.floor( result ); + } + else if( result < 0 ) + { + if( result > -1 ) + return -1; + return Math.ceil( result ); + } + } + + return 0; +} + +// + +function lastGet( ointerval, options ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + + // options = options || Object.create( null ); /* Dmytro : I don't know why routine makes this side effect */ + // if( options.increment === undefined ) /* The creating of new map has no sense, improved below */ + // options.increment = 1; + + if( options ) + { + _.assert( _.object.like( options ) ); + if( options.increment === undefined ) + options.increment = 1; + } + + if( _.longIs( ointerval ) ) + { + _.assert( _.intervalIs( ointerval ) ); + return ointerval[ 1 ] - 1; + } + else if( _.mapIs( ointerval ) ) + { + return ointerval.last; + } + _.assert( 0, 'unexpected type of ointerval', _.entity.strType( ointerval ) ); + +} + +// -- +// define +// -- + +class Orange +{ + static[ Symbol.hasInstance ]( instance ) + { + return is( instance ); + } +} + +let Handler = +{ + construct( original, args ) + { + return Orange.fromLeft( ... args ); + } +}; + +const Self = new Proxy( Orange, Handler ); +Self.original = Orange; + +// -- +// implementation +// -- + +let Extension = +{ + + // dichotomy + + is : _.intervalIs, + isValid : _.intervalIsValid, + defined : _.intervalIsValid, + isEmpty, + isPopulated, + + has, + + sureIn, + assertIn, + + // maker + + fromLeft : _.cinterval.fromLeft, + fromRight : _.cinterval.fromRight, + fromSingle, + + clamp, + countElements, + firstGet : _.cinterval.firstGet, + lastGet, + + toStr : _.cinterval.toStr, + +} + +// + +_.props.supplement( Self, Extension ); +_.assert( _.ointerval !== undefined ); +_.props.supplement( Self, _.ointerval ); +_.ointerval = Self; +// _.assert( _.auxIs( _.ointerval ) ); /* xxx : uncomment? */ + +/* xxx : qqq : for Dmytro : bad : [ 1, 3 ] instanceof _.ointerval is not covered and does not work! */ + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Intervalo.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Intervalo_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Intervalo_s */ })(); + +/* */ /* begin of file Introspector_s */ ( function Introspector_s() { function Introspector_s_naked() { ( function _Introspector_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global.wTools; +const Self = _.introspector = _.introspector || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +let Extension = +{ +} + +_.props.supplement( _.introspector, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Introspector.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Introspector_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Introspector_s */ })(); + +/* */ /* begin of file Itself_s */ ( function Itself_s() { function Itself_s_naked() { ( function _l5_Itself_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +// + +let ItselfExtension = +{ +} + +Object.assign( _.itself, ItselfExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Itself.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Itself_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Itself_s */ })(); + +/* */ /* begin of file Logic_s */ ( function Logic_s() { function Logic_s_naked() { ( function _l5_Logic_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// logic +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +// + +let LogicExtension = +{ +} + +Object.assign( _.logic, LogicExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Logic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Logic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Logic_s */ })(); + +/* */ /* begin of file Long_s */ ( function Long_s() { function Long_s_naked() { ( function _l5_Long_s_() +{ + +'use strict'; + +const _ArrayIndexOf = Array.prototype.indexOf; +const _ArrayIncludes = Array.prototype.includes; +if( !_ArrayIncludes ) +_ArrayIncludes = function( e ){ _ArrayIndexOf.call( this, e ) } + +const _global = _global_; +const _ = _global_.wTools; + +/* + | can grow | can shrink | range +grow + - positive +only - + positive +relength + + positive +but - + negative +*/ + +/* array / long / buffer */ +/* - / inplace */ + +// -- +// long +// -- + +function _longMake_functor( onMake ) +{ + + _.assert( _.routine.is( onMake ) ); + + return function _longMake( src, ins ) + { + let result; + + /* */ + + let length = ins; + + if( _.longLike( length ) ) + length = length.length; + + if( length === undefined || length === null ) + { + if( src === null ) + { + length = 0; + } + else if( _.longLike( src ) ) + { + length = src.length; + } + else if( _.number.is( src ) ) + { + length = src; + src = null; + } + else if( _.routine.is( src ) ) + { + length = 0; + } + else _.assert( 0 ); + } + + if( !length ) + length = 0; + + /* */ + + if( ins === undefined || ins === null ) + { + if( _.longLike( src ) ) + { + if( ins === null ) + { + ins = src; + } + else + { + ins = src; + // src = null; + } + } + else + { + ins = null; + } + } + else if( !_.longLike( ins ) ) + { + if( _.longIs( src ) ) + ins = src; + else + ins = null; + } + + /**/ + + let minLength; + if( ins ) + minLength = Math.min( ins.length, length ); + else + minLength = 0; + + /**/ + + if( _.argumentsArray.is( src ) ) + src = null; + + let self = this; + if( src === null ) + src = function( src ) + { + return self.tools.long.default.make( src ); + }; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.number.isFinite( length ) ); + _.assert( _.routine.is( src ) || _.longLike( src ), () => 'Expects long, but got ' + _.entity.strType( src ) ); + + result = onMake.call( this, src, ins, length, minLength ); + + _.assert( _.longLike( result ) ); + + return result; + } + +} + +// + +/** + * The routine longMake() returns a new Long with the same type as source Long {-src-}. New Long makes from inserted Long {-ins-} + * or if {-ins-} is number, the Long makes from {-src-} with length equal to {-ins-}. If {-ins-} is not provided, routine makes + * container with default Long type. New Long contains {-src-} elements. + * + * @param { Long|Function|Null } src - Instance of Long or constructor, defines type of returned Long. If null is provided, routine returns + * container with default Long type. + * @param { Number|Long|Null } ins - Defines length of new Long. If Long is provided, routine makes new Long from {-ins-} with {-src-} type. + * If null is provided, then routine makes container with default Long type. + * + * Note. Default Long type defines by descriptor {-longDescriptor-}. If descriptor not provided directly, then it is Array descriptor. + * + * @example + * _.long.make(); + * // returns [] + * + * @example + * _.long.make( null ); + * // returns [] + * + * @example + * _.long.make( null, null ); + * // returns [] + * + * @example + * _.long.make( 3 ); + * // returns [ undefined, undefined, undefined ] + * + * @example + * _.long.make( 3, null ); + * // returns [ undefined, undefined, undefined ] + * + * @example + * _.long.make( [ 1, 2, 3, 4 ] ); + * // returns [ 1, 2, 3, 4 ]; + * + * @example + * _.long.make( [ 1, 2, 3, 4 ], null ); + * // returns [ 1, 2, 3, 4 ]; + * + * @example + * _.long.make( [ 1, 2 ], 4 ); + * // returns [ 1, 2, undefined, undefined ]; + * + * @example + * let got = _.long.make( _.unroll.make( [] ), [ 1, 2, 3 ] ); + * console.log( got ); + * // log [ 1, 2, 3 ]; + * console.log( _.unrollIs( got ) ); + * // log true + * + * @example + * let got = _.long.make( new F32x( [ 1, 2, 3 ] ), 1 ); + * console.log( got ); + * // log Float32Array[ 1 ]; + * + * @example + * let got = _.long.make( Array, null ); + * console.log( got ); + * // log []; + * + * @example + * let got = _.long.make( Array, 3 ); + * console.log( got ); + * // log [ undefined, undefined, undefined ]; + * + * @returns { Long } - Returns a Long with type of source Long {-src-} which makes from {-ins-}. If {-ins-} is not + * provided, then routine returns container with default Long type. + * @function longMake + * @throws { Error } If arguments.length is more then two. + * @throws { Error } If {-src-} is not a Long, not a constructor, not null. + * @throws { Error } If {-ins-} is not a number, not a Long, not null, not undefined. + * @throws { Error } If {-ins-} or ins.length has a not finite value. + * @namespace Tools + */ + +/* aaa : extend coverage and documentation of longMake */ +/* Dmytro : extended coverage and documentation of routine longMake */ +/* aaa : longMake does not create unrolls, but should */ +/* Dmytro : longMake creates unrolls */ + +// let longMake = _longMake_functor( function( /* src, ins, length, minLength */ ) +// { +// let src = arguments[ 0 ]; +// let ins = arguments[ 1 ]; +// let length = arguments[ 2 ]; +// let minLength = arguments[ 3 ]; +// +// let result; +// if( _.routine.is( src ) ) +// { +// if( ins && ins.length === length ) +// { +// if( src === Array ) +// { +// if( _.longLike( ins ) ) +// { +// if( ins.length === 1 ) +// result = [ ins[ 0 ] ]; +// else if( !_.argumentsArray.like( ins ) ) +// result = new( _.constructorJoin( src, [ ... ins ] ) ); +// else +// result = new( _.constructorJoin( src, ins ) ); +// } +// else +// { +// result = new src( ins ); +// } +// } +// else +// { +// result = new src( ins ); +// } +// } +// else +// { +// result = new src( length ); +// // let minLength = Math.min( length, ins.length ); +// for( let i = 0 ; i < minLength ; i++ ) +// result[ i ] = ins[ i ]; +// } +// } +// else if( _.arrayIs( src ) ) +// { +// _.assert( length >= 0 ); +// result = _.unrollIs( src ) ? _.unroll.make( length ) : new src.constructor( length ); +// // let minLength = Math.min( length, ins.length ); +// for( let i = 0 ; i < minLength ; i++ ) +// result[ i ] = ins[ i ]; +// } +// else +// { +// if( ins && length === ins.length ) +// { +// result = new src.constructor( ins ); +// } +// else +// { +// result = new src.constructor( length ); +// // let minLength = Math.min( length, ins.length ); +// for( let i = 0 ; i < minLength ; i++ ) +// result[ i ] = ins[ i ]; +// } +// } +// +// return result; +// }); + +// function longMake( src, ins ) +// { +// let result; +// let length = ins; +// +// if( _.longLike( length ) ) +// length = length.length; +// +// if( length === undefined ) +// { +// if( src === null ) +// { +// length = 0; +// } +// else if( _.longLike( src ) ) +// { +// length = src.length; +// } +// else if( _.number.is( src ) ) +// { +// length = src; +// src = null; +// } +// else _.assert( 0 ); +// } +// +// // if( !_.longLike( ins ) ) +// // { +// // if( _.longLike( src ) ) +// // ins = src; +// // else +// // ins = []; +// // } +// +// if( !_.longLike( ins ) ) +// { +// if( _.longLike( src ) ) +// { +// ins = src; +// src = null; +// } +// else +// { +// ins = []; +// } +// } +// +// if( !length ) +// length = 0; +// +// if( _.argumentsArray.is( src ) ) +// src = null; +// +// if( src === null ) +// src = this.tools.long.default.make; +// +// _.assert( arguments.length === 1 || arguments.length === 2 ); +// _.assert( _.number.isFinite( length ) ); +// _.assert( _.routine.is( src ) || _.longLike( src ), () => 'Expects long, but got ' + _.entity.strType( src ) ); +// +// if( _.routine.is( src ) ) +// { +// if( ins.length === length ) +// { +// if( src === Array ) +// { +// if( _.longLike( ins ) ) +// { +// if( ins.length === 1 ) +// result = [ ins[ 0 ] ]; +// else if( !_.argumentsArray.like( ins ) ) +// result = new( _.constructorJoin( src, [ ... ins ] ) ); +// else +// result = new( _.constructorJoin( src, ins ) ); +// } +// else +// { +// result = new src( ins ); +// } +// } +// else +// { +// result = new src( ins ); +// } +// } +// else +// { +// result = new src( length ); +// let minLen = Math.min( length, ins.length ); +// for( let i = 0 ; i < minLen ; i++ ) +// result[ i ] = ins[ i ]; +// } +// } +// else if( _.arrayIs( src ) ) +// { +// if( length === ins.length ) +// { +// result = _.unrollIs( src ) ? _.unroll.make( ins ) : new( _.constructorJoin( src.constructor, ins ) ); +// } +// else +// { +// _.assert( length >= 0 ); +// result = _.unrollIs( src ) ? _.unroll.make( length ) : new src.constructor( length ); +// let minLen = Math.min( length, ins.length ); +// for( let i = 0 ; i < minLen ; i++ ) +// result[ i ] = ins[ i ]; +// } +// } +// else +// { +// if( length === ins.length ) +// { +// result = new src.constructor( ins ); +// } +// else +// { +// result = new src.constructor( length ); +// let minLen = Math.min( length, ins.length ); +// for( let i = 0 ; i < minLen ; i++ ) +// result[ i ] = ins[ i ]; +// } +// } +// +// _.assert( result instanceof this.tools.long.default.InstanceConstructor ); +// // _.assert( _.longLike( result ) ); +// +// return result; +// } + +// + +/* aaa : implement test */ +/* Dmytro : implemented */ + +function longMakeEmpty( src ) +{ + if( arguments.length === 0 ) + return this.tools.long.default.make( 0 ); + + _.assert( arguments.length === 1 ); + + if( _.unrollIs( src ) ) + { + return _.unroll.make( 0 ); + } + else if( src === null || _.argumentsArray.is( src ) ) + { + return this.tools.long.default.make( 0 ); + } + // else if( _.longLike( src ) ) + else if( _.vector.like( src ) ) + { + return new src.constructor(); + } + // else if( _.routine.is( src ) ) /* aaa : it was covered badly! */ /* Dmytro : coverage is extended */ + else if( _.routine.is( src.constructor ) ) + { + let result = new src(); + // let result = new src.onstructor(); /* Dmytro : src is a class, it calls without constructor property */ + // _.assert( _.long.lengthOf( result ) === 0, 'Constructor should return empty long' ); + _.assert( result.length === 0, 'Constructor should return empty long' ); + return result; + } + _.assert( 0, `Unknown long subtype ${_.entity.strType( src )}` ); +} + +// function longMakeEmpty( src ) +// { +// let result; +// let length = 0; +// +// if( src === null ) +// src = []; +// +// if( _.argumentsArray.is( src ) ) +// src = []; +// +// _.assert( arguments.length === 1 ); +// +// result = new src.constructor(); +// +// _.assert( _.longIs( result ) ); +// _.assert( result.length === 0 ); +// +// return result; +// } + +// // +// +// let _longMakeOfLength = _longMake_functor( function( /* src, ins, length, minLength */ ) +// { +// let src = arguments[ 0 ]; +// let ins = arguments[ 1 ]; +// let length = arguments[ 2 ]; +// let minLength = arguments[ 3 ]; +// +// let result; +// if( _.routine.is( src ) ) +// { +// result = new src( length ); +// } +// else if( _.arrayIs( src ) ) +// { +// if( length === src.length ) +// { +// result = new( _.constructorJoin( src.constructor, src ) ); +// } +// else if( length < src.length ) +// { +// result = src.slice( 0, length ); +// } +// else +// { +// result = new src.constructor( length ); +// for( let i = 0 ; i < minLength ; i++ ) +// result[ i ] = src[ i ]; +// } +// } +// else +// { +// if( length === src.length ) +// { +// result = new src.constructor( ins ); +// } +// else +// { +// result = new src.constructor( length ); +// for( let i = 0 ; i < minLength ; i++ ) +// result[ i ] = src[ i ]; +// } +// } +// +// return result; +// }); + +// function _longMakeOfLength( src, len ) +// { +// let result; +// +// // if( src === null ) +// // src = []; +// +// if( _.longLike( len ) ) +// len = len.length; +// +// if( len === undefined ) +// { +// if( src === null ) +// { +// len = 0; +// } +// else if( _.longLike( src ) ) +// { +// len = src.length; +// } +// else if( _.number.is( src ) ) +// { +// len = src; +// src = null; +// } +// else _.assert( 0 ); +// } +// +// if( !len ) +// len = 0; +// +// if( _.argumentsArray.is( src ) ) +// src = this.tools.long.default.name === 'ArgumentsArray' ? this.tools.long.default.make : this.tools.long.default.make( src ); +// +// if( src === null ) +// src = this.tools.long.default.make; +// +// _.assert( arguments.length === 1 || arguments.length === 2 ); +// _.assert( _.number.isFinite( len ) ); +// _.assert( _.routine.is( src ) || _.longLike( src ), () => 'Expects long, but got ' + _.entity.strType( src ) ); +// +// if( _.routine.is( src ) ) +// { +// result = new src( len ); +// } +// else if( _.arrayIs( src ) ) +// { +// if( len === src.length ) +// { +// result = new( _.constructorJoin( src.constructor, src ) ); +// } +// else if( len < src.length ) +// { +// result = src.slice( 0, len ); +// } +// else +// { +// result = new src.constructor( len ); +// let minLen = Math.min( len, src.length ); +// for( let i = 0 ; i < minLen ; i++ ) +// result[ i ] = src[ i ]; +// } +// } +// else +// { +// if( len === src.length ) +// { +// result = new src.constructor( len ); +// } +// else +// { +// result = new src.constructor( len ); +// let minLen = Math.min( len, src.length ); +// for( let i = 0 ; i < minLen ; i++ ) +// result[ i ] = src[ i ]; +// } +// } +// +// _.assert( _.longLike( result ), 'Instance should be a long' ); +// +// return result; +// } + +// + +/** + * The routine longMakeUndefined() returns a new Long with the same type as source Long {-src-}. New Long has length equal to {-ins-} + * argument. If {-ins-} is not provided, then new container has default Long type and length of source Long {-src-}. + * + * @param { Long|Function|Null } src - Long or constructor, defines type of returned Long. If null is provided, then routine returns + * container with default Long type. + * @param { Number|Long } ins - Defines length of new Long. If {-ins-} is Long, then routine makes new Long with length equal to ins.length. + * + * Note. Default Long type defines by descriptor {-longDescriptor-}. If descriptor not provided directly, then it is Array descriptor. + * + * @example + * _.long.makeUndefined(); + * // returns [] + * + * @example + * _.long.makeUndefined( null ); + * // returns [] + * + * @example + * _.long.makeUndefined( null, null ); + * // returns [] + * + * @example + * _.long.makeUndefined( 3 ); + * // returns [ undefined, undefined, undefined ] + * + * @example + * _.long.makeUndefined( 3, undefined ); + * // returns [ undefined, undefined, undefined ] + * + * @example + * _.long.makeUndefined( [ 1, 2, 3, 4 ] ); + * // returns [ undefined, undefined, undefined, undefined ]; + * + * @example + * _.long.makeUndefined( [ 1, 2, 3, 4 ], null ); + * // returns [ undefined, undefined, undefined, undefined ]; + * + * @example + * _.long.makeUndefined( [ 1, 2, 3, 4 ], 2 ); + * // returns [ undefined, undefined ]; + * + * @example + * let got = _.long.makeUndefined( _.unroll.make( [] ), [ 1, 2, 3 ] ); + * console.log( got ); + * // log [ undefined, undefined, undefined ]; + * console.log( _.unrollIs( got ) ); + * // log true + * + * @example + * let got = _.long.makeUndefined( new F32x( [ 1, 2, 3, 4 ] ), 2 ); + * console.log( got ); + * // log Float32Array[ undefined, undefined ]; + * + * @example + * let got = _.long.makeUndefined( Array, null ); + * console.log( got ); + * // log []; + * + * @example + * let got = _.long.makeUndefined( Array, 3 ); + * console.log( got ); + * // log [ undefined, undefined, undefined ]; + * + * @returns { Long } - Returns a Long with type of source Long {-src-} with a certain length defined by {-ins-}. + * If {-ins-} is not defined, then routine returns container with default Long type. Length of the new container defines by {-src-}. + * @function longMakeUndefined + * @throws { Error } If arguments.length is more then two. + * @throws { Error } If the {-src-} is not a Long, not a constructor, not null. + * @throws { Error } If the {-ins-} is not a number, not a Long, not null, not undefined. + * @throws { Error } If the {-ins-} or ins.length has a not finite value. + * @namespace Tools + */ + +/* +aaa : extend coverage and documentation of longMakeUndefined +Dmytro : extended coverage and documentation +aaa : longMakeUndefined does not create unrolls, but should +Dmytro : longMakeUndefined creates unrolls. +*/ + +// let longMakeUndefined = _longMake_functor( function( /* src, ins, length, minLength */ ) +// { +// let src = arguments[ 0 ]; +// let ins = arguments[ 1 ]; +// let length = arguments[ 2 ]; +// let minLength = arguments[ 3 ]; +// +// let result; +// if( _.routine.is( src ) ) +// result = new src( length ); +// else if( _.unrollIs( src ) ) +// result = _.unroll.make( length ); +// else if( src === null ) +// result = this.tools.long.default.make( length ); +// else +// result = new src.constructor( length ); +// +// return result; +// }) + +// function longMakeUndefined( ins, len ) +// { +// let result, length; +// +// /* aaa3 : ask. use default long container */ +// /* Dmytro : explained, used this.tools.longDescriptor */ +// // if( ins === null ) +// // result = []; +// +// if( len === undefined ) +// { +// if( ins === null ) +// { +// length = 0; +// } +// else if( _.number.is( ins ) ) +// { +// length = ins; +// ins = null; +// } +// else +// { +// length = ins.length; +// } +// } +// else +// { +// if( _.longLike( len ) ) +// length = len.length; +// else if( _.number.is( len ) ) +// length = len; +// else _.assert( 0 ); +// } +// +// if( _.argumentsArray.is( ins ) ) +// ins = null; +// +// _.assert( arguments.length === 1 || arguments.length === 2 ); +// _.assert( _.number.isFinite( length ) ); +// _.assert( _.routine.is( ins ) || _.longLike( ins ) || ins === null, () => 'Expects long, but got ' + _.entity.strType( ins ) ); +// +// if( _.routine.is( ins ) ) +// result = new ins( length ); +// else if( _.unrollIs( ins ) ) +// result = _.unroll.make( length ); +// else if( ins === null ) /* aaa3 : ask */ +// result = this.tools.long.default.make( length ); +// else +// result = new ins.constructor( length ); +// +// return result; +// } + +// + +/* aaa3 : teach to accept only length */ +/* aaa3 : use default long type if type is not clear */ +/* aaa3 : allow buffers which are long */ +/* aaa3 : relevant to all routines longMake* of such kind */ +/* Dmytro : all requirements implemented and covered */ + +// let longMakeZeroed = _longMake_functor( function( /* src, ins, length, minLength */ ) +// { +// let src = arguments[ 0 ]; +// let ins = arguments[ 1 ]; +// let length = arguments[ 2 ]; +// let minLength = arguments[ 3 ]; +// +// let result; +// if( _.routine.is( src ) ) +// result = new src( length ); +// else if( _.unrollIs( src ) ) +// result = _.unroll.make( length ); +// else if( src === null ) +// result = this.tools.long.default.make( length ); +// else +// result = new src.constructor( length ); +// +// if( !_.bufferTypedIs( result ) ) +// { +// for( let i = 0 ; i < length ; i++ ) +// result[ i ] = 0; +// } +// +// return result; +// }) + +// function longMakeZeroed( ins, src ) +// { +// let result, length; +// +// if( _.routine.is( ins ) ) +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// +// if( src === undefined ) +// { +// length = ins.length; +// } +// else +// { +// if( _.longLike( src ) ) +// length = src.length; +// else if( _.number.is( src ) ) +// length = src; +// else _.assert( 0, 'Expects long or number as the second argument, got', _.entity.strType( src ) ); +// } +// +// if( _.argumentsArray.is( ins ) ) +// ins = []; +// +// _.assert( arguments.length === 1 || arguments.length === 2 ); +// _.assert( _.number.isFinite( length ) ); +// _.assert( _.routine.is( ins ) || _.longLike( ins ), () => 'Expects long, but got ' + _.entity.strType( ins ) ); +// +// if( _.routine.is( ins ) ) +// result = new ins( length ); +// else if( _.unrollIs( ins ) ) +// result = _.unroll.make( length ); +// else +// result = new ins.constructor( length ); +// +// if( !_.bufferTypedIs( result ) ) +// for( let i = 0 ; i < length ; i++ ) +// result[ i ] = 0; +// +// return result; +// } + +function longMakeFilling( type, value, length ) +{ + let result; + + // _.assert( arguments.length === 2 || arguments.length === 3 ); /* Dmytro : double check */ + + if( arguments.length === 2 ) + { + value = arguments[ 0 ]; + length = arguments[ 1 ]; + if( _.longIs( length ) ) + { + if( _.argumentsArray.is( length ) ) + type = null; + else + type = length.constructor; + } + else + { + type = null; + } + } + else if( arguments.length !== 3 ) + { + _.assert( 0, 'Expects two or three arguments' ); + } + + /* Dmytro : missed */ + if( _.longIs( length ) ) + length = length.length; + + _.assert( value !== undefined ); + _.assert( _.number.is( length ) ); + _.assert( type === null || _.routine.is( type ) || _.longIs( type ) ); + + result = this.long.make( type, length ); + for( let i = 0 ; i < length ; i++ ) + result[ i ] = value; + + return result; +} + +// + +/* aaa : add good coverage for longFrom. */ +/* Dmytro : covered, two test routines implemented */ + +function longFrom( src ) +{ + _.assert( arguments.length === 1 ); + if( src instanceof this.tools.long.default.InstanceConstructor ) + if( !_.unrollIs( src ) && _.longIs( src ) ) + return src; + return this.longMake.call( this, src ); +} + +// + +/** + * The routine longFromCoercing() returns Long from provided argument {-src-}. The feature of routine is possibility of + * converting an object-like {-src-} into Long. Also, routine longFromCoercing() converts string with number literals + * to a Long. + * If routine convert {-src-}, then result returns in container with default Long type. + * + * @param { Long|ObjectLike|String } src - An instance to convert into Long. + * If {-src-} is a Long and it type is equal to current default Long type, then routine convert not {-src-}. + * + * Note. Default Long type defines by descriptor {-longDescriptor-}. If descriptor not provided directly, then it is Array descriptor. + * + * @example + * let src = [ 3, 7, 13, 'abc', false, undefined, null, {} ]; + * let got = _.longFromCoercing( src ); + * // returns [ 3, 7, 13, 'abc', false, undefined, null, {} ] + * console.log( got === src ); + * // log true + * + * @example + * let src = _.argumentsArray.make( [ 3, 7, 13, 'abc', false, undefined, null, {} ] ); + * let got = _.longFromCoercing( src ); + * // returns [ 3, 7, 13, 'abc', false, undefined, null, {} ] + * console.log( got === src ); + * // log false + * + * @example + * let src = { a : 3, b : 7, c : 13 }; + * let got = _.longFromCoercing( src ); + * // returns [ [ 'a', 3 ], [ 'b', 7 ], [ 'c', 13 ] ] + * + * @example + * let src = "3, 7, 13, 3.5abc, 5def, 7.5ghi, 13jkl"; + * let got = _.longFromCoercing( src ); + * // returns [ 3, 7, 13, 3.5, 5, 7.5, 13 ] + * + * @returns { Long } - Returns a Long. If {-src-} is Long with default Long type, then routine returns original {-src-}. + * Otherwise, it makes new container with default Long type. + * @function longFromCoercing + * @throws { Error } If arguments.length is less or more then one. + * @throws { Error } If {-src-} is not a Long, not an object-like, not a string. + * @namespace Tools + */ + +function longFromCoercing( src ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( this.long.default.InstanceConstructor ) + if( src instanceof this.long.default.InstanceConstructor && _.longIs( src ) ) + return src; + + /* Dmytro : this condition make recursive call with array from argumentsArray. But first condition return any long object + ( ArgumentsArray.type is Object ), and next make other long types without recursive call */ + // if( _.argumentsArray.is( src ) ) + // return this.longFromCoercing( Array.prototype.slice.call( src ) ); + + if( _.longIs( src ) ) + return this.long.default.from( src ); + + if( _.object.isBasic( src ) ) + return this.longFromCoercing( _.props.pairs( src ) ); + + /* aaa : cover */ + /* Dmytro : covered */ + if( _.strIs( src ) ) + return this.longFromCoercing( this.arrayFromStr( src ) ); + + _.assert( 0, `Unknown data type : ${ _.entity.strType( src ) }` ); +} + +// + +/** + * The routine longFill() fills elements the given Long {-src-} by static value. The range of replaced elements + * defines by a parameter {-range-}. If it possible, routine longFill() saves original container {-src-}. + * + * @param { Long } src - The source Long. + * @param { * } value - Any value to fill the elements in the {-src-}. + * If {-value-} is not provided, the routine fills elements of source Long by 0. + * @param { Range|Number } range - The two-element array that defines the start index and the end index for copying elements. + * If {-range-} is number, then it defines the end index, and the start index is 0. + * If range[ 0 ] < 0, then start index sets to 0, end index increments by absolute value of range[ 0 ]. + * If range[ 1 ] <= range[ 0 ], then routine returns a copy of original Long. + * If {-range-} is not provided, routine fills all elements of the {-src-}. + * + * @example + * _.longFill( [ 1, 2, 3, 4, 5 ] ); + * // returns [ 0, 0, 0, 0, 0 ] + * + * @example + * _.longFill( [ 1, 2, 3, 4, 5 ], 'a' ); + * // returns [ 'a', 'a', 'a', 'a', 'a' ] + * + * @example + * _.longFill( [ 1, 2, 3, 4, 5 ], 'a', 2 ); + * // returns [ 'a', 'a', 3, 4, 5 ] + * + * @example + * _.longFill( [ 1, 2, 3, 4, 5 ], 'a', [ 1, 3 ] ); + * // returns [ 1, 'a', 'a', 4, 5 ] + * + * @example + * _.longFill( [ 1, 2, 3, 4, 5 ], 'a', [ -1, 3 ] ); + * // returns [ 'a', 'a', 'a', 'a', 5 ] + * + * @example + * _.longFill( [ 1, 2, 3, 4, 5 ], 'a', [ 4, 3 ] ); + * // returns [ 1, 2, 3, 4, 5 ] + * + * @returns { Long } - If it is possible, returns the source Long filled with a static value. + * Otherwise, returns copy of the source Long filled with a static value. + * @function longFill + * @throws { Error } If arguments.length is less then one or more then three. + * @throws { Error } If {-src-} is not a Long. + * @throws { Error } If {-range-} is not a Range or not a Number. + * @namespace Tools + */ + +function longFill( src, value, range ) +{ + + if( range === undefined ) + range = [ 0, src.length ]; + if( _.number.is( range ) ) + range = [ 0, range ]; + + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + _.assert( _.longIs( src ) ); + _.assert( _.intervalIs( range ) ); + + if( value === undefined ) + value = 0; + + // src = _.longGrowInplace( src, range ); + src = _.longGrow_( src, src, [ range[ 0 ], range[ 1 ] - 1 ] ); + + let offset = Math.max( -range[ 0 ], 0 ); + + if( range[ 0 ] < 0 ) + { + range[ 1 ] -= range[ 0 ]; + range[ 0 ] = 0; + } + + if( _.routine.is( src.fill ) ) + { + src.fill( value, range[ 0 ], range[ 1 ] + offset ); + } + else + { + for( let t = range[ 0 ] ; t < range[ 1 ] + offset ; t++ ) + src[ t ] = value; + } + + return src; +} + +// + +function longFill_( src, ins, cinterval ) +{ + + if( cinterval === undefined ) + cinterval = [ 0, src.length - 1 ]; + if( _.number.is( cinterval ) ) + cinterval = [ 0, cinterval - 1 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + _.assert( _.longIs( src ) ); + _.assert( _.intervalIs( cinterval ) ); + + if( ins === undefined ) + ins = 0; + + src = _.longGrow_( src, src, cinterval ); + + let offset = Math.max( -cinterval[ 0 ], 0 ); + + if( cinterval[ 0 ] < 0 ) + { + cinterval[ 1 ] -= cinterval[ 0 ]; + cinterval[ 0 ] = 0; + } + + if( _.routine.is( src.fill ) ) + { + src.fill( ins, cinterval[ 0 ], cinterval[ 1 ] + 1 + offset ); + } + else + { + for( let t = cinterval[ 0 ] ; t < cinterval[ 1 ] + 1 + offset ; t++ ) + src[ t ] = ins; + } + + return src; +} + +// + +/** + * The longDuplicate() routine returns an array with duplicate values of a certain number of times. + * + * @param { objectLike } [ o = { } ] o - The set of arguments. + * @param { longIs } o.src - The given initial array. + * @param { longIs } o.result - To collect all data. + * @param { Number } [ o.nScalarsPerElement = 1 ] o.nScalarsPerElement - The certain number of times + * to append the next value from (srcArray or o.src) to the (o.result). + * If (o.nScalarsPerElement) is greater that length of a (srcArray or o.src) it appends the 'undefined'. + * @param { Number } [ o.nDupsPerElement = 2 ] o.nDupsPerElement = 2 - The number of duplicates per element. + * + * @example + * _.longDuplicate( [ 'a', 'b', 'c' ] ); + * // returns [ 'a', 'a', 'b', 'b', 'c', 'c' ] + * + * @example + * let options = { + * src : [ 'abc', 'def' ], + * result : [ ], + * nScalarsPerElement : 2, + * nDupsPerElement : 3 + * }; + * _.longDuplicate( options, {} ); + * // returns [ 'abc', 'def', 'abc', 'def', 'abc', 'def' ] + * + * @example + * let options = { + * src : [ 'abc', 'def' ], + * result : [ ], + * nScalarsPerElement : 3, + * nDupsPerElement : 3 + * }; + * _.longDuplicate( options, { a : 7, b : 13 } ); + * // returns [ 'abc', 'def', undefined, 'abc', 'def', undefined, 'abc', 'def', undefined ] + * + * @returns { Array } Returns an array with duplicate values of a certain number of times. + * @function longDuplicate + * @throws { Error } Will throw an Error if ( o ) is not an objectLike. + * @namespace Tools + */ + +function longDuplicate( o ) /* xxx : review interface */ +{ + // _.assert( arguments.length === 1 || arguments.length === 2 ); + + _.assert( _.mapIs( o ) ); + + // if( arguments.length === 2 ) + // { + // o = { src : arguments[ 0 ], nDupsPerElement : arguments[ 1 ] }; + // } + // else if( arguments.length === 1 ) + // { + // if( !_.mapIs( o ) ) + // o = { src : o }; + // } + // else _.assert( 0 ); + + if( o.nScalarsPerElement === 0 ) + if( o.src.length === 0 ) + o.nScalarsPerElement = 1; + else + o.nScalarsPerElement = o.src.length; + + _.routine.options( longDuplicate, o ); + _.assert( _.number.is( o.nDupsPerElement ) ); + _.assert( _.longIs( o.src ), 'Expects Long {-o.src-}' ); + _.assert( _.intIs( o.src.length / o.nScalarsPerElement ) ); + + if( o.nDupsPerElement === 1 ) + { + if( o.dst ) + { + _.assert( _.longIs( o.dst ) || _.bufferTypedIs( o.dst ), 'Expects o.dst as longIs or TypedArray if nDupsPerElement equals 1' ); + + if( _.bufferTypedIs( o.dst ) ) + o.dst = _.longJoin( o.dst, o.src ); + else if( _.longIs( o.dst ) ) + o.dst.push.apply( o.dst, o.src ); + } + else + { + o.dst = o.src; + } + return o.dst; + } + + let length = o.src.length * o.nDupsPerElement; + let numberOfElements = o.src.length / o.nScalarsPerElement; + + if( o.dst ) + _.assert( o.dst.length >= length ); + + o.dst = o.dst || _.long.makeUndefined( o.src, length ); + + let rlength = o.dst.length; + + for( let c = 0, cl = numberOfElements ; c < cl ; c++ ) + { + + for( let d = 0, dl = o.nDupsPerElement ; d < dl ; d++ ) + { + + for( let e = 0, el = o.nScalarsPerElement ; e < el ; e++ ) + { + let indexDst = c*o.nScalarsPerElement*o.nDupsPerElement + d*o.nScalarsPerElement + e; + let indexSrc = c*o.nScalarsPerElement+e; + o.dst[ indexDst ] = o.src[ indexSrc ]; + } + + } + + } + + _.assert( o.dst.length === rlength ); + + return o.dst; +} + +longDuplicate.defaults = /* qqq : cover. take into account extreme cases */ +{ + src : null, + dst : null, + nScalarsPerElement : 1, + nDupsPerElement : 2, +} + +// + +/* +aaa : find and let me know what is _.buffer* analog of _longClone | +aaa Dmytro : module has not _.buffer* analog of routine _longClone. The closest functionality has routine bufferMake( ins, src ) +zzz +*/ + +// function _longClone( src ) /* qqq for Dmyto : _longClone should not accept untyped buffers. _bufferClone should accept untyped buffer */ +function _longClone( src ) /* qqq for Dmyto : _longClone should not accept untyped buffers. _bufferClone should accept untyped buffer */ +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.longLike( src ) || _.bufferAnyIs( src ) ); + // _.assert( !_.bufferNodeIs( src ), 'not tested' ); + + if( _.unrollIs( src ) ) + return _.unroll.make( src ); + else if( _.arrayIs( src ) ) + return src.slice(); + else if( _.argumentsArray.is( src ) ) + return Array.prototype.slice.call( src ); + else if( _.bufferRawIs( src ) ) + return new U8x( new U8x( src ) ).buffer; + else if( _.bufferTypedIs( src ) || _.bufferNodeIs( src ) ) + return new src.constructor( src ); + else if( _.bufferViewIs( src ) ) + return new src.constructor( src.buffer, src.byteOffset, src.byteLength ); + + _.assert( 0, 'unknown kind of buffer', _.entity.strType( src ) ); +} + +// + +/** + * Returns a copy of original array( array ) that contains elements from index( f ) to index( l ), + * but not including ( l ). + * + * If ( l ) is omitted or ( l ) > ( array.length ), _longShallow extracts through the end of the sequence ( array.length ). + * If ( f ) > ( l ), end index( l ) becomes equal to begin index( f ). + * If ( f ) < 0, zero is assigned to begin index( f ). + + * @param { Array/BufferNode } array - Source array or buffer. + * @param { Number } [ f = 0 ] f - begin zero-based index at which to begin extraction. + * @param { Number } [ l = array.length ] l - end zero-based index at which to end extraction. + * + * @example + * _._longShallow( [ 1, 2, 3, 4, 5, 6, 7 ], 2, 6 ); + * // returns [ 3, 4, 5, 6 ] + * + * @example + * // begin index is less then zero + * _._longShallow( [ 1, 2, 3, 4, 5, 6, 7 ], -1, 2 ); + * // returns [ 1, 2 ] + * + * @example + * // end index is bigger then length of array + * _._longShallow( [ 1, 2, 3, 4, 5, 6, 7 ], 5, 100 ); + * // returns [ 6, 7 ] + * + * @returns { Array } Returns a shallow copy of elements from the original array. + * @function _longShallow + * @throws { Error } Will throw an Error if ( array ) is not an Array or BufferNode. + * @throws { Error } Will throw an Error if ( f ) is not a Number. + * @throws { Error } Will throw an Error if ( l ) is not a Number. + * @throws { Error } Will throw an Error if no arguments provided. + * @namespace Tools + */ + +/* aaa : optimize */ +/* Dmytro : optimized */ + +// function longSlice( array, f, l ) +function _longShallow( src, f, l ) +{ + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + _.assert( _.longIs( src ), 'Expects long {-src-}' ); + _.assert( f === undefined || _.number.is( f ) ); + _.assert( l === undefined || _.number.is( l ) ); + + /* xxx qqq for Dmytro : check and cover */ + + f = f === undefined ? 0 : f; + l = l === undefined ? src.length : l; + + if( f < 0 ) + f = src.length + f; + if( l < 0 ) + l = src.length + l; + + if( f < 0 ) + f = 0; + if( f > l ) + l = f; + + if( _.bufferTypedIs( src ) ) + return _.longOnly_( null, src, [ f, l - 1 ] ); + return Array.prototype.slice.call( src, f, l ); + + // if( _.bufferTypedIs( src ) ) + // return src.subsrc( f, l ); + // else if( _.srcLikeResizable( src ) ) + // return src.slice( f, l ); + // else if( _.argumentssrcIs( src ) ) + // return src.prototype.slice.call( src, f, l ); + // else + // _.assert( 0 ); +} + +// + +/** + * The longRepresent() routine returns a shallow copy of a portion of an array + * or a new TypedArray that contains + * the elements from (begin) index to the (end) index, + * but not including (end). + * + * @param { Array } src - Source array. + * @param { Number } begin - Index at which to begin extraction. + * @param { Number } end - Index at which to end extraction. + * + * @example + * _.longRepresent( [ 1, 2, 3, 4, 5 ], 2, 4 ); + * // returns [ 3, 4 ] + * + * @example + * _.longRepresent( [ 1, 2, 3, 4, 5 ], -4, -2 ); + * // returns [ 2, 3 ] + * + * @example + * _.longRepresent( [ 1, 2, 3, 4, 5 ] ); + * // returns [ 1, 2, 3, 4, 5 ] + * + * @returns { Array } - Returns a shallow copy of a portion of an array into a new Array. + * @function longRepresent + * @throws { Error } If the passed arguments is more than three. + * @throws { Error } If the first argument is not an array. + * @namespace Tools + */ + +/* qqq2 : review. ask */ +/* qqq2 : implement bufferRepresent_( any buffer ) +should return undefined if cant create representation +let representation = _.bufferRepresent_( src ); +representation[ 4 ] = x; // src changed too +*/ + +/* qqq2 : implement longRepresent_( src, cinterval ~ [ first, last ] ) */ +/* xxx qqq for Dmytro : implement longRepresent_ */ + +function longRepresent( src, begin, end ) +{ + + _.assert( arguments.length <= 3 ); + _.assert( _.longLike( src ), 'Unknown type of (-src-) argument' ); + _.assert( _.routine.is( src.slice ) || _.routine.is( src.subarray ) ); + + if( _.routine.is( src.subarray ) ) + return src.subarray( begin, end ); + + return src.slice( begin, end ); +} + +// function longSlice( array, f, l ) +// { +// let result; +// +// if( _.argumentsArray.is( array ) ) +// if( f === undefined && l === undefined ) +// { +// if( array.length === 2 ) +// return [ array[ 0 ], array[ 1 ] ]; +// else if( array.length === 1 ) +// return [ array[ 0 ] ]; +// else if( array.length === 0 ) +// return []; +// } +// +// _.assert( _.longIs( array ) ); +// _.assert( 1 <= arguments.length && arguments.length <= 3 ); +// +// if( _.arrayLikeResizable( array ) ) +// { +// _.assert( f === undefined || _.number.is( f ) ); +// _.assert( l === undefined || _.number.is( l ) ); +// result = array.slice( f, l ); +// return result; +// } +// +// f = f !== undefined ? f : 0; +// l = l !== undefined ? l : array.length; +// +// _.assert( _.number.is( f ) ); +// _.assert( _.number.is( l ) ); +// +// if( f < 0 ) +// f = array.length + f; +// if( l < 0 ) +// l = array.length + l; +// +// if( f < 0 ) +// f = 0; +// if( l > array.length ) +// l = array.length; +// if( l < f ) +// l = f; +// +// result = _.long.makeUndefined( array, l-f ); +// // if( _.bufferTypedIs( array ) ) +// // result = new array.constructor( l-f ); +// // else +// // result = new Array( l-f ); +// +// for( let r = f ; r < l ; r++ ) +// result[ r-f ] = array[ r ]; +// +// return result; +// } + +// + +/** + * The routine longJoin() makes new container with type defined by first argument. Routine clones content of provided arguments + * into created container. + * + * @param { Long|Buffer } arguments[ 0 ] - Long or Buffer, defines type of returned container. If provided only {-arguments[ 0 ]-}, then + * routine makes shallow copy of it. + * @param { * } ... - Arguments to make copy into new container. Can have any types exclude undefined. + * + * @example + * let src = []; + * let got = _.longJoin( src ); + * console.log( got ); + * // log [] + * console.log( src === got ); + * // log false + * + * @example + * var src = new U8x( [ 1, 2, 3, 4 ] ); + * var got = _.longJoin( src ); + * console.log( got ); + * // log Uint8Array [ 1, 2, 3, 4 ]; + * console.log( src === got ); + * // log false + * + * @example + * let src = _.unroll.make( [] ); + * let got = _.longJoin( src, 1, 'str', new F32x( [ 3 ] ) ); + * console.log( got ); + * // log [ 1, 'str', 3 ] + * console.log( _.unrollIs( got ) ); + * // log true + * console.log( src === got ); + * // log false + * + * @example + * let src = new BufferRaw( 3 ); + * let got = _.longJoin( src, 1, 2, _.argumentsArray.make( [ 3, 4 ] ) ); + * console.log( got ); + * // log ArrayBuffer { [Uint8Contents]: <00 00 00 01 02 03 04>, byteLength: 7 } + * console.log( src === got ); + * // log false + * + * @returns { Long|Buffer } - Returns a Long or a Buffer with type of first argument. Returned container filled by content of provided arguments. + * @function longJoin + * @throws { Error } If arguments.length is less than one. + * @throws { Error } If the {-arguments[ 0 ]-} is not a Long or not a Buffer. + * @throws { Error } If {-arguments-} has undefined value. + * @namespace Tools + */ + +function longJoin() +{ + _.assert( arguments.length >= 1, 'Expects at least one argument' ); + + if( arguments.length === 1 ) + { + return _._longClone( arguments[ 0 ] ); + } + + /* eval length */ + + let length = 0; + + for( let a = 0 ; a < arguments.length ; a++ ) + { + let argument = arguments[ a ]; + + _.assert( argument !== undefined, 'argument is not defined' ); + // if( argument === undefined ) + // throw _.err( 'argument is not defined' ); + + if( _.longLike( argument ) || _.bufferNodeIs( argument ) ) + length += argument.length; + else if( _.bufferRawIs( argument ) || _.bufferViewIs( argument ) ) + length += argument.byteLength; + else + length += 1; + } + + /* make result */ + + let result, bufferDst; + let offset = 0; + + if( _.bufferRawIs( arguments[ 0 ] ) ) + { + result = new BufferRaw( length ); + bufferDst = new U8x( result ); + } + else if( _.bufferViewIs( arguments[ 0 ] ) ) + { + result = new BufferView( new BufferRaw( length ) ); + bufferDst = new U8x( result.buffer ); + } + else + { + if( _.arrayIs( arguments[ 0 ] ) || _.bufferTypedIs( arguments[ 0 ] ) || _.argumentsArray.is( arguments[ 0 ] ) ) + result = _.long.makeUndefined( arguments[ 0 ], length ); + else if( _.bufferNodeIs( arguments[ 0 ] ) ) + result = BufferNode.alloc( length ); + else + _.assert( 0, 'Unexpected data type' ); + + bufferDst = result; + } + + /* copy */ + + for( let a = 0; a < arguments.length ; a++ ) + { + let srcTyped; + let argument = arguments[ a ]; + if( _.bufferRawIs( argument ) ) + srcTyped = new U8x( argument ); + else if( _.bufferViewIs( argument ) ) + srcTyped = new U8x( argument.buffer ); + else if( _.bufferTypedIs( argument ) ) + srcTyped = argument; + else if( _.longLike( argument ) || _.bufferNodeIs( argument ) ) + srcTyped = argument; + else + srcTyped = [ argument ]; + + for( let i = 0; i < srcTyped.length; i++ ) + bufferDst[ i + offset ] = srcTyped[ i ]; + + offset += srcTyped.length; + } + + // for( let a = 0, c = 0 ; a < arguments.length ; a++ ) + // { + // let argument = arguments[ a ]; + // if( _.bufferRawIs( argument ) ) + // { + // bufferDst.set( new U8x( argument ), offset ); + // offset += argument.byteLength; + // } + // else if( _.bufferTypedIs( arguments[ 0 ] ) ) + // { + // result.set( argument, offset ); + // offset += argument.length; + // } + // else if( _.longLike( argument ) ) + // for( let i = 0 ; i < argument.length ; i++ ) + // { + // result[ c ] = argument[ i ]; + // c += 1; + // } + // else + // { + // result[ c ] = argument; + // c += 1; + // } + // } + + return result; +} + +// + +function longEmpty( dstLong ) +{ + if( _.arrayIs( dstLong ) ) + { + // dstLong.slice( 0, dstLong.length ); // Dmytro : slice() method make copy of array, splice() method removes elements + dstLong.splice( 0, dstLong.length ); + return dstLong; + } + _.assert( 0, () => `Cant change length of fixed-length container ${_.entity.strType( dstLong )}` ); +} + +// // +// +// /** +// * The routine longBut() returns a shallow copy of provided Long {-array-}. Routine removes existing +// * elements in bounds defined by {-range-} and inserts new elements from {-val-}. The original +// * source Long {-array-} will not be modified. +// * +// * @param { Long } array - The Long from which makes a shallow copy. +// * @param { Range|Number } range - The two-element array that defines the start index and the end index for removing elements. +// * If {-range-} is number, then it defines the start index, and the end index is start index incremented by one. +// * If {-range-} is undefined, routine returns copy of {-array-}. +// * If range[ 0 ] < 0, then start index sets to 0. +// * If range[ 1 ] > array.length, end index sets to array.length. +// * If range[ 1 ] <= range[ 0 ], then routine removes not elements, the insertion of elements begins at start index. +// * @param { Long } val - The Long with elements for insertion. Inserting begins at start index. +// * If quantity of removed elements is not equal to val.length, then returned Long will have length different to array.length. +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.longBut( src ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5 ] +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = _.unroll.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longBut( src, 2, [ 'str' ] ); +// * console.log( got ); +// * // log [ 1, 2, 'str', 4, 5 ] +// * console.log( _.unrollIs( got ) ); +// * // log true +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = new F32x( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longBut( src, [ 1, 4 ], [ 5, 6, 7 ] ); +// * console.log( got ); +// * // log Float32Array[ 1, 5, 6, 7, 5 ] +// * console.log( _.bufferTypedIs( got ) ); +// * // log true +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.longBut( src, [ -5, 10 ], [ 'str' ] ); +// * console.log( got ); +// * // log [ 'str' ] +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.longBut( src, [ 4, 1 ], [ 'str' ] ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 'str', 5 ] +// * console.log( got === src ); +// * // log false +// * +// * @returns { Long } - Returns a copy of source Long with removed or replaced existing elements and / or added new elements. The copy has same type as source Long. +// * @function longBut +// * @throws { Error } If arguments.length is less then one or more then three. +// * @throws { Error } If argument {-array-} is not a Long. +// * @throws { Error } If range.length is less or more then two. +// * @throws { Error } If range elements is not number / undefined. +// * @throws { Error } If argument {-val-} is not Long / undefined. +// * @namespace Tools +// */ +// +// /* +// qqq : routine longBut requires good test coverage and documentation | Dmytro : extended routine coverage by using given clarifications, documented +// */ + +// function longBut( array, range, val ) +// { +// +// _.assert( 1 <= arguments.length && arguments.length <= 3 ); +// +// if( range === undefined ) +// return _.longJoin( array ); +// // return _.long.make( array ); +// +// if( _.arrayIs( array ) ) +// return _.arrayBut( array, range, val ); +// +// if( _.number.is( range ) ) +// range = [ range, range + 1 ]; +// +// _.assert( _.longLike( array ) ); +// _.assert( val === undefined || _.longLike( val ) ); +// _.assert( _.intervalIs( range ) ); +// // _.assert( _.longLike( range ), 'not tested' ); +// // _.assert( !_.longLike( range ), 'not tested' ); +// +// // if( _.number.is( range ) ) +// // range = [ range, range + 1 ]; +// +// _.ointerval.clamp/*rangeClamp*/( range, [ 0, array.length ] ); +// if( range[ 1 ] < range[ 0 ] ) +// range[ 1 ] = range[ 0 ]; +// +// let d = range[ 1 ] - range[ 0 ]; +// let len = ( val ? val.length : 0 ); +// let d2 = d - len; +// let l2 = array.length - d2; +// +// let result = _.long.makeUndefined( array, l2 ); +// +// // _.assert( 0, 'not tested' ) +// +// for( let i = 0 ; i < range[ 0 ] ; i++ ) +// result[ i ] = array[ i ]; +// +// for( let i = range[ 1 ] ; i < array.length ; i++ ) +// result[ i-d2 ] = array[ i ]; +// +// if( val ) +// { +// for( let i = 0 ; i < val.length ; i++ ) +// result[ range[ 0 ]+i ] = val[ i ]; +// } +// +// return result; +// } + +// // +// +// /** +// * The routine longButInplace() returns a Long {-array-} with removed existing elements in bounds +// * defined by {-range-} and inserted new elements from {-val-}. +// * If provided Long is resizable, routine modifies this Long in place, otherwise, return copy. +// * +// * @param { Long } array - The Long to remove, replace or add elements. +// * @param { Range|Number } range - The two-element array that defines the start index and the end index for removing elements. +// * If {-range-} is number, then it defines the start index, and the end index defines as start index incremented by one. +// * If {-range-} is undefined, routine returns {-src-}. +// * If range[ 0 ] < 0, then start index sets to 0. +// * If range[ 1 ] > array.length, end index sets to array.length. +// * If range[ 1 ] <= range[ 0 ], then routine removes no elements, the insertion of elements begins at start index. +// * @param { Long } ins - The Long with elements for insertion. Inserting begins at start index. +// * If quantity of removed elements is not equal to val.length, then returned array will have length different to original array.length. +// * +// * @example +// * var src = new U8x( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longButInplace( src ); +// * console.log( got ); +// * // log Uint8Array[ 1, 2, 3, 4, 5 ] +// * console.log( _.bufferTypedIs( got ) ); +// * // log true +// * console.log( got === src ); +// * // log true +// * +// * @example +// * var src = new I32x( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longButInplace( src, 2, [ 6, 7 ] ); +// * console.log( got ); +// * // log Int8Array[ 1, 2, 6, 7, 4, 5 ] +// * console.log( _.bufferTypedIs( got ) ); +// * // log true +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = _.unroll.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longButInplace( src, [ 1, 4 ], [ 'str' ] ); +// * console.log( got ); +// * // log [ 1, 'str', 5 ] +// * console.log( _.unrollIs( got ) ); +// * // log true +// * console.log( got === src ); +// * // log true +// * +// * @example +// * var src = _.argumentsArray.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longButInplace( src, [ -5, 10 ], [ 'str' ] ); +// * console.log( got ); +// * // log [ 'str' ] +// * console.log( _.argumentsArray.is( got ) ); +// * // log false +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.longButInplace( src, [ 4, 1 ], [ 'str' ] ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 'str', 5 ] +// * console.log( got === src ); +// * // log true +// * +// * @returns { Long } Returns Long with removed or replaced existing elements and / or added new elements. +// * If long is resizable, routine returns modified source long, otherwise, returns a copy. +// * @function longButInplace +// * @throws { Error } If arguments.length is less then one or more then three. +// * @throws { Error } If argument {-array-} is not a long. +// * @throws { Error } If range.length is less or more then two. +// * @throws { Error } If range elements is not number / undefined. +// * @throws { Error } If argument {-val-} is not long / undefined. +// * @namespace Tools +// */ +// +// /* +// aaa : routine longButInplace requires good test coverage and documentation | Dmytro : implemented and covered routine longButInplace, documented +// */ +// +// function longButInplace( array, range, val ) +// { +// +// _.assert( 1 <= arguments.length && arguments.length <= 3 ); +// +// if( _.arrayLikeResizable( array ) ) +// return _.arrayButInplace( array, range, val ); +// +// if( range === undefined ) +// return array; +// if( _.number.is( range ) ) +// range = [ range, range + 1 ]; +// +// _.assert( _.longLike( array ) ); +// _.assert( _.intervalIs( range ) ); +// +// _.ointerval.clamp/*rangeClamp*/( range, [ 0, array.length ] ); +// if( range[ 1 ] < range[ 0 ] ) +// range[ 1 ] = range[ 0 ]; +// +// if( range[ 0 ] === range[ 1 ] && val === undefined ) +// return array; +// else +// return _.longBut( array, range, val ); +// +// // let result; +// // +// // _.assert( _.longLike( src ) ); +// // _.assert( ins === undefined || _.longLike( ins ) ); +// // _.assert( _.longLike( range ), 'not tested' ); +// // _.assert( !_.longLike( range ), 'not tested' ); +// // +// // _.assert( 0, 'not implemented' ) +// +// // +// // if( _.number.is( range ) ) +// // range = [ range, range + 1 ]; +// // +// // _.ointerval.clamp/*rangeClamp*/( range, [ 0, src.length ] ); +// // if( range[ 1 ] < range[ 0 ] ) +// // range[ 1 ] = range[ 0 ]; +// // +// // let d = range[ 1 ] - range[ 0 ]; +// // let range[ 1 ] = src.length - d + ( ins ? ins.length : 0 ); +// // +// // result = _.long.makeUndefined( src, range[ 1 ] ); +// // +// // _.assert( 0, 'not tested' ) +// // +// // for( let i = 0 ; i < range[ 0 ] ; i++ ) +// // result[ i ] = src[ i ]; +// // +// // for( let i = range[ 1 ] ; i < range[ 1 ] ; i++ ) +// // result[ i-d ] = src[ i ]; +// // +// // return result; +// } +// +// // +// +// // function _relength_head( dst, src, range, ins ) +// // { +// // _.assert( 1 <= arguments.length && arguments.length <= 4 ); +// // +// // /* aaa : suspicious */ /* Dmytro : removed */ +// // +// // if( dst === null ) +// // { +// // dst = true; +// // } +// // else if( dst === src ) +// // { +// // dst = false; +// // } +// // else if( arguments.length === 4 ) +// // { +// // _.assert( _.longLike( dst ), '{-dst-} should be Long' ); +// // } +// // else +// // { +// // /* aaa2 : wrong. src could pass check intervalIs if length is 2 */ +// // /* Dmytro : this check means: if length > 1 and second argument is not a range, then it is source container, and third argument is range */ +// // // if( arguments.length > 1 && !_.intervalIs( src ) && !_.number.is( src ) ) +// // // { +// // // _.assert( _.longLike( dst ) ); +// // // } +// // // else +// // // { +// // // ins = range; +// // // range = src; +// // // src = dst; +// // // dst = false; +// // // } +// // +// // ins = range; +// // range = src; +// // src = dst; +// // dst = false; +// // } +// // +// // _.assert( _.longLike( src ) ); +// // +// // return [ dst, src, range, ins ]; +// // } + +// + +/* aaa2 : rename arguments. ask */ /* Dmytro : renamed and standardized for each routine */ + +function longBut_( /* dst, src, cinterval, ins */ ) +{ + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + + if( arguments.length < 4 && dst !== null && dst !== src ) + { + dst = arguments[ 0 ]; + src = arguments[ 0 ]; + cinterval = arguments[ 1 ]; + ins = arguments[ 2 ]; + } + + if( cinterval === undefined ) + { + cinterval = [ 0, -1 ]; + ins = undefined; + } + else if( _.number.is( cinterval ) ) + { + cinterval = [ cinterval, cinterval ]; + } + + _.assert( _.longIs( dst ) || dst === null, 'Expects {-dst-} of any long type or null' ); + _.assert( _.longIs( src ), 'Expects {-src-} of any long type' ); + _.assert( _.intervalIs( cinterval ), 'Expects cinterval {-cinterval-}' ); + _.assert( _.longLike( ins ) || ins === undefined || ins === null, 'Expects long {-ins-} for insertion' ); + + let first = cinterval[ 0 ] = cinterval[ 0 ] !== undefined ? cinterval[ 0 ] : 0; + let last = cinterval[ 1 ] = cinterval[ 1 ] !== undefined ? cinterval[ 1 ] : src.length - 1; + + if( first < 0 ) + first = 0; + if( first > src.length ) + first = src.length; + if( last > src.length - 1 ) + last = src.length - 1; + + if( last + 1 < first ) + last = first - 1; + + let delta = last - first + 1; + let insLength = ins ? ins.length : 0; + let delta2 = delta - insLength; + let resultLength = src.length - delta2; + + let result = dst; + if( dst === null ) + { + result = _.long.makeUndefined( src, resultLength ); + } + else if( dst === src ) + { + if( ( dst.length === resultLength ) && delta === 0 ) + { + return dst; + } + if( _.arrayLikeResizable( dst ) ) + { + ins ? dst.splice( first, delta, ... ins ) : dst.splice( first, delta ); + return dst; + } + else if( dst.length !== resultLength || _.argumentsArray.is( dst ) ) + { + result = _.long.makeUndefined( dst, resultLength ); + } + } + else if( dst.length !== resultLength ) + { + dst = _.long.makeUndefined( dst, resultLength ); + } + + /* */ + + for( let i = 0 ; i < first ; i++ ) + result[ i ] = src[ i ]; + + for( let i = last + 1 ; i < src.length ; i++ ) + result[ i - delta2 ] = src[ i ]; + + if( ins ) + { + for( let i = 0 ; i < ins.length ; i++ ) + result[ first + i ] = ins[ i ]; + } + + return result; +} + +// // +// +// /** +// * The routine longOnly() returns a copy of a portion of provided Long {-array-} into a new Long +// * selected by {-range-}. The original {-array-} will not be modified. +// * +// * @param { Long } array - The Long from which makes a shallow copy. +// * @param { Range|Number } range - The two-element array that defines the start index and the end index for copying elements. +// * If {-range-} is number, then it defines the start index, and the end index sets to array.length. +// * If {-range-} is undefined, routine returns copy of {-array-}. +// * If range[ 0 ] < 0, then start index sets to 0. +// * If range[ 1 ] > array.length, end index sets to array.length. +// * If range[ 1 ] <= range[ 0 ], then routine returns empty Long. +// * @param { * } val - The object of any type for insertion. +// * +// * @example +// * var src = new F32x( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.+( src ); +// * console.log( got ); +// * // log Float32Array[ 1, 2, 3, 4, 5 ] +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = _.unroll.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longOnly( src, 2, [ 'str' ] ); +// * console.log( got ); +// * // log [ 3, 4, 5 ] +// * console.log( _.unrollIs( got ) ); +// * // log true +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.longOnly( src, [ 1, 4 ], [ 'str' ] ); +// * console.log( got ); +// * // log [ 2, 3, 4 ] +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = _.argumentsArray.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longOnly( src, [ -5, 10 ], [ 'str' ] ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5 ] +// * console.log( _.argumentsArray.is( got ) ); +// * // log false +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.longOnly( src, [ 4, 1 ], [ 'str' ] ); +// * console.log( got ); +// * // log [] +// * console.log( got === src ); +// * // log false +// * +// * @returns { Long } Returns a copy of source Long containing the extracted elements. The copy has same type as source Long. +// * @function longOnly +// * @throws { Error } If arguments.length is less then one or more then three. +// * @throws { Error } If argument {-array-} is not a Long. +// * @throws { Error } If range.length is less or more then two. +// * @throws { Error } If range elements is not number / undefined. +// * @namespace Tools +// */ +// +// /* +// qqq : extend documentation and test coverage of longOnly | Dmytro : documented, covered. +// */ +// +// function longOnly( array, range, val ) +// { +// let result; +// +// _.assert( 1 <= arguments.length && arguments.length <= 3 ); +// +// if( range === undefined ) +// // return _.long.make( array, array.length ? array.length : 0 ); +// return _.longJoin( array ); +// +// if( _.number.is( range ) ) +// range = [ range, array.length ]; +// +// // let f = range ? range[ 0 ] : undefined; +// // let l = range ? range[ 1 ] : undefined; +// // +// // f = f !== undefined ? f : 0; +// // l = l !== undefined ? l : array.length; +// +// _.assert( _.longLike( array ) ); +// _.assert( _.intervalIs( range ) ) +// +// // if( f < 0 ) +// // { +// // l -= f; +// // f -= f; +// // } +// +// _.ointerval.clamp/*rangeClamp*/( range, [ 0, array.length ] ); +// if( range[ 1 ] < range[ 0 ] ) +// range[ 1 ] = range[ 0 ]; +// +// // if( l < f ) +// // l = f; +// +// // if( f < 0 ) +// // f = 0; +// // if( l > array.length ) +// // l = array.length; +// +// if( range[ 0 ] === 0 && range[ 1 ] === array.length ) +// // return _.long.make( array, array.length ); +// return _.longJoin( array ); +// +// result = _.long.makeUndefined( array, range[ 1 ]-range[ 0 ] ); +// +// let f2 = Math.max( range[ 0 ], 0 ); +// let l2 = Math.min( array.length, range[ 1 ] ); +// for( let r = f2 ; r < l2 ; r++ ) +// result[ r-f2 ] = array[ r ]; +// +// if( val !== undefined ) +// { +// for( let r = 0 ; r < -range[ 0 ] ; r++ ) +// { +// result[ r ] = val; +// } +// for( let r = l2 - range[ 0 ]; r < result.length ; r++ ) +// { +// result[ r ] = val; +// } +// } +// +// return result; +// } + +// // +// +// /** +// * The routine longOnlyInplace() returns a portion of provided Long {-array-} selected by {-range-}. +// * If provided Long is resizable, routine modifies this Long in place, otherwise, return copy. +// * +// * @param { Long } array - The Long from which selects elements. +// * @param { Range|Number } range - The two-element array that defines the start index and the end index for copying elements. +// * If {-range-} is number, then it defines the start index, and the end index sets to array.length. +// * If {-range-} is undefined, routine returns {-array-}. +// * If range[ 0 ] < 0, then start index sets to 0. +// * If range[ 1 ] > array.length, end index sets to array.length. +// * If range[ 1 ] <= range[ 0 ], then routine returns empty Long. +// * @param { * } val - The object of any type for insertion. +// * +// * @example +// * var src = new F32x( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longOnlyInplace( src ); +// * console.log( got ); +// * // log Float32Array[ 1, 2, 3, 4, 5 ] +// * console.log( got === src ); +// * // log true +// * +// * @example +// * var src = _.unroll.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longOnlyInplace( src, 2, [ 'str' ] ); +// * console.log( got ); +// * // log [ 3, 4, 5 ] +// * console.log( _.unrollIs( got ) ); +// * // log true +// * console.log( got === src ); +// * // log true +// * +// * @example +// * var src = new U8x( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longOnlyInplace( src, [ 1, 4 ], [ 1 ] ); +// * console.log( got ); +// * // log Uint8Array[ 2, 3, 4 ] +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = _.argumentsArray.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longOnlyInplace( src, [ -5, 10 ], [ 'str' ] ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5 ] +// * console.log( _.argumentsArray.is( got ) ); +// * // log false +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.longOnlyInplace( src, [ 4, 1 ], [ 'str' ] ); +// * console.log( got ); +// * // log [] +// * console.log( got === src ); +// * // log false +// * +// * @returns { Long } Returns a Long containing the selected elements. If Long is resizable, +// * routine returns modified source Long, otherwise, returns a copy. +// * @function longOnlyInplace +// * @throws { Error } If arguments.length is less then one or more then three. +// * @throws { Error } If argument {-array-} is not a Long. +// * @throws { Error } If range.length is less or more then two. +// * @throws { Error } If range elements is not number / undefined. +// * @namespace Tools +// */ +// +// /* +// qqq : extend documentation and test coverage of longOnlyInplace | Dmytro : documented, covered +// qqq : implement arrayShrink | Dmytro : implemented +// qqq : implement arrayShrinkInplace | Dmytro : implemented +// */ +// +// function longOnlyInplace( array, range, val ) +// { +// +// _.assert( 1 <= arguments.length && arguments.length <= 3 ); +// +// if( _.arrayLikeResizable( array ) ) +// return _.arrayShrinkInplace( array, range, val ); +// +// if( range === undefined ) +// return array; +// if( _.number.is( range ) ) +// range = [ range, array.length ]; +// +// _.assert( _.longLike( array ) ); +// _.assert( _.intervalIs( range ) ); +// +// _.ointerval.clamp/*rangeClamp*/( range, [ 0, array.length ] ); +// if( range[ 1 ] < range[ 0 ] ) +// range[ 1 ] = range[ 0 ]; +// +// if( range[ 0 ] === 0 && range[ 1 ] === array.length ) +// return array; +// else +// return _.longOnly( array, range, val ); +// // let result; +// // +// // if( range === undefined ) +// // return array; +// // +// // if( _.number.is( range ) ) +// // range = [ range, array.length ]; +// // +// // // let f = range ? range[ 0 ] : undefined; +// // // let l = range ? range[ 1 ] : undefined; +// // // +// // // f = f !== undefined ? f : 0; +// // // l = l !== undefined ? l : array.length; +// // +// // _.assert( _.longLike( array ) ); +// // _.assert( _.intervalIs( range ) ) +// // // _.assert( _.number.is( f ) ); +// // // _.assert( _.number.is( l ) ); +// // _.assert( 1 <= arguments.length && arguments.length <= 3 ); +// // // _.assert( 1 <= arguments.length && arguments.length <= 4 ); +// // +// // _.ointerval.clamp/*rangeClamp*/( range, [ 0, array.length ] ); +// // if( range[ 1 ] < range[ 0 ] ) +// // range[ 1 ] = range[ 0 ]; +// // +// // // if( l < f ) +// // // l = f; +// // // +// // // if( f < 0 ) +// // // f = 0; +// // // if( l > array.length ) +// // // l = array.length; +// // +// // if( range[ 0 ] === 0 && range[ 1 ] === array.length ) +// // // if( range[ 0 ] === 0 && l === array.length ) // Dmytro : l is not defined +// // return array; +// // +// // // if( _.bufferTypedIs( array ) ) +// // // result = new array.constructor( l-f ); +// // // else +// // // result = new Array( l-f ); +// // +// // result = _.long.makeUndefined( array, range[ 1 ]-range[ 0 ] ); +// // +// // /* */ +// // +// // let f2 = Math.max( range[ 0 ], 0 ); +// // let l2 = Math.min( array.length, range[ 1 ] ); +// // for( let r = f2 ; r < l2 ; r++ ) +// // result[ r-range[ 0 ] ] = array[ r ]; +// // +// // /* */ +// // +// // if( val !== undefined ) +// // { +// // for( let r = 0 ; r < -range[ 0 ] ; r++ ) +// // { +// // result[ r ] = val; +// // } +// // for( let r = l2 - range[ 0 ]; r < result.length ; r++ ) +// // { +// // result[ r ] = val; +// // } +// // } +// // +// // /* */ +// // +// // return result; +// } + +// + +function longOnly_( dst, src, cinterval ) +{ + _.assert( 1 <= arguments.length && arguments.length <= 3, 'Expects not {-ins-} element' ); + + if( arguments.length < 3 && dst !== null && dst !== src ) + { + dst = arguments[ 0 ]; + src = arguments[ 0 ]; + cinterval = arguments[ 1 ]; + } + + if( cinterval === undefined ) + cinterval = [ 0, src.length - 1 ]; + if( _.number.is( cinterval ) ) + cinterval = [ 0, cinterval ]; + + _.assert( _.longIs( dst ) || dst === null, 'Expects {-dst-} of any long type or null' ); + _.assert( _.longIs( src ), 'Expects {-src-} of any long type' ); + _.assert( _.intervalIs( cinterval ), 'Expects cinterval {-cinterval-}' ); + + let first = cinterval[ 0 ] = cinterval[ 0 ] !== undefined ? cinterval[ 0 ] : 0; + let last = cinterval[ 1 ] = cinterval[ 1 ] !== undefined ? cinterval[ 1 ] : src.length - 1; + + if( first < 0 ) + first = 0; + if( last > src.length - 1 ) + last = src.length - 1; + + if( last + 1 < first ) + last = first - 1; + + let first2 = Math.max( first, 0 ); + let last2 = Math.min( src.length - 1, last ); + + let resultLength = last - first + 1; + + let result = dst; + if( dst === null ) + { + result = _.long.makeUndefined( src, resultLength ); + } + else if( dst === src ) + { + if( dst.length === resultLength ) + { + return dst; + } + if( _.arrayLikeResizable( dst ) ) + { + _.assert( Object.isExtensible( dst ), 'Array is not extensible, cannot change array' ); + if( resultLength === 0 ) + return _.longEmpty( dst ); + + dst.splice( last2 + 1, dst.length - last + 1 ); + dst.splice( 0, first2 ); + return dst; + } + else if( dst.length !== resultLength || _.argumentsArray.is( dst ) ) + { + result = _.long.makeUndefined( dst, resultLength ); + } + } + else if( dst.length !== resultLength ) + { + if( !_.arrayLikeResizable( result ) ) + result = _.bufferMakeUndefined( dst, resultLength ); + else + result.splice( resultLength ); + } + + for( let r = first2 ; r < last2 + 1 ; r++ ) + result[ r - first2 ] = src[ r ]; + + return result; +} + +// // +// +// /** +// * Routine longGrow() changes length of provided Long {-array-} by copying it elements to newly created Long of the same +// * type using range {-range-} positions of the original Long and value to fill free space after copy {-val-}. +// * Routine can only grows size of Long. The original {-array-} will not be modified. +// * +// * @param { Long } array - The Long from which makes a shallow copy. +// * @param { Range } The two-element array that defines the start index and the end index for copying elements. +// * If {-range-} is number, then it defines the end index, and the start index is 0. +// * If range[ 0 ] < 0, then start index sets to 0, end index incrementes by absolute value of range[ 0 ]. +// * If range[ 0 ] > 0, then start index sets to 0. +// * If range[ 1 ] > array.length, end index sets to array.length. +// * If range[ 1 ] <= range[ 0 ], then routine returns a copy of original Long. +// * @param { * } val - The object of any type. Used to fill the space left after copying elements of the original Long. +// * +// * @example +// * var src = new F32x( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longGrow( src ); +// * console.log( got ); +// * // log Float32Array[ 1, 2, 3, 4, 5 ] +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = _.unroll.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longGrow( src, 7, 'str' ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5, 'str', 'str' ] +// * console.log( _.unrollIs( got ) ); +// * // log true +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = new U8x( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longGrow( src, [ 1, 6 ], 7 ); +// * console.log( got ); +// * // log Uint8Array[ 1, 2, 3, 4, 5, 7 ] +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = _.argumentsArray.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longGrow( src, [ -5, 6 ], 7 ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5, 7, 7, 7, 7, 7, 7 ] +// * console.log( _.argumentsArray.is( got ) ); +// * // log false +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.longGrow( src, [ 4, 1 ], 'str' ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5 ] +// * console.log( got === src ); +// * // log false +// * +// * @returns { Long } Returns a copy of provided Long with changed length. +// * @function longGrow +// * @throws { Error } If arguments.length is less then one or more then three. +// * @throws { Error } If argument {-array-} is not a Long. +// * @throws { Error } If range.length is less or more then two. +// * @throws { Error } If range elements is not number / undefined. +// * @namespace Tools +// */ +// +// /* +// aaa : extend documentation and test coverage of longGrowInplace | Dmytro : extended documentation, covered routine longGrow, longGrowInplace +// aaa : implement arrayGrow | Dmytro : implemented +// aaa : implement arrayGrowInplace | Dmytro : implemented +// */ +// +// function longGrow( array, range, val ) +// { +// _.assert( 1 <= arguments.length && arguments.length <= 3 ); +// +// if( range === undefined ) +// return _.longJoin( array ); +// +// if( _.number.is( range ) ) +// range = [ 0, range ]; +// +// let f = range[ 0 ] !== undefined ? range[ 0 ] : 0; +// let l = range[ 1 ] !== undefined ? range[ 1 ] : array.length; +// +// _.assert( _.longLike( array ) ); +// _.assert( _.intervalIs( range ) ) +// +// if( l < f ) +// l = f; +// +// if( f < 0 ) +// { +// l -= f; +// f -= f; +// } +// +// if( f > 0 ) +// f = 0; +// if( l < array.length ) +// l = array.length; +// +// if( l === array.length && -range[ 0 ] <= 0 ) +// return _.longJoin( array ); +// +// /* */ +// +// let f2 = Math.max( -range[ 0 ], 0 ); +// let l2 = Math.min( array.length, l ); +// +// let result = _.long.makeUndefined( array, range[ 1 ] > array.length ? l : array.length + f2 ); +// for( let r = f2 ; r < l2 + f2 ; r++ ) +// result[ r ] = array[ r - f2 ]; +// +// /* */ +// +// if( val !== undefined ) +// { +// for( let r = 0 ; r < f2 ; r++ ) +// result[ r ] = val; +// for( let r = l2 + f2; r < result.length ; r++ ) +// result[ r ] = val; +// } +// +// /* */ +// +// return result; +// } +// +// // +// +// /** +// * Routine longGrowInplace() changes length of provided Long {-array-} using range {-range-} positions of the original +// * Long and value to fill free space after copy {-val-}. If provided Long is resizable, routine modifies this +// * Long in place, otherwise, return copy. Routine can only grows size of Long. +// * +// * @param { Long } array - The Long to grow length. +// * @param { Range|Number } range - The two-element array that defines the start index and the end index for copying elements. +// * If {-range-} is number, then it defines the end index, and the start index is 0. +// * If range[ 0 ] < 0, then start index sets to 0, end index incrementes by absolute value of range[ 0 ]. +// * If range[ 0 ] > 0, then start index sets to 0. +// * If range[ 1 ] > array.length, end index sets to array.length. +// * If range[ 1 ] <= range[ 0 ], then routine returns origin array. +// * @param { * } val - The object of any type. Used to fill the space left of the original Long. +// * +// * @example +// * var src = new F32x( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longGrowInplace( src ); +// * console.log( got ); +// * // log Float32Array[ 1, 2, 3, 4, 5 ] +// * console.log( got === src ); +// * // log true +// * +// * @example +// * var src = _.unroll.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longGrowInplace( src, 7, 'str' ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5, 'str', 'str' ] +// * console.log( _.unrollIs( got ) ); +// * // log true +// * console.log( got === src ); +// * // log true +// * +// * @example +// * var src = new U8x( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longGrowInplace( src, [ 1, 6 ], 7 ); +// * console.log( got ); +// * // log Uint8Array[ 1, 2, 3, 4, 5, 7 ] +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = _.argumentsArray.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longGrowInplace( src, [ -5, 6 ], 7 ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5, 7, 7, 7, 7, 7, 7 ] +// * console.log( _.argumentsArray.is( got ) ); +// * // log false +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.longGrowInplace( src, [ 4, 1 ], 'str' ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5 ] +// * console.log( got === src ); +// * // log true +// * +// * @returns { Long } Returns a Long with changed length. +// * If Long is resizable, routine returns modified source Long, otherwise, returns a copy. +// * @function longGrowInplace +// * @throws { Error } If arguments.length is less then one or more then three. +// * @throws { Error } If argument {-array-} is not a Long. +// * @throws { Error } If range.length is less or more then two. +// * @throws { Error } If range elements is not number / undefined. +// * @namespace Tools +// */ +// +// function longGrowInplace( array, range, val ) +// { +// +// _.assert( 1 <= arguments.length && arguments.length <= 3 ); +// +// if( _.arrayLikeResizable( array ) ) +// return _.arrayGrowInplace( array, range, val ); +// +// if( range === undefined ) +// return array; +// if( _.number.is( range ) ) +// range = [ 0, range ]; +// +// let f = range[ 0 ] !== undefined ? range[ 0 ] : 0; +// let l = range[ 1 ] !== undefined ? range[ 1 ] : array.length; +// +// _.assert( _.longLike( array ) ); +// _.assert( _.intervalIs( range ) ) +// +// if( l < f ) +// l = f; +// if( f < 0 ) +// { +// l -= f; +// f -= f; +// } +// if( f > 0 ) +// f = 0; +// if( l < array.length ) +// l = array.length; +// +// if( l === array.length && -range[ 0 ] <= 0 ) +// return array; +// else +// return _.longGrow( array, range, val ); +// } + +// + +function longGrow_( /* dst, src, cinterval, ins */ ) +{ + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + + if( arguments.length < 4 && dst !== null && dst !== src ) + { + dst = arguments[ 0 ]; + src = arguments[ 0 ]; + cinterval = arguments[ 1 ]; + ins = arguments[ 2 ]; + } + + if( cinterval === undefined ) + cinterval = [ 0, src.length - 1 ]; + if( _.number.is( cinterval ) ) + cinterval = [ 0, cinterval - 1 ]; + + _.assert( _.longIs( dst ) || dst === null, 'Expects {-dst-} of any long type or null' ); + _.assert( _.longIs( src ), 'Expects {-src-} of any long type' ); + _.assert( _.intervalIs( cinterval ), 'Expects cinterval {-cinterval-}' ); + + let first = cinterval[ 0 ] = cinterval[ 0 ] !== undefined ? cinterval[ 0 ] : 0; + let last = cinterval[ 1 ] = cinterval[ 1 ] !== undefined ? cinterval[ 1 ] : src.length - 1; + + if( first > 0 ) + first = 0; + if( last < src.length - 1 ) + last = src.length - 1; + + if( first < 0 ) + { + last -= first; + first -= first; + } + + if( last + 1 < first ) + last = first - 1; + + let first2 = Math.max( -cinterval[ 0 ], 0 ); + let last2 = Math.min( src.length - 1 + first2, last + first2 ); + + let resultLength = last - first + 1; + + let result = dst; + if( dst === null ) + { + result = _.long.makeUndefined( src, resultLength ); + } + else if( dst === src ) + { + if( dst.length === resultLength ) + { + return dst; + } + if( _.arrayLikeResizable( dst ) ) + { + _.assert( Object.isExtensible( dst ), 'Array is not extensible, cannot change array' ); + dst.splice( 0, 0, ... _.dup( ins, first2 ) ); + dst.splice( last2 + 1, 0, ... _.dup( ins, resultLength <= last2 ? 0 : resultLength - last2 - 1 ) ); + return dst; + } + else if( dst.length !== resultLength || _.argumentsArray.is( dst ) ) + { + result = _.long.makeUndefined( dst, resultLength ); + } + } + else if( dst.length !== resultLength ) + { + if( !_.arrayLikeResizable( result ) ) + result = _.bufferMakeUndefined( dst, resultLength ); + else + result.splice( resultLength ); + } + + for( let r = first2 ; r < last2 + 1 ; r++ ) + result[ r ] = src[ r - first2 ]; + + if( ins !== undefined ) + { + for( let r = 0 ; r < first2 ; r++ ) + result[ r ] = ins; + for( let r = last2 + 1 ; r < resultLength ; r++ ) + result[ r ] = ins; + } + + return result; +} + +// // +// +// /** +// * Routine longRelength() changes length of provided Long {-array-} by copying its elements to newly created Long of the same +// * type as source Long. Routine uses range {-range-} positions of the original Long and value {-val-} to fill free space after copy. +// * Routine can grows and reduces size of Long. The original {-array-} will not be modified. +// * +// * @param { Long } array - The Long from which makes a shallow copy. +// * @param { Range } The two-element array that defines the start index and the end index for copying elements. +// * If {-range-} is number, then it defines the start index, and the end index sets to array.length. +// * If range[ 0 ] < 0, then start index sets to 0. +// * If range[ 1 ] <= range[ 0 ], then routine returns empty Long. +// * @param { * } val - The object of any type. Used to fill the space left after copying elements of the original Long. +// * +// * @example +// * var src = new F32x( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longRelength( src ); +// * console.log( got ); +// * // log Float32Array[ 1, 2, 3, 4, 5 ] +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = _.unroll.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longRelength( src, 7, 'str' ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5, 'str', 'str' ] +// * console.log( _.unrollIs( got ) ); +// * // log true +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = new U8x( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longRelength( src, [ 1, 6 ], 7 ); +// * console.log( got ); +// * // log Uint8Array[ 2, 3, 4, 5, 7 ] +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = _.argumentsArray.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longRelength( src, [ -5, 6 ], 7 ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5, 7 ] +// * console.log( _.argumentsArray.is( got ) ); +// * // log false +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.longRelength( src, [ 4, 1 ], 'str' ); +// * console.log( got ); +// * // log [] +// * console.log( got === src ); +// * // log false +// * +// * @returns { Long } Returns a copy of provided Long with changed length. +// * @function longRelength +// * @throws { Error } If arguments.length is less then one or more then three. +// * @throws { Error } If argument {-array-} is not a Long. +// * @throws { Error } If range.length is less or more then two. +// * @throws { Error } If range elements is not number / undefined. +// * @namespace Tools +// */ +// +// function longRelength( array, range, val ) +// { +// +// let result; +// +// _.assert( 1 <= arguments.length && arguments.length <= 3 ); +// +// if( range === undefined ) +// return _.longJoin( array ); +// // return _.long.make( array ); +// +// if( _.number.is( range ) ) +// range = [ range, array.length ]; +// +// let f = range[ 0 ] !== undefined ? range[ 0 ] : 0; +// let l = range[ 1 ] !== undefined ? range[ 1 ] : src.length; +// +// _.assert( _.longLike( array ) ); +// _.assert( _.intervalIs( range ) ) +// +// if( l < f ) +// l = f; +// if( f > array.length ) +// f = array.length +// +// if( f < 0 ) +// f = 0; +// +// if( f === 0 && l === array.length ) +// return _.long.make( array ); +// +// result = _.long.makeUndefined( array, l-f ); +// +// /* */ +// +// let f2 = Math.max( f, 0 ); +// let l2 = Math.min( array.length, l ); +// for( let r = f2 ; r < l2 ; r++ ) +// result[ r-f2 ] = array[ r ]; +// +// /* */ +// +// if( val !== undefined ) +// { +// for( let r = l2 - range[ 0 ]; r < result.length ; r++ ) +// { +// result[ r ] = val; +// } +// } +// +// /* */ +// +// return result; +// } +// +// // +// +// /** +// * Routine longRelengthInplace() changes length of provided Long {-array-} using range {-range-} positions of the original +// * Long and value to fill free space after copy {-val-}. If provided Long is resizable, routine modifies this +// * Long in place, otherwise, return copy. Routine can grows and reduce size of Long. +// * +// * @param { Long } array - The Long to change length. +// * @param { Range|Number } range - The two-element array that defines the start index and the end index for copying elements. +// * If {-range-} is number, then it defines the start index, and the end index sets to src.length. +// * If range[ 0 ] < 0, then start index sets to 0. +// * If range[ 1 ] <= range[ 0 ], then routine returns empty array. +// * @param { * } val - The object of any type. Used to fill the space left of the original Long. +// * +// * @example +// * var src = new F32x( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longRelengthInplace( src ); +// * console.log( got ); +// * // log Float32Array[ 1, 2, 3, 4, 5 ] +// * console.log( got === src ); +// * // log true +// * +// * @example +// * var src = _.unroll.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longRelengthInplace( src, 7, 'str' ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5, 'str', 'str' ] +// * console.log( _.unrollIs( got ) ); +// * // log true +// * console.log( got === src ); +// * // log true +// * +// * @example +// * var src = new U8x( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longRelengthInplace( src, [ 1, 6 ], 7 ); +// * console.log( got ); +// * // log Uint8Array[ 2, 3, 4, 5, 7 ] +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = _.argumentsArray.make( [ 1, 2, 3, 4, 5 ] ); +// * var got = _.longRelengthInplace( src, [ -5, 6 ], 7 ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5, 7 ] +// * console.log( _.argumentsArray.is( got ) ); +// * // log false +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.longRelengthInplace( src, [ 4, 1 ], 'str' ); +// * console.log( got ); +// * // log [] +// * console.log( got === src ); +// * // log true +// * +// * @returns { Long } Returns a Long with changed length. +// * If Long is resizable, routine returns modified source Long, otherwise, returns a copy. +// * @function longRelengthInplace +// * @throws { Error } If arguments.length is less then one or more then three. +// * @throws { Error } If argument {-array-} is not a Long. +// * @throws { Error } If range.length is less or more then two. +// * @throws { Error } If range elements is not number / undefined. +// * @namespace Tools +// */ +// +// function longRelengthInplace( array, range, val ) +// { +// +// _.assert( 1 <= arguments.length && arguments.length <= 3 ); +// +// if( _.arrayLikeResizable( array ) ) +// return _.arrayRelengthInplace( array, range, val ); +// +// if( range === undefined ) +// return array; +// if( _.number.is( range ) ) +// range = [ range, array.length ]; +// +// let f = range[ 0 ] !== undefined ? range[ 0 ] : 0; +// let l = range[ 1 ] !== undefined ? range[ 1 ] : src.length; +// +// _.assert( _.longLike( array ) ); +// _.assert( _.intervalIs( range ) ) +// +// if( l < f ) +// l = f; +// if( f > array.length ) +// f = array.length; +// if( f < 0 ) +// f = 0; +// +// if( f === 0 && l === array.length ) +// return array; +// else +// return _.longRelength( array, range, val ); +// +// } + +// + +function longRelength_( /* dst, src, cinterval, ins */ ) +{ + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + + if( arguments.length < 4 && dst !== null && dst !== src ) + { + dst = arguments[ 0 ]; + src = arguments[ 0 ]; + cinterval = arguments[ 1 ]; + ins = arguments[ 2 ]; + } + + if( cinterval === undefined ) + cinterval = [ 0, src.length - 1 ]; + if( _.number.is( cinterval ) ) + cinterval = [ 0, cinterval - 1 ]; + + _.assert( _.longIs( dst ) || dst === null, 'Expects {-dst-} of any long type or null' ); + _.assert( _.longIs( src ), 'Expects {-src-} of any long type' ); + _.assert( _.intervalIs( cinterval ), 'Expects cinterval {-cinterval-}' ); + + let first = cinterval[ 0 ] = cinterval[ 0 ] !== undefined ? cinterval[ 0 ] : 0; + let last = cinterval[ 1 ] = cinterval[ 1 ] !== undefined ? cinterval[ 1 ] : src.length - 1; + + if( last < first ) + last = first - 1; + + if( cinterval[ 1 ] < 0 && cinterval[ 0 ] < 0 ) + cinterval[ 0 ] -= cinterval[ 1 ] + 1; + + if( first < 0 ) + { + last -= first; + first -= first; + } + + let first2 = Math.max( Math.abs( cinterval[ 0 ] ), 0 ); + let last2 = Math.min( src.length - 1, last ); + + let resultLength = last - first + 1; + + let result = dst; + if( dst === null ) + { + result = _.long.makeUndefined( src, resultLength ); + } + else if( dst === src ) + { + if( dst.length === resultLength && cinterval[ 0 ] === 0 ) + { + return dst; + } + if( _.arrayLikeResizable( dst ) ) + { + _.assert( Object.isExtensible( dst ), 'dst is not extensible, cannot change dst' ); + if( cinterval[ 0 ] < 0 ) + { + dst.splice( first, 0, ... _.dup( ins, first2 ) ); + dst.splice( last2 + 1, src.length - last2, ... _.dup( ins, last - last2 ) ); + } + else + { + dst.splice( 0, first ); + dst.splice( last2 + 1 - first2, src.length - last2, ... _.dup( ins, last - last2 ) ); + } + return dst; + } + else if( dst.length !== resultLength || _.argumentsArray.is( dst ) ) + { + result = _.long.makeUndefined( dst, resultLength ); + } + } + else if( dst.length !== resultLength ) + { + if( !_.arrayLikeResizable( result ) ) + result = _.bufferMakeUndefined( dst, resultLength ); + else + result.splice( resultLength ); + } + + /* */ + + if( resultLength === 0 ) + { + return result; + } + if( cinterval[ 0 ] < 0 ) + { + for( let r = first2 ; r < ( last2 + 1 + first2 ) && r < resultLength ; r++ ) + result[ r ] = src[ r - first2 ]; + if( ins !== undefined ) + { + for( let r = 0 ; r < first2 ; r++ ) + result[ r ] = ins; + for( let r = last2 + 1 + first2 ; r < resultLength ; r++ ) + result[ r ] = ins; + } + } + else + { + for( let r = first2 ; r < last2 + 1 ; r++ ) + result[ r - first2 ] = src[ r ]; + + if( ins !== undefined ) + { + for( let r = last2 + 1 ; r < last + 1 ; r++ ) + result[ r - first2 ] = ins; + } + } + + return result; +} + +// -- +// array checker +// -- + +// /** +// * The longCompare() routine returns the first difference between the values of the first array from the second. +// * +// * @param { longLike } src1 - The first array. +// * @param { longLike } src2 - The second array. +// * +// * @example +// * _.longCompare( [ 1, 5 ], [ 1, 2 ] ); +// * // returns 3 +// * +// * @returns { Number } - Returns the first difference between the values of the two arrays. +// * @function longCompare +// * @throws { Error } Will throw an Error if (arguments.length) is less or more than two. +// * @throws { Error } Will throw an Error if (src1 and src2) are not the array-like. +// * @throws { Error } Will throw an Error if (src2.length) is less or not equal to the (src1.length). +// * @namespace Tools +// */ +// +// function longCompare( src1, src2 ) +// { +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// _.assert( _.longLike( src1 ) && _.longLike( src2 ) ); +// _.assert( src2.length >= src1.length ); +// +// let result = 0; +// +// for( let s = 0 ; s < src1.length ; s++ ) +// { +// +// result = src1[ s ] - src2[ s ]; +// if( result !== 0 ) +// return result; +// +// } +// +// return result; +// } +// +// // +// +// /** +// * The long.identicalShallow() routine checks the equality of two arrays. +// * +// * @param { longLike } src1 - The first array. +// * @param { longLike } src2 - The second array. +// * +// * @example +// * _.long.identicalShallow( [ 1, 2, 3 ], [ 1, 2, 3 ] ); +// * // returns true +// * +// * @returns { Boolean } - Returns true if all values of the two arrays are equal. Otherwise, returns false. +// * @function long.identicalShallow +// * @throws { Error } Will throw an Error if (arguments.length) is less or more than two. +// * @namespace Tools +// */ +// +// /* xxx : vector? */ +// /* qqq : extend test */ +// function long.identicalShallow( src1, src2 ) +// { +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// // qqq : for junior : ! +// // _.assert( _.longLike( src1 ) ); +// // _.assert( _.longLike( src2 ) ); +// +// if( !_.longLike( src1 ) ) +// return false; +// if( !_.longLike( src2 ) ) +// return false; +// +// return _._long.identicalShallow( src1, src2 ); +// +// } +// +// // +// +// function _long.identicalShallow( src1, src2 ) +// { +// let result = true; +// +// if( src1.length !== src2.length ) +// return false; +// +// for( let s = 0 ; s < src1.length ; s++ ) +// { +// result = src1[ s ] === src2[ s ]; +// if( result === false ) +// return false; +// } +// +// return result; +// } + +// + +function longHas( /* array, element, evaluator1, evaluator2 */ ) +{ + let array = arguments[ 0 ]; + let element = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + _.assert( _.argumentsArray.like( array ) ); + + if( !evaluator1 && !evaluator2 ) + { + // return _ArrayIndexOf.call( array, element ) !== -1; + return _ArrayIncludes.call( array, element ); + } + else + { + if( _.longLeftIndex( array, element, evaluator1, evaluator2 ) >= 0 ) + return true; + return false; + } + +} + +// + +/** + * The routine longHasAny() checks if the source long {-src-} has at least one element of the long {-ins-}. + * It can take equalizer or evaluators for comparing elements. + * + * It iterates over source long {-src-} each element of the long {-ins-} by the routine + * [longLeftIndex()]{@link wTools.longLeftIndex} + * Checks, if {-src-} has at least one element of the {-ins-}. + * If true, it returns true. + * Otherwise, it returns false. + * + * @see {@link wTools.longLeftIndex} - See for more information. + * + * @param { Long } src - The source array. + * @param { Long|Primitive } ins - The elements to check in the source array. + * @param { Function } evaluator1 - A callback function. Can be an equalizer or evaluator. + * @param { Function } evaluator2 - A callback function. Uses only as second evaluator. + * + * @example + * _.longHasAny( [ 5, 'str', 42, false ], 7 ); + * // returns false + * + * @example + * _.longHasAny( [ 5, 'str', 42, false ], [ false, 7, 10 ] ); + * // returns true + * + * @example + * _.longHasAny( [ { a : 2 }, 'str', 42, false ], [ { a : 2 }, { a : 3 } ] ); + * // returns false + * + * @example + * var evaluator = ( e ) => e.a; + * _.longHasAny( [ { a : 2 }, 'str', 42, false ], [ { a : 2 }, { a : 3 } ], evaluator ); + * // returns true + * + * @example + * var evaluator1 = ( e ) => e.a; + * var evaluator2 = ( e ) => e.b; + * _.longHasAny( [ { a : 2 }, 'str', 42, false ], [ { b : 2 }, { b : 3 } ], evaluator1, evaluator2 ); + * // returns true + * + * @example + * var equalizer = ( eSrc, eIns ) => eSrc.a === eIns.b; + * _.longHasAny( [ { a : 2 }, 'str', 42, false ], [ { b : 2 }, { b : 3 } ], equalizer ); + * // returns true + * + * @returns { Boolean } - Returns true, if {-src-} has at least one element of {-ins-}, otherwise false is returned. + * @function longHasAny + * @throws { Error } If arguments.length is less then one or more then four. + * @throws { Error } If {-src-} is not a Long. + * @throws { Error } If {-ins-} is not a Long, not a primitive. + * @throws { Error } If {-evaluator1-} is not a routine. + * @throws { Error } If {-evaluator1-} is an evaluator and accepts less or more than one argument. + * @throws { Error } If {-evaluator1-} is an equalizer and accepts less or more than two argument. + * @throws { Error } If {-evaluator2-} is not a routine. + * @throws { Error } If {-evaluator2-} is an evaluator and accepts less or more than one argument. + * @namespace Tools + */ + +function longHasAny( /* src, ins, evaluator1, evaluator2 */ ) +{ + let src = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + _.assert( _.longLike( src ), `Expects long, but got ${ _.entity.strType( src ) }` ); + _.assert( _.longLike( ins ) || _.primitive.is( ins ) ); + + if( _.primitive.is( ins ) ) + ins = [ ins ]; + + let i = 0; + let result; + + do + { + result = _.longLeftIndex( src, ins[ i ], 0, evaluator1, evaluator2 ); + i++; + } + while( result < 0 && i < ins.length ) + + if( result !== -1 ) + return true; + return false; +} + +// + +/** + * The routine longHasAll() checks if the source long {-src-} has all elements of the long {-ins-}. + * It can take equalizer or evaluators for comparing elements. + * + * It iterates over source long {-src-} each element of the long {-ins-} by the routine + * [longLeftIndex()]{@link wTools.longLeftIndex} + * Checks, if {-src-} has all elements of the {-ins-}. + * If true, it returns true. + * Otherwise, it returns false. + * + * @see {@link wTools.longLeftIndex} - See for more information. + * + * @param { Long } src - The source array. + * @param { Long|Primitive } ins - The elements to check in the source array. + * @param { Function } evaluator1 - A callback function. Can be an equalizer or evaluator. + * @param { Function } evaluator2 - A callback function. Uses only as second evaluator. + * + * @example + * _.longHasAll( [ 5, 'str', 42, false ], 7 ); + * // returns false + * + * @example + * _.longHasAny( [ 5, 'str', 42, false ], [ false, 5, 'str' ] ); + * // returns true + * + * @example + * _.longHasAny( [ { a : 2 }, { a : 3 } 'var', 42, false ], [ { a : 2 }, { a : 3 } ] ); + * // returns false + * + * @example + * var evaluator = ( e ) => e.a; + * _.longHasAny( [ { a : 2 }, { a : 3 } 'str', 42, false ], [ { a : 2 }, { a : 3 } ], evaluator ); + * // returns true + * + * @example + * var evaluator1 = ( eSrc ) => eSrc.a; + * var evaluator2 = ( eIns ) => eIns.b; + * _.longHasAny( [ { a : 2 }, { a : 3 } 'str', 42, false ], [ { b : 2 }, { b : 3 } ], evaluator1, evaluator2 ); + * // returns true + * + * @example + * var equalizer = ( eSrc, eIns ) => eSrc.a === eIns.b; + * _.longHasAny( [ { a : 2 }, { a : 3 } 'str', 42, false ], [ { b : 2 }, { b : 3 } ], equalizer ); + * // returns true + * + * @returns { Boolean } - Returns true, if {-src-} has all elements of {-ins-}, otherwise false is returned. + * @function longHasAll + * @throws { Error } If arguments.length is less then one or more then four. + * @throws { Error } If {-src-} is not a Long. + * @throws { Error } If {-ins-} is not a Long, not a primitive. + * @throws { Error } If {-evaluator1-} is not a routine. + * @throws { Error } If {-evaluator1-} is an evaluator and accepts less or more than one argument. + * @throws { Error } If {-evaluator1-} is an equalizer and accepts less or more than two argument. + * @throws { Error } If {-evaluator2-} is not a routine. + * @throws { Error } If {-evaluator2-} is an evaluator and accepts less or more than one argument. + * @namespace Tools + */ + +function longHasAll( /* src, ins, evaluator1, evaluator2 */ ) +{ + let src = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + _.assert( _.longLike( src ), `Expects long, but got ${ _.entity.strType( src ) }` ); + _.assert( _.longLike( ins ) || _.primitive.is( ins ) ); + + if( _.primitive.is( ins ) ) + ins = [ ins ]; + + if( ins.length === 0 ) + return true; + + let i = 0; + let result = 0; + while( result >= 0 && i < ins.length ) + { + result = _.longLeftIndex( src, ins[ i ], 0, evaluator1, evaluator2 ); + i++; + } + + if( result !== -1 ) + return true; + return false; +} + +// + +/** + * The routine longHasNone() checks if the source long {-src-} has no one element of the long {-ins-}. + * It can take equalizer or evaluators for the comparing elements. + * + * It iterates over source long {-src-} each element of the long {-ins-} by the routine + * [longLeftIndex()]{@link wTools.longLeftIndex} + * Checks, if {-src-} has no one elements of the {-ins-}. + * If true, it returns true. + * Otherwise, it returns false. + * + * @see {@link wTools.longLeftIndex} - See for more information. + * + * @param { Long } src - The source array. + * @param { Long|Primitive } ins - The elements to check in the source array. + * @param { Function } evaluator1 - A callback function. Can be an equalizer or evaluator. + * @param { Function } evaluator2 - A callback function. Uses only as second evaluator. + * + * @example + * _.longHasNone( [ 5, 'str', 42, false ], 7 ); + * // returns true + * + * @example + * _.longHasNone( [ 5, 'str', 42, false ], [ false, 5, 'str' ] ); + * // returns false + * + * @example + * _.longHasNone( [ { a : 2 }, { a : 3 } 'var', 42, false ], [ { a : 2 }, { a : 3 } ] ); + * // returns true + * + * @example + * var evaluator = ( e ) => e.a; + * _.longHasNone( [ { a : 2 }, { a : 3 } 'str', 42, false ], [ { a : 2 }, { a : 4 } ], evaluator ); + * // returns false + * + * @example + * var evaluator1 = ( eSrc ) => eSrc.a; + * var evaluator2 = ( eIns ) => eIns.b; + * _.longHasNone( [ { a : 2 }, { a : 3 } 'str', 42, false ], [ { b : 2 }, { b : 4 } ], evaluator1, evaluator2 ); + * // returns false + * + * @example + * var equalizer = ( eSrc, eIns ) => eSrc.a === eIns.b; + * _.longHasNone( [ { a : 2 }, { a : 3 } 'str', 42, false ], [ { b : 2 }, { b : 4 } ], equalizer ); + * // returns false + * + * @returns { Boolean } - Returns true, if {-src-} has no one element of {-ins-}, otherwise false is returned. + * @function longHasAll + * @throws { Error } If arguments.length is less then one or more then four. + * @throws { Error } If {-src-} is not a Long. + * @throws { Error } If {-ins-} is not a Long, not a primitive. + * @throws { Error } If {-evaluator1-} is not a routine. + * @throws { Error } If {-evaluator1-} is an evaluator and accepts less or more than one argument. + * @throws { Error } If {-evaluator1-} is an equalizer and accepts less or more than two argument. + * @throws { Error } If {-evaluator2-} is not a routine. + * @throws { Error } If {-evaluator2-} is an evaluator and accepts less or more than one argument. + * @namespace Tools + */ + +function longHasNone( /* src, ins, evaluator1, evaluator2 */ ) +{ + let src = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let evaluator1 = arguments[ 2 ]; + let evaluator2 = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + _.assert( _.longLike( src ), `Expects long, but got ${ _.entity.strType( src ) }` ); + _.assert( _.longLike( ins ) || _.primitive.is( ins ) ); + + if( _.primitive.is( ins ) ) + ins = [ ins ]; + + let i = 0; + let result; + + do + { + result = _.longLeftIndex( src, ins[ i ], 0, evaluator1, evaluator2 ); + i++; + } + while( result < 0 && i < ins.length ) + + if( result !== -1 ) + return false; + return true; +} + +// + +/* aaa : cover please | Dmytro : covered */ + +function longHasDepth( arr, level = 1 ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.intIs( level ) ); + + if( !_.longLike( arr ) ) + return false; + + if( level <= 0 ) + return true; + + for( let a = 0 ; a < arr.length ; a += 1 ) + if( _.longLike( arr[ a ] ) ) + { + if( _.longHasDepth( arr[ a ], level - 1 ) ) + return true; + } + + return false; +} + +// + +function longAll( src ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.longLike( src ) ); + + for( let s = 0 ; s < src.length ; s += 1 ) + { + if( !src[ s ] ) + return false; + } + + return true; +} + +// + +function longAny( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.longLike( src ) ); + + for( let s = 0 ; s < src.length ; s += 1 ) + if( src[ s ] ) + return true; + + return false; +} + +// + +function longNone( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.longLike( src ) ); + + for( let s = 0 ; s < src.length ; s += 1 ) + if( src[ s ] ) + return false; + + return true; +} + +// -- +// long sequential search +// -- + +/** + * The routine longCountElement() returns the count of matched elements {-element-} in the {-srcArray-} array. + * Returns 0 if no {-element-} is matched. It can take equalizer or evaluators to check specific equalities. + * + * @param { Long } srcArray - The source array. + * @param { * } element - The value to count matches. + * @param { Function } onEvaluate1 - It's a callback. If the routine has two parameters, it is used as an equalizer, and if it has only one, then routine used as the evaluator. + * @param { Function } onEvaluate2 - The second part of evaluator. Accepts the value to search. + * + * @example + * // simple exapmle, no matches + * _.longCountElement( [ 1, 2, 'str', 10, 10, true ], 3 ); + * // returns 0 + * + * @example + * // simple exapmle + * _.longCountElement( [ 1, 2, 'str', 10, 10, true ], 10 ); + * // returns 2 + * + * @example + * // with equalizer + * _.longCountElement( [ 1, 2, 'str', 10, 10, true ], 10, ( a, b ) => _.typeOf( a ) === _.typeOf( b ) ); + * // returns 4 + * + * @example + * // with single evaluator + * _.longCountElement( [ [ 10 ], [ 10 ], [ 'str' ], [ 10 ], [ false ] ], [ 'str' ], ( e ) => e[ 0 ] ); + * // returns 1 + * + * @example + * // with two part of evaluator + * _.longCountElement( [ [ 10 ], [ 10 ], [ 'str' ], [ 10 ], [ false ] ], 10, ( e ) => e[ 0 ], ( e ) => e ); + * // returns 4 + * + * @returns { Number } - Returns the count of matched elements {-element-} in the {-srcArray-}. + * @function longCountElement + * @throws { Error } If passed arguments is less than two or more than four. + * @throws { Error } If the first argument is not a Long. + * @throws { Error } If the third or fourth argument is not a routine. + * @throws { Error } If the routine in third argument has less than one or more than two arguments. + * @throws { Error } If the routine in third argument has two arguments and fourth argument is passed into routine longCountElement. + * @throws { Error } If the routine in fourth argument has less than one or more than one arguments. + * @namespace Tools + */ + +/* +aaa : are all combinations of call of routine arrayCountElement covered? | Dmytro : yes, all combinations of call is implemented +*/ + +function longCountElement( /* srcArray, element, onEvaluate1, onEvaluate2 */ ) +{ + let srcArray = arguments[ 0 ]; + let element = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + let result = 0; + + _.assert( 2 <= arguments.length && arguments.length <= 4 ); + _.assert( _.longLike( srcArray ), 'Expects long' ); + + let left = _.longLeftIndex( srcArray, element, onEvaluate1, onEvaluate2 ); + // let index = srcArray.indexOf( element ); + + while( left >= 0 ) + { + result += 1; + left = _.longLeftIndex( srcArray, element, left+1, onEvaluate1, onEvaluate2 ); + // index = srcArray.indexOf( element, index+1 ); + } + + return result; +} + +// + +/** + * The routine longCountTotal() adds all the elements in {-srcArray-}, elements can be numbers or booleans ( it considers them 0 or 1 ). + * + * @param { Array } srcArray - The source array. + * + * @example + * _.longCountTotal( [ 1, 2, 10, 10 ] ); + * // returns 23 + * + * @example + * _.longCountTotal( [ true, false, false ] ); + * // returns 1 + * + * @returns { Number } - Returns the sum of the elements in {-srcArray-}. + * @function longCountTotal + * @throws { Error } If passed arguments is different than one. + * @throws { Error } If the first argument is not a Long. + * @throws { Error } If {-srcArray-} doesn´t contain number-like elements. + * @namespace Tools + */ + +function longCountTotal( srcArray ) +{ + let result = 0; + + _.assert( arguments.length === 1 ); + _.assert( _.longLike( srcArray ), 'Expects long' ); + + for( let i = 0 ; i < srcArray.length ; i++ ) + { + _.assert( _.bool.is( srcArray[ i ] ) || _.number.is( srcArray[ i ] ) || srcArray[ i ] === null ); + result += srcArray[ i ]; + } + + return result; +} + +// + +/** + * The longCountUnique() routine returns the count of matched pairs ([ 1, 1, 2, 2, ., . ]) in the array {-srcMap-}. + * + * @param { longLike } src - The source array. + * @param { Function } [ onEvaluate = function( e ) { return e } ] - A callback function. + * + * @example + * _.longCountUnique( [ 1, 1, 2, 'abc', 'abc', 4, true, true ] ); + * // returns 3 + * + * @example + * _.longCountUnique( [ 1, 2, 3, 4, 5 ] ); + * // returns 0 + * + * @returns { Number } - Returns the count of matched pairs ([ 1, 1, 2, 2, ., . ]) in the array {-srcMap-}. + * @function longCountUnique + * @throws { Error } If passed arguments is less than one or more than two. + * @throws { Error } If the first argument is not an array-like object. + * @throws { Error } If the second argument is not a Function. + * @namespace Tools + */ + +function longCountUnique( src, onEvaluate ) +{ + let found = []; + onEvaluate = onEvaluate || function( e ){ return e }; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.longLike( src ), 'longCountUnique :', 'Expects ArrayLike' ); + _.assert( _.routine.is( onEvaluate ) ); + _.assert( onEvaluate.length === 1 ); + + for( let i1 = 0 ; i1 < src.length ; i1++ ) + { + let element1 = onEvaluate( src[ i1 ] ); + if( found.indexOf( element1 ) !== -1 ) + continue; + + for( let i2 = i1+1 ; i2 < src.length ; i2++ ) + { + + let element2 = onEvaluate( src[ i2 ] ); + if( found.indexOf( element2 ) !== -1 ) + continue; + + if( element1 === element2 ) + found.push( element1 ); + + } + + } + + return found.length; +} + +// -- +// extension +// -- + +let Extension = +{ + + _longMake_functor, + + // longMake, + // longMakeEmpty, + // _longMakeOfLength, + // longMakeUndefined, + // longMakeZeroed, /* xxx : review */ + // longMakeFilling, + /* qqq : check routine longMakeFilling, and add perfect coverage */ + /* qqq : implement routine arrayMakeFilling, and add perfect coverage */ + + longFrom, /* aaa2 : cover please | Dmytro : covered */ + longFromCoercing, /* aaa2 : cover please | Dmytro : covered */ + + longFill, /* !!! */ + longFill_, + longDuplicate, + + _longClone, + _longShallow, + longSlice : _longShallow, + longRepresent, /* qqq2 : review. ask */ + longJoin, /* qqq for Dmytro : look, analyze and cover _.buferJoin */ + longEmpty, + + // longBut, + // longButInplace, /* !!! : use instead of longBut, longButInplace */ /* Dmytro : the coverage of the alternative covers inplace and not inplace versions */ + longBut_, + // longOnly, + // longOnlyInplace, /* !!! : use instead of longOnly, longOnlyInplace */ /* Dmytro : the coverage of the alternative covers inplace and not inplace versions */ + longOnly_, + // longGrow, + // longGrowInplace, /* !!! : use instead of longGrow, longGrowInplace */ /* Dmytro : the coverage of the alternative covers inplace and not inplace versions */ + longGrow_, + // longRelength, + // longRelengthInplace, /* !!! : use instead of longRelength, longRelengthInplace */ /* Dmytro : the coverage of the alternative covers inplace and not inplace versions */ + longRelength_, + + // array checker + + // longCompare, + + // long.identicalShallow, + // _long.identicalShallow, + // long.identical : long.identicalShallow, + // longEquivalentShallow : long.identicalShallow, + + longHas, + longHasAny, + longHasAll, + longHasNone, + longHasDepth, + + longAll, + longAny, + longNone, + + // long sequential search + + longCountElement, + longCountTotal, + longCountUnique, + + // to replace + + /* + | routine | makes new dst container | saves dst container | + | ---------------- | ---------------------------------------- | ------------------------------------------------------- | + | longBut_ | _.longBut_( null, src, range ) | _.longBut_( src ) | + | | _.longBut_( dst, src, range ) | _.longBut_( src, range ) | + | | if dst not resizable and change length | _.longBut_( dst, dst ) | + | | | _.longBut_( dst, dst, range ) if dst is resizable | + | | | or dst not change length | + | | | _.longBut_( dst, src, range ) if dst is resizable | + | | | or dst not change length | + | --------------- | ---------------------------------------- | ------------------------------------------------------ | + | longOnly_ | _.longOnly_( null, src, range ) | _.longOnly_( src ) | + | | _.longOnly_( dst, src, range ) | _.longOnly_( src, range ) | + | | if dst not resizable and change length | _.longOnly_( dst, dst ) | + | | | _.longOnly_( dst, dst, range ) if dst is resizable | + | | | or dst not change length | + | | | _.longOnly_( dst, src, range ) if dst is resizable | + | | | or dst not change length | + | --------------- | ---------------------------------------- | ------------------------------------------------------ | + | longGrow_ | _.longGrow_( null, src, range ) | _.longGrow_( src ) | + | | _.longGrow_( dst, src, range ) | _.longGrow_( src, range ) | + | | if dst not resizable and change length | _.longGrow_( dst, dst ) | + | | qqq2 : should throw error | _.longGrow_( dst, dst, range ) if dst is resizable | + | | if not resizable | or dst not change length | + | | | _.longGrow_( dst, src, range ) if dst is resizable | + | | | or dst not change length | + | --------------- | ---------------------------------------- | ------------------------------------------------------ | + | longRelength_ | _.longRelength_( null, src, range ) | _.longRelength_( src ) | + | | _.longRelength_( dst, src, range ) | _.longRelength_( src, range ) | + | | if dst not resizable and change length | _.longRelength_( dst, dst ) | + | | | _.longRelength_( dst, dst, range ) if dst is resizable | + | | | or dst not change length | + | | | _.longRelength_( dst, src, range ) if dst is resizable | + | | | or dst not change length | + | --------------- | ---------------------------------------- | ------------------------------------------------------- | + */ + +} + +_.props.supplement( _, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Long.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Long_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Long_s */ })(); + +/* */ /* begin of file Map_s */ ( function Map_s() { function Map_s_naked() { ( function _l5_Map_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +/* qqq for junior : check each _.aux.is() call, extend tests for each branch | aaa : Done. */ +/* qqq for junior : check each !_.primitive.is() call, extend tests for each branch | aaa : Done. */ +/* qqq for junior : check each _.vector.is() call, extend tests for each branch | aaa : Done. */ + +// -- +// map selector +// -- + +/** + * The mapFirstPair() routine returns first pair [ key, value ] as array. + * + * @param { objectLike } srcMap - An object like entity of get first pair. + * + * @example + * _.mapFirstPair( { a : 3, b : 13 } ); + * // returns [ 'a', 3 ] + * + * @example + * _.mapFirstPair( { } ); + * // returns 'undefined' + * + * @example + * _.mapFirstPair( [ [ 'a', 7 ] ] ); + * // returns [ '0', [ 'a', 7 ] ] + * + * @returns { Array } Returns pair [ key, value ] as array if {-srcMap-} has fields, otherwise, undefined. + * @function mapFirstPair + * @throws { Error } Will throw an Error if (arguments.length) less than one, if {-srcMap-} is not an object-like. + * @namespace Tools + */ + +function mapFirstPair( srcMap ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.object.like( srcMap ) ); + + for( let s in srcMap ) + { + return [ s, srcMap[ s ] ]; + } + + return []; +} + +// + +function mapAllValsSet( dstMap, val ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + for( let k in dstMap ) + { + dstMap[ k ] = val; + } + + return dstMap; +} + +// + +function mapValsWithKeys( srcMap, keys ) +{ + let result = Object.create( null ); + + _.assert( _.argumentsArray.like( keys ) ); + + for( let k = 0 ; k < keys.length ; k++ ) + { + let key = keys[ k ]; + _.assert( _.strIs( key ) || _.number.is( key ) ); + result[ key ] = srcMap[ key ]; + } + + return result; +} + +// + +/** + * The mapValWithIndex() returns value of {-srcMap-} by corresponding (index). + * + * It takes {-srcMap-} and (index), creates a variable ( i = 0 ), + * checks if ( index > 0 ), iterate over {-srcMap-} object-like and match + * if ( i == index ). + * If true, it returns value of {-srcMap-}. + * Otherwise it increment ( i++ ) and iterate over {-srcMap-} until it doesn't match index. + * + * @param { objectLike } srcMap - An object-like. + * @param { number } index - To find the position an element. + * + * @example + * _.mapValWithIndex( [ 3, 13, 'c', 7 ], 3 ); + * // returns 7 + * + * @returns { * } Returns value of {-srcMap-} by corresponding (index). + * @function mapValWithIndex + * @throws { Error } Will throw an Error if( arguments.length > 2 ) or {-srcMap-} is not an Object. + * @namespace Tools + */ + +function mapValWithIndex( srcMap, index ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( index < 0 ) + return; + + let i = 0; + for( let s in srcMap ) + { + if( i === index ) + return srcMap[ s ]; + i++; + } +} + +// + +/** + * The mapKeyWithIndex() returns key of {-srcMap-} by corresponding (index). + * + * It takes {-srcMap-} and (index), creates a variable ( i = 0 ), + * checks if ( index > 0 ), iterate over {-srcMap-} object-like and match + * if ( i == index ). + * If true, it returns value of {-srcMap-}. + * Otherwise it increment ( i++ ) and iterate over {-srcMap-} until it doesn't match index. + * + * @param { objectLike } srcMap - An object-like. + * @param { number } index - To find the position an element. + * + * @example + * _.mapKeyWithIndex( [ 'a', 'b', 'c', 'd' ], 1 ); + * // returns '1' + * + * @returns { string } Returns key of {-srcMap-} by corresponding (index). + * @function mapKeyWithIndex + * @throws { Error } Will throw an Error if( arguments.length > 2 ) or {-srcMap-} is not an Object. + * @namespace Tools + */ + +function mapKeyWithIndex( srcMap, index ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.number.intIs( index ) ); + _.assert( _.map.like( srcMap ) ); + + if( index < 0 ) + return; + + let i = 0; + for( let s in srcMap ) + { + if( i === index ) + return s; + i++; + } +} + +// + +function mapKeyWithValue( srcMap, value ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.map.like( srcMap ) ); + + for( let s in srcMap ) + if( srcMap[ s ] === value ) + return s; +} + +// + +// function mapIndexWithKey( srcMap, key ) +// { +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// +// for( let s in srcMap ) +// { +// if( s === key ) +// return s; +// } +// +// return; +// } +// +// // +// +// function mapIndexWithValue( srcMap, value ) +// { +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// +// for( let s in srcMap ) +// { +// if( srcMap[ s ] === value ) +// return s; +// } +// +// return; +// } + +// + +function mapOnlyNulls( srcMap ) +{ + let result = Object.create( null ); + + _.assert( arguments.length === 1 ); + _.assert( _.map.like( srcMap ) ); + + for( let s in srcMap ) + { + if( srcMap[ s ] === null ) + result[ s ] = null; + } + + return result; +} + +// + +function mapButNulls( srcMap ) +{ + let result = Object.create( null ); + + _.assert( arguments.length === 1 ); + + for( let s in srcMap ) + { + if( srcMap[ s ] !== null ) + result[ s ] = srcMap[ s ]; + } + + return result; +} + +// -- +// map checker +// -- + +// /** +// * The mapsAreIdentical() returns true, if the second object (src2) +// * has the same values as the first object(src1). +// * +// * It takes two objects (scr1, src2), checks +// * if both object have the same length and [key, value] return true +// * otherwise it returns false. +// * +// * @param { objectLike } src1 - First object. +// * @param { objectLike } src2 - Target object. +// * Objects to compare values. +// * +// * @example +// * _.map.identical( { a : 7, b : 13 }, { a : 7, b : 13 } ); +// * // returns true +// * +// * @example +// * _.map.identical( { a : 7, b : 13 }, { a : 33, b : 13 } ); +// * // returns false +// * +// * @example +// * _.map.identical( { a : 7, b : 13, c : 33 }, { a : 7, b : 13 } ); +// * // returns false +// * +// * @returns { boolean } Returns true, if the second object (src2) +// * has the same values as the first object(src1). +// * @function mapsAreIdentical +// * @throws Will throw an error if ( arguments.length !== 2 ). +// * @namespace Tools +// */ +// +// /* xxx qqq : for junior : duplicate in _.props.identical() | aaa : Done */ +// /* xxx qqq : for junior : move to _.aux.identical() | aaa : Done */ +// function mapsAreIdentical( src1, src2 ) +// { +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// _.assert( !_.primitive.is( src1 ) ); +// _.assert( !_.primitive.is( src2 ) ); +// +// if( Object.keys( src1 ).length !== Object.keys( src2 ).length ) +// return false; +// +// for( let s in src1 ) +// { +// if( src1[ s ] !== src2[ s ] ) +// return false; +// } +// +// return true; +// } +// +// // +// +// /** +// * The mapContain() returns true, if the first object {-srcMap-} +// * has the same values as the second object(ins). +// * +// * It takes two objects (scr, ins), +// * checks if the first object {-srcMap-} has the same [key, value] as +// * the second object (ins). +// * If true, it returns true, +// * otherwise it returns false. +// * +// * @param { objectLike } src - Target object. +// * @param { objectLike } ins - Second object. +// * Objects to compare values. +// * +// * @example +// * _.map.contain( { a : 7, b : 13, c : 15 }, { a : 7, b : 13 } ); +// * // returns true +// * +// * @example +// * _.map.contain( { a : 7, b : 13 }, { a : 7, b : 13, c : 15 } ); +// * // returns false +// * +// * @returns { boolean } Returns true, if the first object {-srcMap-} +// * has the same values as the second object(ins). +// * @function mapContain +// * @throws Will throw an error if ( arguments.length !== 2 ). +// * @namespace Tools +// */ +// +// function mapContain( src, ins ) +// { +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// +// /* +// if( Object.keys( src ).length < Object.keys( ins ).length ) +// return false; +// */ +// +// for( let s in ins ) +// { +// +// if( ins[ s ] === undefined ) +// continue; +// +// if( src[ s ] !== ins[ s ] ) +// return false; +// +// } +// +// return true; +// } + +// + +/** + * Checks if object( o.src ) has at least one key/value pair that is represented in( o.template ). + * Also works with ( o.template ) as routine that check( o.src ) with own rules. + * @param {wTools.objectSatisfyOptions} o - Default options {@link wTools.objectSatisfyOptions}. + * @returns { boolean } Returns true if( o.src ) has same key/value pair(s) with( o.template ) + * or result if ( o.template ) routine call is true. + * + * @example + * _.objectSatisfy( {a : 1, b : 1, c : 1 }, { a : 1, b : 2 } ); + * // returns true + * + * @example + * _.objectSatisfy( { template : {a : 1, b : 1, c : 1 }, src : { a : 1, b : 2 } } ); + * // returns true + * + * @example + * function routine( src ){ return src.a === 12 } + * _.objectSatisfy( { template : routine, src : { a : 1, b : 2 } } ); + * // returns false + * + * @function objectSatisfy + * @throws {exception} If( arguments.length ) is not equal to 1 or 2. + * @throws {exception} If( o.template ) is not a Object. + * @throws {exception} If( o.template ) is not a Routine. + * @throws {exception} If( o.src ) is undefined. + * @namespace Tools +*/ + +function objectSatisfy( o ) +{ + + if( arguments.length === 2 ) + o = { template : arguments[ 0 ], src : arguments[ 1 ] }; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.object.isBasic( o.template ) || _.routine.is( o.template ) ); + _.assert( o.src !== undefined ); + _.routine.options( objectSatisfy, o ); + + return _objectSatisfy( o.template, o.src, o.src, o.levels, o.strict ); + + /* */ + + function _objectSatisfy( /* template, src, root, levels, strict */ ) + { + let template = arguments[ 0 ]; + let src = arguments[ 1 ]; + let root = arguments[ 2 ]; + let levels = arguments[ 3 ]; + let strict = arguments[ 4 ]; + + if( !strict && src === undefined ) + return true; + + if( template === src ) + return true; + + if( levels === 0 ) + { + if + ( + _.object.isBasic( template ) + && _.object.isBasic( src ) + && _.routine.is( template.identicalWith ) + && src.identicalWith === template.identicalWith + ) + return template.identicalWith( src ); + else + return template === src; + } + else if( levels < 0 ) + { + return false; + } + + if( _.routine.is( template ) ) + return template( src ); + + if( !_.object.isBasic( src ) ) + return false; + + if( _.object.isBasic( template ) ) + { + for( let t in template ) + { + let satisfy = false; + satisfy = _objectSatisfy( template[ t ], src[ t ], root, levels-1, strict ); + if( !satisfy ) + return false; + } + return true; + } + + return false; + } + +} + +objectSatisfy.defaults = +{ + template : null, + src : null, + levels : 1, + strict : 1, +} + +// + +function mapOwnKey( srcMap, key ) +{ + // if( srcMap === null ) + // return false; + // if( srcMap === undefined ) + // return false; + if( _.primitive.is( srcMap ) ) + return false; + return Object.hasOwnProperty.call( srcMap, key ); +} + +// + +function mapHasKey( srcMap, key ) +{ + if( _.primitive.is( srcMap ) ) + return false; + if( !Reflect.has( srcMap, key ) ) + return false; + return true; +} + +// + +/** + * The mapOnlyOwnKey() returns true if (object) has own property. + * + * It takes (name) checks if (name) is a String, + * if (object) has own property with the (name). + * If true, it returns true. + * + * @param { Object } object - Object that will be check. + * @param { name } name - Target property. + * + * @example + * _.mapOnlyOwnKey( { a : 7, b : 13 }, 'a' ); + * // returns true + * + * @example + * _.mapOnlyOwnKey( { a : 7, b : 13 }, 'c' ); + * // returns false + * + * @returns { boolean } Returns true if (object) has own property. + * @function mapOnlyOwnKey + * @throws { mapOnlyOwnKey } Will throw an error if the (name) is unknown. + * @namespace Tools + */ + +// + +function mapOnlyOwnKey( object, key ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( key ) || _.symbolIs( key ), `Expects either string or symbol, but got ${_.entity.strType( key )}`, ); + + if( _.strIs( key ) ) + return Object.hasOwnProperty.call( object, key ); + else if( _.symbol.is( key ) ) + return Object.hasOwnProperty.call( object, key ); + // else if( _.aux.is( key ) ) + // return Object.hasOwnProperty.call( object, _.nameUnfielded( key ).coded ); + + // _.assert( 0, 'Unknown type of key :', _.entity.strType( key ) ); +} + +// + +function mapHasVal( object, val ) +{ + let vals = _.props.vals( object ); + return vals.indexOf( val ) !== -1; +} + +// + +function mapOnlyOwnVal( object, val ) +{ + let vals = _.props.onlyOwnVals( object ); + return vals.indexOf( val ) !== -1; +} + +// + +/** + * The mapHasAll() returns true if object( src ) has all enumerable keys from object( screen ). + * Values of properties are not checked, only names. + * + * Uses for..in to get each key name from object( screen ) and checks if source( src ) has property with same name. + * Returns true if all keys from( screen ) exists on object( src ), otherwise returns false. + * + * @param { ObjectLike } src - Map that will be checked for keys from( screen ). + * @param { ObjectLike } screen - Map that hold keys. + * + * @example + * _.mapHasAll( {}, {} ); + * // returns true + * + * @example + * _.mapHasAll( {}, { a : 1 } ); + * // returns false + * + * @returns { boolean } Returns true if object( src ) has all enumerable keys from( screen ). + * @function mapHasAll + * @throws { Exception } Will throw an error if the ( src ) is not a ObjectLike entity. + * @throws { Exception } Will throw an error if the ( screen ) is not a ObjectLike entity. + * @namespace Tools + */ + +function mapHasAll( src, screen ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( !_.primitive.is( src ) ); + _.assert( !_.primitive.is( screen ) ); + + if( _.argumentsArray.like( screen ) ) + { + for( let s = 0 ; s < screen.length ; s++ ) + if( !( screen[ s ] in src ) ) + return false; + } + else if( _.countable.is( screen ) ) + { + for( let value of screen ) + if( !( value in src ) ) + return false; + } + else if( _.aux.is( screen ) ) + { + for( let k in screen ) + if( !( k in src ) ) + return false; + } + + return true; + +} + +// + +/** + * The mapHasAny() returns true if object( src ) has at least one enumerable key from object( screen ). + * Values of properties are not checked, only names. + * + * Uses for..in to get each key name from object( screen ) and checks if source( src ) has at least one property with same name. + * Returns true if any key from( screen ) exists on object( src ), otherwise returns false. + * + * @param { ObjectLike } src - Map that will be checked for keys from( screen ). + * @param { ObjectLike|Vector } screen - Map or vector that hold keys. + * + * @example + * _.mapHasAny( {}, {} ); + * // returns false + * + * @example + * _.mapHasAny( { a : 1, b : 2 }, { a : 1 } ); + * // returns true + * + * @example + * _.mapHasAny( { a : 1, b : 2 }, { c : 1 } ); + * // returns false + * + * @returns { boolean } Returns true if object( src ) has at least one enumerable key from( screen ). + * @function mapHasAny + * @throws { Exception } Will throw an error if the ( src ) is not a ObjectLike entity. + * @throws { Exception } Will throw an error if the ( screen ) is not a ObjectLike entity. + * @namespace Tools + */ + +/* xxx qqq : for junior : teach to accept vector | aaa : Done. */ +/* xxx qqq : for junior : duplicate in _.props.hasAny() | aaa : Done */ +function mapHasAny( src, screen ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( !_.primitive.is( src ) ); + _.assert( !_.primitive.is( screen ) ); + + if( _.argumentsArray.like( screen ) ) + { + for( let s = 0 ; s < screen.length ; s++ ) + if( screen[ s ] in src ) + return true; + } + else if( _.countable.is( screen ) ) + { + for( let value of screen ) + if( value in src ) + return true; + } + else if( _.aux.is( screen ) ) + { + for( let k in screen ) + if( k in src ) + return true; + } + + return false; +} + +// + +/** + * The mapHasAny() returns true if object( src ) has no one enumerable key from object( screen ). + * Values of properties are not checked, only names. + * + * Uses for..in to get each key name from object( screen ) and checks if source( src ) has no one property with same name. + * Returns true if all keys from( screen ) not exists on object( src ), otherwise returns false. + * + * @param { ObjectLike } src - Map that will be checked for keys from( screen ). + * @param { ObjectLike } screen - Map that hold keys. + * + * @example + * _.mapHasNone( {}, {} ); + * // returns true + * + * @example + * _.mapHasNone( { a : 1, b : 2 }, { a : 1 } ); + * // returns false + * + * @example + * _.mapHasNone( { a : 1, b : 2 }, { c : 1 } ); + * // returns true + * + * @returns { boolean } Returns true if object( src ) has at least one enumerable key from( screen ). + * @function mapHasNone + * @throws { Exception } Will throw an error if the ( src ) is not a ObjectLike entity. + * @throws { Exception } Will throw an error if the ( screen ) is not a ObjectLike entity. + * @namespace Tools + */ + +/* qqq : for junior : teach to accept vector | aaa : Done */ +/* xxx qqq : for junior : duplicate in _.props.hasNone() | aaa : Done */ +function mapHasNone( src, screen ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( !_.primitive.is( src ) ); + _.assert( !_.primitive.is( screen ) ); + + if( _.argumentsArray.like( screen ) ) + { + for( let s = 0 ; s < screen.length ; s++ ) + if( screen[ s ] in src ) + return false; + } + else if( _.countable.is( screen ) ) + { + for( let value of screen ) + if( value in src ) + return false; + } + else if( _.aux.is( screen ) ) + { + for( let k in screen ) + if( k in src ) + return false; + } + + return true; +} + +// + +/** + * The mapOnlyOwnAll() returns true if object( src ) has all own keys from object( screen ). + * Values of properties are not checked, only names. + * + * Uses for..in to get each key name from object( screen ) and checks if source( src ) has own property with that key name. + * Returns true if all keys from( screen ) exists on object( src ), otherwise returns false. + * + * @param { Object } src - Map that will be checked for keys from( screen ). + * @param { Object } screen - Map that hold keys. + * + * @example + * _.mapOnlyOwnAll( {}, {} ); + * // returns true + * + * @example + * _.mapOnlyOwnAll( { a : 1, b : 2 }, { a : 1 } ); + * // returns true + * + * @example + * _.mapOnlyOwnAll( { a : 1, b : 2 }, { c : 1 } ); + * // returns false + * + * @returns { boolean } Returns true if object( src ) has own properties from( screen ). + * @function mapOnlyOwnAll + * @throws { Exception } Will throw an error if the ( src ) is not a ObjectLike entity. + * @throws { Exception } Will throw an error if the ( screen ) is not a ObjectLike entity. + * @namespace Tools + */ + +/* qqq : for junior : teach to accept vector | aaa : Done. */ +function mapOnlyOwnAll( src, screen ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( !_.primitive.is( src ) ); + _.assert( !_.primitive.is( screen ) ); + + if( _.argumentsArray.like( screen ) ) + { + for( let s = 0 ; s < screen.length ; s++ ) + if( !Object.hasOwnProperty.call( src, screen[ s ] ) ) + return false; + } + else if( _.countable.is( screen ) ) + { + for( let value of screen ) + if( !Object.hasOwnProperty.call( src, value ) ) + return false; + } + else if( _.aux.is( screen ) ) + { + for( let k in screen ) + if( !Object.hasOwnProperty.call( src, k ) ) + return false; + } + + return true; +} + +// + +/** + * The mapOnlyOwnAny() returns true if map( src ) has at least one own property from map( screen ). + * Values of properties are not checked, only names. + * + * Uses for..in to get each key name from map( screen ) and checks if source( src ) has at least one property with that key name. + * Returns true if one of keys from( screen ) exists on object( src ), otherwise returns false. + * + * @param { Object } src - Map that will be checked for keys from( screen ). + * @param { Object } screen - Map that hold keys. + * + * @example + * _.mapOnlyOwnAny( {}, {} ); + * // returns false + * + * @example + * _.mapOnlyOwnAny( { a : 1, b : 2 }, { a : 1 } ); + * // returns true + * + * @example + * _.mapOnlyOwnAny( { a : 1, b : 2 }, { c : 1 } ); + * // returns false + * + * @returns { boolean } Returns true if object( src ) has own properties from( screen ). + * @function mapOnlyOwnAny + * @throws { Exception } Will throw an error if the ( src ) is not a map. + * @throws { Exception } Will throw an error if the ( screen ) is not a map. + * @namespace Tools + */ + +/* qqq : for junior : teach to accept vector | aaa : Done. */ +function mapOnlyOwnAny( src, screen ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( !_.primitive.is( src ) ); + _.assert( !_.primitive.is( screen ) ); + + if( _.argumentsArray.like( screen ) ) + { + for( let s = 0 ; s < screen.length ; s++ ) + if( Object.hasOwnProperty.call( src, screen[ s ] ) ) + return true; + } + else if( _.countable.is( screen ) ) + { + for( let value of screen ) + if( Object.hasOwnProperty.call( src, value ) ) + return true; + } + else if( _.aux.is( screen ) ) + { + for( let k in screen ) + if( Object.hasOwnProperty.call( src, k ) ) + return true; + } + + return false; +} + +// + +/** + * The mapOnlyOwnNone() returns true if map( src ) not owns properties from map( screen ). + * Values of properties are not checked, only names. + * + * Uses for..in to get each key name from object( screen ) and checks if source( src ) has own property with that key name. + * Returns true if no one key from( screen ) exists on object( src ), otherwise returns false. + * + * @param { Object } src - Map that will be checked for keys from( screen ). + * @param { Object } screen - Map that hold keys. + * + * @example + * _.mapOnlyOwnNone( {}, {} ); + * // returns true + * + * @example + * _.mapOnlyOwnNone( { a : 1, b : 2 }, { a : 1 } ); + * // returns false + * + * @example + * _.mapOnlyOwnNone( { a : 1, b : 2 }, { c : 1 } ); + * // returns true + * + * @returns { boolean } Returns true if map( src ) not owns properties from( screen ). + * @function mapOnlyOwnNone + * @throws { Exception } Will throw an error if the ( src ) is not a map. + * @throws { Exception } Will throw an error if the ( screen ) is not a map. + * @namespace Tools + */ + +/* qqq : for junior : teach to accept vector | aaa : Done.*/ +/* xxx : move? */ +function mapOnlyOwnNone( src, screen ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( !_.primitive.is( src ) ); + _.assert( !_.primitive.is( screen ) ); + + if( _.argumentsArray.like( screen ) ) + { + for( let s = 0 ; s < screen.length ; s++ ) + if( Object.hasOwnProperty.call( src, screen[ s ] ) ) + return false; + } + else if( _.countable.is( screen ) ) + { + for( let value of screen ) + if( Object.hasOwnProperty.call( src, value ) ) + return false; + } + else if( _.aux.is( screen ) ) + { + for( let k in screen ) + if( Object.hasOwnProperty.call( src, k ) ) + return false; + } + + return true; +} + +// + +function mapHasExactly( srcMap, screenMaps ) +{ + let result = true; + + _.assert( arguments.length === 2 ); + + result = result && _.mapHasOnly( srcMap, screenMaps ); + result = result && _.mapHasAll( srcMap, screenMaps ); + + return result; +} + +// + +function mapOnlyOwnExactly( srcMap, screenMaps ) +{ + let result = true; + + _.assert( arguments.length === 2 ); + + result = result && _.mapOnlyOwnOnly( srcMap, screenMaps ); + result = result && _.mapOnlyOwnAll( srcMap, screenMaps ); + + return result; +} + +// + +function mapHasOnly( srcMap, screenMaps ) +{ + + _.assert( arguments.length === 2 ); + + let l = arguments.length; + let but = Object.keys( _.mapBut_( null, srcMap, screenMaps ) ); + + if( but.length > 0 ) + return false; + + return true; +} + +// + +/* xxx : review */ +function mapOnlyOwnOnly( srcMap, screenMaps ) +{ + + _.assert( arguments.length === 2 ); + + let l = arguments.length; + // let but = Object.keys( _.mapOnlyOwnBut_( null, srcMap, screenMaps ) ); + let but = Object.keys( _.mapOnlyOwnButOld( srcMap, screenMaps ) ); + + if( but.length > 0 ) + return false; + + return true; +} + +// + +function mapHasNoUndefine( srcMap ) +{ + + _.assert( arguments.length === 1 ); + + let but = []; + let l = arguments.length; + + for( let s in srcMap ) + if( srcMap[ s ] === undefined ) + return false; + + return true; +} + +// -- +// map move +// -- + +// /** +// * The mapMake() routine is used to copy the values of all properties +// * from one or more source objects to the new object. +// * +// * @param { ...objectLike } arguments[] - The source object(s). +// * +// * @example +// * _.mapMake( { a : 7, b : 13 }, { c : 3, d : 33 }, { e : 77 } ); +// * // returns { a : 7, b : 13, c : 3, d : 33, e : 77 } +// * +// * @returns { objectLike } It will return the new object filled by [ key, value ] +// * from one or more source objects. +// * @function mapMake +// * @namespace Tools +// */ +// +// function mapMake( src ) +// { +// _.assert( arguments.length === 0 || arguments.length === 1 ); +// if( arguments.length <= 1 ) +// if( arguments[ 0 ] === undefined || arguments[ 0 ] === null ) +// return Object.create( null ); +// return _.props.extend( null, src ); +// } +// +// // +// +// function mapCloneShallow( src ) +// { +// return _.mapMake( src ); +// } + +// + +/** + * @callback mapCloneAssigning.onField + * @param { objectLike } dstContainer - destination object. + * @param { objectLike } srcContainer - source object. + * @param { string } key - key to coping from one object to another. + * @param { function } onField - handler of fields. + */ + +/** + * The mapCloneAssigning() routine is used to clone the values of all + * enumerable own properties from {-srcMap-} object to an (options.dst) object. + * + * It creates two variables: + * let options = options || {}, result = options.dst || {}. + * Iterate over {-srcMap-} object, checks if {-srcMap-} object has own properties. + * If true, it calls the provided callback function( options.onField( result, srcMap, k ) ) for each key (k), + * and copies each [ key, value ] of the {-srcMap-} to the (result), + * and after cycle, returns clone with prototype of srcMap. + * + * @param { objectLike } srcMap - The source object. + * @param { Object } o - The options. + * @param { objectLike } [options.dst = Object.create( null )] - The target object. + * @param { mapCloneAssigning.onField } [options.onField()] - The callback function to copy each [ key, value ] + * of the {-srcMap-} to the (result). + * + * @example + * function Example() { + * this.name = 'Peter'; + * this.age = 27; + * } + * _.mapCloneAssigning( new Example(), { dst : { sex : 'Male' } } ); + * // returns Example { sex : 'Male', name : 'Peter', age : 27 } + * + * @returns { objectLike } The (result) object gets returned. + * @function mapCloneAssigning + * @throws { Error } Will throw an Error if ( o ) is not an Object, + * if ( arguments.length > 2 ), if (key) is not a String or + * if {-srcMap-} has not own properties. + * @namespace Tools + */ + +function mapCloneAssigning( o ) /* xxx : review */ +{ + o.dstMap = o.dstMap || Object.create( null ); + + _.assert( _.mapIs( o ) ); + _.assert( arguments.length === 1, 'Expects {-srcMap-} as argument' ); + _.assert( !_.primitive.is( o.srcMap ), 'Expects {-srcMap-} as argument' ); + _.routine.options( mapCloneAssigning, o ); + + if( !o.onField ) + o.onField = function onField( dstContainer, srcContainer, key ) + { + _.assert( _.strIs( key ) ); + dstContainer[ key ] = srcContainer[ key ]; + } + + for( let k in o.srcMap ) + { + if( Object.hasOwnProperty.call( o.srcMap, k ) ) + o.onField( o.dstMap, o.srcMap, k, o.onField ); + } + + Object.setPrototypeOf( o.dstMap, Object.getPrototypeOf( o.srcMap ) ); + + return o.dstMap; +} + +mapCloneAssigning.defaults = +{ + srcMap : null, + dstMap : null, + onField : null, +} + +// + +function mapsExtend( dstMap, srcMaps ) +{ + + if( dstMap === null ) + dstMap = Object.create( null ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( !_.primitive.is( dstMap ), 'Expects non primitive as the first argument' ); + + /* aaa : allow and cover vector */ /* Dmytro : allowed and covered. I think, an optimization for array like vectors has no sense. Otherwise, we need to add single branch with for cycle */ + if( _.countable.is( srcMaps ) ) + for( let srcMap of srcMaps ) + dstMapExtend( srcMap ); + else + dstMapExtend( srcMaps ); + + return dstMap; + + /* */ + + function dstMapExtend( srcMap ) + { + _.assert( !_.primitive.is( srcMap ), 'Expects non primitive' ); + + if( Object.getPrototypeOf( srcMap ) === null ) + Object.assign( dstMap, srcMap ); + else for( let k in srcMap ) + dstMap[ k ] = srcMap[ k ]; + } + + // if( dstMap === null ) + // dstMap = Object.create( null ); + // + // if( srcMaps.length === 1 && Object.getPrototypeOf( srcMaps[ 0 ] ) === null ) + // return Object.assign( dstMap, srcMaps[ 0 ] ); + // + // if( !_.vector.is( srcMaps ) ) + // srcMaps = [ srcMaps ]; + // + // _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + // _.assert( _.vector.is( srcMaps ) ); + // _.assert( !_.primitive.is( dstMap ), 'Expects non primitive as the first argument' ); + // + // /* aaa : allow and cover vector */ /* Dmytro : allowed and covered. I think, an optimization for array like vectors has no sense. Otherwise, we need to add single branch with for cycle */ + // for( let a = 0 ; a < srcMaps.length ; a++ ) + // { + // let srcMap = srcMaps[ a ]; + // + // _.assert( !_.primitive.is( srcMap ), 'Expects non primitive' ); + // + // if( Object.getPrototypeOf( srcMap ) === null ) + // Object.assign( dstMap, srcMap ); + // else for( let k in srcMap ) + // dstMap[ k ] = srcMap[ k ]; + // + // } + // + // return dstMap; +} + +// + +/** + * The mapExtendConditional() creates a new [ key, value ] + * from the next objects if callback function(filter) returns true. + * + * It calls a provided callback function(filter) once for each key in an (argument), + * and adds to the {-srcMap-} all the [ key, value ] for which callback + * function(filter) returns true. + * + * @param { function } filter - The callback function to test each [ key, value ] + * of the (dstMap) object. + * @param { objectLike } dstMap - The target object. + * @param { ...objectLike } arguments[] - The next object. + * + * @example + * _.mapExtendConditional( _.props.mapper.dstNotHas(), { a : 1, b : 2 }, { a : 1 , c : 3 } ); + * // returns { a : 1, b : 2, c : 3 } + * + * @returns { objectLike } Returns the unique [ key, value ]. + * @function mapExtendConditional + * @throws { Error } Will throw an Error if ( arguments.length < 3 ), (filter) + * is not a Function, (result) and (argument) are not the objects. + * @namespace Tools + */ + +function mapExtendConditional( filter, dstMap ) +{ + + if( dstMap === null ) + dstMap = Object.create( null ); + + _.assert( !!filter ); + // _.assert( filter.functionFamily === 'PropertyMapper' ); + _.assert( _.props.mapperIs( filter ) && !filter.identity.functor ); + _.assert( arguments.length >= 3, 'Expects more arguments' ); + _.assert( _.routine.is( filter ), 'Expects filter' ); + _.assert( !_.primitive.is( dstMap ), 'Expects non primitive as argument' ); + + for( let a = 2 ; a < arguments.length ; a++ ) + { + let srcMap = arguments[ a ]; + + _.assert( !_.primitive.is( srcMap ), () => 'Expects object-like entity to extend, but got : ' + _.entity.strType( srcMap ) ); + + for( let k in srcMap ) + { + + filter.call( this, dstMap, srcMap, k ); + + } + + } + + return dstMap; +} + +// + +function mapsExtendConditional( filter, dstMap, srcMaps ) +{ + + if( dstMap === null ) + dstMap = Object.create( null ); + + _.assert( !!filter ); + // _.assert( filter.functionFamily === 'PropertyMapper' ); + _.assert( _.props.mapperIs( filter ) && !filter.identity.functor ); + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + _.assert( _.routine.is( filter ), 'Expects filter' ); + _.assert( !_.primitive.is( dstMap ), 'Expects non primitive as argument' ); + + if( _.arrayIs( srcMaps ) ) + for( let a = 0 ; a < srcMaps.length ; a++ ) + { + let srcMap = srcMaps[ a ]; + + _.assert( !_.primitive.is( srcMap ), () => 'Expects object-like entity to extend, but got : ' + _.entity.strType( srcMap ) ); + + for( let k in srcMap ) + { + filter.call( this, dstMap, srcMap, k ); + } + } + else /* countable */ + for( let srcMap of srcMaps ) + { + _.assert( !_.primitive.is( srcMap ), () => 'Expects object-like entity to extend, but got : ' + _.entity.strType( srcMap ) ); + + for( let k in srcMap ) + { + filter.call( this, dstMap, srcMap, k ); + } + } + + return dstMap; +} + +// + +function mapExtendHiding( dstMap ) +{ + return _.mapExtendConditional( _.props.mapper.hiding(), ... arguments ); +} + +// + +function mapsExtendHiding( dstMap, srcMaps ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + return _.mapsExtendConditional( _.props.mapper.hiding(), dstMap, srcMaps ); +} + +// + +function mapExtendAppending( dstMap ) +{ + if( dstMap === null && arguments.length === 2 ) + return Object.assign( Object.create( null ), srcMap ); + return _.mapExtendConditional( _.props.mapper.appendingAnything(), ... arguments ); +} + +// + +function mapsExtendAppending( dstMap, srcMaps ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + if( dstMap === null ) + return _.props.extend( null, srcMaps[ 0 ] ); + return _.mapsExtendConditional( _.props.mapper.appendingAnything(), dstMap, srcMaps ); +} + +// + +function mapExtendPrepending( dstMap ) +{ + if( dstMap === null && arguments.length === 2 ) + return Object.assign( Object.create( null ), srcMap ); + return _.mapExtendConditional( _.props.mapper.prependingAnything(), ... arguments ); +} + +// + +function mapsExtendPrepending( dstMap, srcMaps ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + if( dstMap === null ) + return _.props.extend( null, srcMaps[ 0 ] ); + return _.mapsExtendConditional( _.props.mapper.prependingAnything(), dstMap, srcMaps ); +} + +// + +function mapExtendAppendingOnlyArrays( dstMap ) +{ + if( dstMap === null && arguments.length === 2 ) + return Object.assign( Object.create( null ), srcMap ); + return _.mapExtendConditional( _.props.mapper.appendingOnlyArrays(), ... arguments ); +} + +// + +function mapsExtendAppendingOnlyArrays( dstMap, srcMaps ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + if( dstMap === null ) + return _.props.extend( null, srcMaps[ 0 ] ); + return _.mapsExtendConditional( _.props.mapper.appendingOnlyArrays(), dstMap, srcMaps ); +} + +// + +function mapExtendByDefined( dstMap ) +{ + if( dstMap === null && arguments.length === 2 ) + return Object.assign( Object.create( null ), srcMap ); + return _.mapExtendConditional( _.props.mapper.srcDefined(), ... arguments ); +} + +// + +function mapsExtendByDefined( dstMap, srcMaps ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + return _.mapsExtendConditional( _.props.mapper.srcDefined(), dstMap, srcMaps ); +} + +// + +function mapExtendNulls( dstMap ) +{ + return _.mapExtendConditional( _.props.mapper.dstNotHasOrSrcNotNull(), ... arguments ); +} + +// + +function mapsExtendNulls( dstMap, srcMaps ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + return _.mapsExtendConditional( _.props.mapper.dstNotHasOrSrcNotNull(), dstMap, srcMaps ); +} + +// + +function mapExtendDstNotOwn( dstMap, srcMap ) +{ + if( dstMap === null && arguments.length === 2 ) + return _.props.extend( dstMap, srcMap ); + return _.mapExtendConditional( _.props.mapper.dstNotOwn(), ... arguments ); +} + +// + +function mapsExtendDstNotOwn( dstMap, srcMaps ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + if( dstMap === null ) + return _.props.extend( null, srcMaps[ 0 ] ); + return _.mapsExtendConditional( _.props.mapper.dstNotOwn(), dstMap, srcMaps ); +} + +// + +function mapExtendNotIdentical( dstMap, srcMap ) +{ + if( dstMap === null && arguments.length === 2 ) + return _.props.extend( dstMap, srcMap ); + return _.mapExtendConditional( _.props.mapper.notIdentical(), ... arguments ); +} + +// + +function mapsExtendNotIdentical( dstMap, srcMaps ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + if( dstMap === null ) + return _.props.extend( null, srcMaps[ 0 ] ); + return _.mapsExtendConditional( _.props.mapper.notIdentical(), dstMap, srcMaps ); +} + +// + +function mapSupplementByMaps( dstMap, srcMaps ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + if( dstMap === null ) + return _.props.extend( null, srcMaps[ 0 ] ); + return _.mapsExtendConditional( _.props.mapper.dstNotHas(), dstMap, srcMaps ); +} + +// + +function mapSupplementNulls( dstMap ) +{ + return _.mapExtendConditional( _.props.mapper.dstNotHasOrHasNull(), ... arguments ); +} + +// + +function mapSupplementNils( dstMap ) +{ + return _.mapExtendConditional( _.props.mapper.dstNotHasOrHasNil(), ... arguments ); +} + +// + +function mapSupplementAssigning( dstMap ) +{ + return _.mapExtendConditional( _.props.mapper.dstNotHasAssigning(), ... arguments ); +} + +// + +function mapSupplementAppending( dstMap ) +{ + if( dstMap === null && arguments.length === 2 ) + return Object.assign( Object.create( null ), srcMap ); + return _.mapExtendConditional( _.props.mapper.dstNotHasAppending(), ... arguments ); +} + +// + +function mapsSupplementAppending( dstMap, srcMaps ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + return _.mapsExtendConditional( _.props.mapper.dstNotHasAppending(), dstMap, srcMaps ); +} + +// + +function mapSupplementOwnAssigning( dstMap ) +{ + return _.mapExtendConditional( _.props.mapper.dstNotOwnAssigning(), ... arguments ); +} + +// + +/** + * The routine mapComplement() complements {-dstMap-} by one or several {-srcMap-}. Routine does not change + * defined pairs key-value in {-dstMap-}. + * If {-dstMap-} and {-srcMap-} has equal keys, and value of {-dstMap-} is undefined, then routine + * mapComplement() changes it to {-srcMap-} value. + * If pair key-value does not exists in {-dstMap-}, then routine appends this pair to {-dstMap-}. + * + * @param { objectLike } dstMap - ObjectLike entity to be complemented. + * @param { ...objectLike } srcMap - The source object(s). + * + * @example + * _.mapComplement( { a : 1, b : 2, c : 3 }, { a : 4, b : 5, c : 6, d : 7 } ); + * // returns { a : 1, b : 3, c : 3, d : 7 }; + * + * @example + * _.mapComplement( { a : 1, b : 2, c : 3 }, { a : 4, b : 5 }, { c : 6, d : 7 } ); + * // returns { a : 1, b : 3, c : 3, d : 7 }; + * + * @example + * _.mapComplement( { a : 1, b : 2, c : undefined }, { a : 4, b : 5, c : 6, d : 7 } ); + * // returns { a : 1, b : 3, c : 6, d : 7 }; + * + * @example + * _.mapComplement( { a : 1, b : 2, c : undefined }, { a : 4, b : 5 }, { c : 6, d : 7 } ); + * // returns { a : 1, b : 3, c : 6, d : 7 }; + * + * @returns { objectLike } - Returns the destination object filled by unique values from source object(s), and if it is possible, replaced undefined + * values in destination object. + * @function mapComplement + * @namespace Tools + */ + +function mapComplement( dstMap, srcMap ) +{ + dstNotOwnOrUndefinedAssigning.identity = { propertyMapper : true, propertyTransformer : true }; + return _.mapExtendConditional( dstNotOwnOrUndefinedAssigning, ... arguments ); + + function dstNotOwnOrUndefinedAssigning( dstContainer, srcContainer, key ) + { + if( Object.hasOwnProperty.call( dstContainer, key ) ) + { + if( dstContainer[ key ] !== undefined ) + return; + } + _.entity.assign2FieldFromContainer( dstContainer, srcContainer, key ); + } + +} + +// + +function mapsComplement( dstMap, srcMaps ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + return _.mapsExtendConditional( _.props.mapper.dstNotOwnOrUndefinedAssigning(), dstMap, srcMaps ); +} + +// + +function mapComplementReplacingUndefines( dstMap, srcMap ) +{ + _.assert( !!_.props.mapper ); + return _.mapExtendConditional( _.props.mapper.dstNotOwnOrUndefinedAssigning(), ... arguments ); +} + +// + +function mapsComplementReplacingUndefines( dstMap, srcMaps ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + return _.mapsExtendConditional( _.props.mapper.dstNotOwnOrUndefinedAssigning(), dstMap, srcMaps ); +} + +// + +function mapComplementPreservingUndefines( dstMap ) +{ + return _.mapExtendConditional( _.props.mapper.dstNotOwnAssigning(), ... arguments ); +} + +// + +function mapsComplementPreservingUndefines( dstMap, srcMaps ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + return _.mapsExtendConditional( _.props.mapper.dstNotOwnAssigning(), dstMap, srcMaps ); +} + +// -- +// map recursive +// -- + +function mapExtendRecursiveConditional( filters, dstMap, srcMap ) +{ + _.assert( arguments.length >= 3, 'Expects at least three arguments' ); + // _.assert( this === Self ); + let srcMaps = _.longSlice( arguments, 2 ); + return _.mapsExtendRecursiveConditional( filters, dstMap, srcMaps ); +} + +// + +function _filterTrue(){ return true }; +_filterTrue.identity = { propertyCondition : true, propertyTransformer : true }; +function _filterFalse(){ return true }; +_filterFalse.identity = { propertyCondition : true, propertyTransformer : true }; + +function mapsExtendRecursiveConditional( filters, dstMap, srcMaps ) +{ + + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + // _.assert( this === Self ); + + if( _.routine.is( filters ) ) + filters = { onUpFilter : filters, onField : filters } + + if( filters.onUpFilter === undefined ) + filters.onUpFilter = filters.onField; + else if( filters.onUpFilter === true ) + filters.onUpFilter = _filterTrue; + else if( filters.onUpFilter === false ) + filters.onUpFilter = _filterFalse; + + if( filters.onField === true ) + filters.onField = _filterTrue; + else if( filters.onField === false ) + filters.onField = _filterFalse; + + _.assert( _.routine.is( filters.onUpFilter ) ); + _.assert( _.routine.is( filters.onField ) ); + // _.assert( _.props.conditionIs( filters.onUpFilter ) ); + _.assert( _.props.conditionIs( filters.onUpFilter ) && !filters.onUpFilter.identity.functor, 'Expects PropertyFilter {-propertyCondition-}' ); + _.assert( _.props.transformerIs( filters.onField ) ); + // _.assert( filters.onUpFilter.functionFamily === 'PropertyFilter' ); + // _.assert( filters.onField.functionFamily === 'PropertyFilter' || filters.onField.functionFamily === 'PropertyMapper' ); + + if( _.arrayIs( srcMaps ) ) + for( let a = 0 ; a < srcMaps.length ; a++ ) + { + let srcMap = srcMaps[ a ]; + _mapExtendRecursiveConditional( filters, dstMap, srcMap ); + } + else /* countable */ + { + for( let srcMap of srcMaps ) + _mapExtendRecursiveConditional( filters, dstMap, srcMap ); + } + + return dstMap; +} + +// + +function _mapExtendRecursiveConditional( filters, dstMap, srcMap ) +{ + + _.assert( _.aux.is( srcMap ) ); + + for( let s in srcMap ) + { + + if( _.aux.is( srcMap[ s ] ) ) + { + + if( filters.onUpFilter( dstMap, srcMap, s ) === true ) + { + if( !_.object.isBasic( dstMap[ s ] ) ) + dstMap[ s ] = Object.create( null ); + _._mapExtendRecursiveConditional( filters, dstMap[ s ], srcMap[ s ] ); + } + + } + else + { + + if( filters.onField( dstMap, srcMap, s ) === true ) + dstMap[ s ] = srcMap[ s ]; + + } + + } + + return dstMap; +} + +// + +function mapExtendRecursive( dstMap, srcMap ) +{ + + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + // _.assert( this === Self ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + srcMap = arguments[ a ]; + _._mapExtendRecursive( dstMap, srcMap ); + } + + return dstMap; +} + +// + +function mapsExtendRecursive( dstMap, srcMaps ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + // _.assert( this === Self ); + + if( _.arrayIs( srcMaps ) ) + for( let a = 1 ; a < srcMaps.length ; a++ ) + { + let srcMap = srcMaps[ a ]; + _._mapExtendRecursive( dstMap, srcMap ); + } + else /* countable */ + { + for( let srcMap of srcMaps ) + _._mapExtendRecursive( dstMap, srcMap ); + } + + return dstMap; +} + +// + +function _mapExtendRecursive( dstMap, srcMap ) +{ + + if( dstMap === null ) + dstMap = Object.create( null ); + + _.assert( _.aux.is( srcMap ) ); + + for( let s in srcMap ) + { + + if( _.aux.is( srcMap[ s ] ) ) + { + + if( !_.aux.is( dstMap[ s ] ) ) + dstMap[ s ] = Object.create( null ); + _._mapExtendRecursive( dstMap[ s ], srcMap[ s ] ); + + } + else + { + + dstMap[ s ] = srcMap[ s ]; + + } + + } + +} + +// + +function mapExtendAppendingAnythingRecursive( dstMap, srcMap ) +{ + // _.assert( this === Self ); + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + let filters = { onField : _.props.mapper.appendingAnything(), onUpFilter : true }; + return _.mapExtendRecursiveConditional( filters, ... arguments ); +} + +// + +function mapsExtendAppendingAnythingRecursive( dstMap, srcMaps ) +{ + // _.assert( this === Self ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + let filters = { onField : _.props.mapper.appendingAnything(), onUpFilter : true }; + return _.mapsExtendRecursiveConditional.call( _, filters, dstMap, srcMaps ); +} + +// + +function mapExtendAppendingArraysRecursive( dstMap, srcMap ) +{ + // _.assert( this === Self ); + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + let filters = { onField : _.props.mapper.appendingOnlyArrays(), onUpFilter : true }; + return _.mapExtendRecursiveConditional( filters, ... arguments ); +} + +// + +function mapsExtendAppendingArraysRecursive( dstMap, srcMaps ) +{ + // _.assert( this === Self ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + let filters = { onField : _.props.mapper.appendingOnlyArrays(), onUpFilter : true }; + return _.mapsExtendRecursiveConditional.call( _, filters, dstMap, srcMaps ); +} + +// + +function mapExtendAppendingOnceRecursive( dstMap, srcMap ) +{ + // _.assert( this === Self ); + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + let filters = { onField : _.props.mapper.appendingOnce(), onUpFilter : true }; + return _.mapExtendRecursiveConditional( filters, ... arguments ); +} + +// + +function mapsExtendAppendingOnceRecursive( dstMap, srcMaps ) +{ + // _.assert( this === Self ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + let filters = { onField : _.props.mapper.appendingOnce(), onUpFilter : true }; + return _.mapsExtendRecursiveConditional.call( _, filters, dstMap, srcMaps ); +} + +// + +function mapSupplementRecursive( dstMap, srcMap ) +{ + // _.assert( this === Self ); + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + let filters = { onField : _.props.mapper.dstNotHas(), onUpFilter : true }; + return _.mapExtendRecursiveConditional( filters, ... arguments ); +} + +// + +function mapSupplementByMapsRecursive( dstMap, srcMaps ) +{ + // _.assert( this === Self ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + let filters = { onField : _.props.mapper.dstNotHas(), onUpFilter : true }; + return _.mapsExtendRecursiveConditional.call( _, filters, dstMap, srcMaps ); +} + +// + +function mapSupplementOwnRecursive( dstMap, srcMap ) +{ + // _.assert( this === Self ); + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + let filters = { onField : _.props.mapper.dstOwn(), onUpFilter : true }; + return _.mapExtendRecursiveConditional( filters, ... arguments ); +} + +// + +function mapsSupplementOwnRecursive( dstMap, srcMaps ) +{ + // _.assert( this === Self ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + let filters = { onField : _.props.mapper.dstOwn(), onUpFilter : true }; + return _.mapsExtendRecursiveConditional.call( _, filters, dstMap, srcMaps ); +} + +// + +function mapSupplementRemovingRecursive( dstMap, srcMap ) +{ + // _.assert( this === Self ); + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + let filters = { onField : _.props.mapper.removing(), onUpFilter : true }; + return _.mapExtendRecursiveConditional( filters, ... arguments ); +} + +// + +function mapSupplementByMapsRemovingRecursive( dstMap, srcMaps ) +{ + // _.assert( this === Self ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + let filters = { onField : _.props.mapper.removing(), onUpFilter : true }; + return _.mapsExtendRecursiveConditional.call( _, filters, dstMap, srcMaps ); +} + +// -- +// map selector +// -- + +/** + * The mapOnlyPrimitives() gets all object`s {-srcMap-} enumerable atomic fields( null, undef, number, string, symbol ) and returns them as new map. + * + * It takes an object {-srcMap-} creates an empty map, + * checks if {-srcMap-} is an object. + * If true, it copies object`s {-srcMap-} enumerable atomic properties to the new map using + * their original name/value and returns the result, otherwise it returns empty map. + * + * @param { objectLike } srcMap - Object to get a map of atomic properties. + * + * @example + * let a = {}; + * Object.defineProperty( a, 'x', { enumerable : 0, value : 3 } ) + * _.mapOnlyPrimitives( a ); + * // returns {} + * + * @example + * let a = { a : 1 }; + * let b = { b : 2, c : function(){} }; + * Object.setPrototypeOf( a, b ); + * _.mapOnlyPrimitives( a ); + * // returns { a : 1, b : 2 } + * + * @returns { object } A new map with all atomic fields from source {-srcMap-}. + * @function mapOnlyPrimitives + * @throws { Error } Will throw an Error if {-srcMap-} is not an Object. + * @namespace Tools + */ + +function mapOnlyPrimitives( srcMap ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( !_.primitive.is( srcMap ) ); + + let result = _.mapExtendConditional( _.props.mapper.primitive(), Object.create( null ), srcMap ); + return result; +} + +// -- +// map manipulator +// -- + +function mapSetWithKeys( dstMap, key, val ) +{ + if( dstMap === null ) + dstMap = Object.create( null ); + + _.assert( _.object.isBasic( dstMap ) ); + _.assert( _.strIs( key ) || _.countable.is( key ) ); + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + + /* aaa : allow and cover vector */ /* Dmytro : implemented and covered */ + if( _.countable.is( key ) ) + { + if( _.argumentsArray.like( key ) ) + for( let s = 0 ; s < key.length ; s++ ) + set( dstMap, key[ s ], val ); + else + for( let value of key ) + set( dstMap, value, val ); + } + else + { + set( dstMap, key, val ); + } + + return dstMap; + + /* */ + + function set( dstMap, key, val ) + { + if( val === undefined ) + delete dstMap[ key ]; + else + dstMap[ key ] = val; + } +} + +// + +function mapSetWithKeyStrictly( dstMap, key, val ) +{ + if( dstMap === null ) + dstMap = Object.create( null ); + + _.assert( _.object.isBasic( dstMap ) ); + _.assert( _.strIs( key ) || _.countable.is( key ) ); + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + + /* aaa : allow and cover vector */ /* Dmytro : implemented and covered */ + if( _.countable.is( key ) ) + { + if( _.argumentsArray.like( key ) ) + for( let s = 0 ; s < key.length ; s++ ) + set( dstMap, key[ s ], val ); + else + for( let value of key ) + set( dstMap, value, val ); + } + else + { + set( dstMap, key, val ); + } + + return dstMap; + + function set( dstMap, key, val ) + { + if( val === undefined ) + { + delete dstMap[ key ]; + } + else + { + _.assert( dstMap[ key ] === undefined || dstMap[ key ] === val ); + dstMap[ key ] = val; + } + } +} + +// -- +// map getter +// -- + +function mapInvert( src, dst ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + return _._mapInvert({ src, dst }); +} + +mapInvert.defaults = +{ + src : null, + dst : null, + duplicate : 'error', +} + +// + +function _mapInvert( o ) +{ + _.routine.options( _mapInvert, o ); + + o.dst = o.dst || Object.create( null ); + + _.assert( arguments.length === 1, 'Expects exactly one argument' ); + _.assert( !_.primitive.is( o.src ) ); + _.assert( !_.primitive.is( o.dst ) ); + /* qqq : for junior : bad : lack of important assert */ + + let del; + if( o.duplicate === 'delete' ) + del = Object.create( null ); + + /* */ + + for( let k in o.src ) + { + let e = o.src[ k ]; + if( o.duplicate === 'delete' ) + if( o.dst[ e ] !== undefined ) + { + del[ e ] = k; + continue; + } + if( o.duplicate === 'array' || o.duplicate === 'array-with-value' ) + { + if( o.dst[ e ] === undefined ) + o.dst[ e ] = o.duplicate === 'array-with-value' ? [ e ] : []; + o.dst[ e ].push( k ); + } + else + { + _.assert( o.dst[ e ] === undefined, 'Cant invert the map, it has several keys with value', o.src[ k ] ); + o.dst[ e ] = k; + } + } + + /* */ + + if( o.duplicate === 'delete' ) + _.mapDelete( o.dst, del ); + + return o.dst; +} + +_mapInvert.defaults = +{ + src : null, + dst : null, + duplicate : 'error', +} + +// + +function mapInvertDroppingDuplicates( src, dst ) +{ + dst = dst || Object.create( null ); + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( !_.primitive.is( src ) ); + + let drop; + + for( let s in src ) + { + if( dst[ src[ s ] ] !== undefined ) + { + drop = drop || Object.create( null ); + drop[ src[ s ] ] = true; + } + dst[ src[ s ] ] = s; + } + + if( drop ) + for( let d in drop ) + { + delete dst[ d ]; + } + + return dst; +} + +// + +function mapsFlatten( o ) +{ + + if( _.countable.is( o ) ) + o = { src : o }; + + _.routine.options( mapsFlatten, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( o.delimeter === false || o.delimeter === 0 || _.strIs( o.delimeter ) ); + _.assert( _.countable.is( o.src ) || _.aux.is( o.src ) ); /* xxx */ + + o.dst = o.dst || Object.create( null ); + extend( o.src, '' ); + + return o.dst; + + /* */ + + function extend( src, prefix ) + { + + /* aaa : allow and cover vector */ /* Dmytro : extended, covered */ + if( _.countable.is( src ) ) + { + if( _.argumentsArray.like( src ) ) + for( let s = 0 ; s < src.length ; s++ ) + extend( src[ s ], prefix ); + else + for( let value of src ) + extend( value, prefix ); + } + else if( _.aux.is( src ) ) + { + + for( let k in src ) + { + let key = k; + if( _.strIs( o.delimeter ) ) + key = ( prefix ? prefix + o.delimeter : '' ) + k; + + if( _.aux.is( src[ k ] ) ) + { + extend( src[ k ], key ); + } + else + { + _.assert( !!o.allowingCollision || o.dst[ key ] === undefined ); + o.dst[ key ] = src[ k ]; + } + } + + } + else + { + _.assert( 0, 'Expects map or array of maps, but got ' + _.entity.strType( src ) ); + } + } + +} + +mapsFlatten.defaults = +{ + src : null, + dst : null, + allowingCollision : 0, + delimeter : '/', +} + +// // +// +// /** +// * The mapToArray() converts an object {-srcMap-} into array [ [ key, value ] ... ]. +// * +// * It takes an object {-srcMap-} creates an empty array, +// * checks if ( arguments.length === 1 ) and {-srcMap-} is an object. +// * If true, it returns a list of [ [ key, value ] ... ] pairs. +// * Otherwise it throws an Error. +// * +// * @param { objectLike } src - object to get a list of [ key, value ] pairs. +// * +// * @example +// * _.mapToArray( { a : 3, b : 13, c : 7 } ); +// * // returns [ [ 'a', 3 ], [ 'b', 13 ], [ 'c', 7 ] ] +// * +// * @returns { array } Returns a list of [ [ key, value ] ... ] pairs. +// * @function mapToArray +// * @throws { Error } Will throw an Error if( arguments.length !== 1 ) or {-srcMap-} is not an object. +// * @namespace Tools +// */ +// +// function mapToArray( src, o ) +// { +// _.assert( this === _ ); +// return _.map.pairs( ... arguments ); +// } + +// + +/** + * The mapToStr() routine converts and returns the passed object {-srcMap-} to the string. + * + * It takes an object and two strings (keyValSep) and (tupleSep), + * checks if (keyValSep and tupleSep) are strings. + * If false, it assigns them defaults ( ' : ' ) to the (keyValSep) and + * ( '; ' ) to the tupleSep. + * Otherwise, it returns a string representing the passed object {-srcMap-}. + * + * @param { objectLike } src - The object to convert to the string. + * @param { string } [ keyValSep = ' : ' ] keyValSep - colon. + * @param { string } [ tupleSep = '; ' ] tupleSep - semicolon. + * + * @example + * _.mapToStr( { a : 1, b : 2, c : 3, d : 4 }, ' : ', '; ' ); + * // returns 'a : 1; b : 2; c : 3; d : 4' + * + * @example + * _.mapToStr( [ 1, 2, 3 ], ' : ', '; ' ); + * // returns '0 : 1; 1 : 2; 2 : 3'; + * + * @example + * _.mapToStr( 'abc', ' : ', '; ' ); + * // returns '0 : a; 1 : b; 2 : c'; + * + * @returns { string } Returns a string (result) representing the passed object {-srcMap-}. + * @function mapToStr + * @namespace Tools + */ + +function mapToStr( o ) +{ + + if( _.strIs( o ) ) + o = { src : o } + + _.routine.options( mapToStr, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + let result = ''; + for( let s in o.src ) + { + result += s + o.keyValDelimeter + o.src[ s ] + o.entryDelimeter; + } + + result = result.substr( 0, result.length-o.entryDelimeter.length ); + + return result +} + +mapToStr.defaults = +{ + src : null, + keyValDelimeter : ':', + entryDelimeter : ';', +} + +// + +function fromHashMap( dstMap, srcMap ) +{ + + if( arguments.length === 1 ) + { + srcMap = arguments[ 0 ]; + dstMap = null; + } + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.hashMap.is( srcMap ) ); + _.assert( !_.primitiveIs( dstMap ) || dstMap === null ); + + if( dstMap === null ) + dstMap = Object.create( null ); + + for( let pair of srcMap ) + { + dstMap[ pair[ 0 ] ] = pair[ 1 ]; + } + + return dstMap +} + +// -- +// map logical operator +// -- + +/** + * The mapButConditional() routine returns a new object (result) + * whose (values) are not equal to the arrays or objects. + * + * Takes any number of objects. + * If the first object has same key any other object has + * then this pair [ key, value ] will not be included into (result) object. + * Otherwise, + * it calls a provided callback function( _.props.mapper.primitive() ) + * once for each key in the {-srcMap-}, and adds to the (result) object + * all the [ key, value ], + * if values are not equal to the array or object. + * + * @param { function } filter.primitive() - Callback function to test each [ key, value ] of the {-srcMap-} object. + * @param { objectLike } srcMap - The target object. + * @param { ...objectLike } arguments[] - The next objects. + * + * @example + * _.mapButConditional_( null, _.props.mapper.primitive(), { a : 1, b : 'b', c : [ 1, 2, 3 ] } ); + * // returns { a : 1, b : "b" } + * + * @returns { object } Returns an object whose (values) are not equal to the arrays or objects. + * @function mapButConditional + * @throws { Error } Will throw an Error if {-srcMap-} is not an object. + * @namespace Tools + */ + +function mapButConditionalOld( propertyCondition, srcMap, butMap ) +{ + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + _.assert( !_.primitive.is( butMap ), 'Expects non primitive {-butMap-}' ); + _.assert( !_.primitive.is( srcMap ), 'Expects non primitive {-srcMap-}' ); + _.assert( propertyCondition && propertyCondition.length === 3, 'Expects PropertyFilter {-propertyCondition-}' ); + _.assert( _.props.conditionIs( propertyCondition ) && !propertyCondition.identity.functor, 'Expects PropertyFilter {-propertyCondition-}' ); + + let result = Object.create( null ); + + /* aaa : allow and cover vector */ /* Dmytro : implemented, covered */ + if( _.countable.is( butMap ) ) + { + let filterRoutines = [ filterWithVectorButMap, filterWithArrayLikeButMap ]; + let arrayLikeIs = _.argumentsArray.like( butMap ) ? 1 : 0; + for( let s in srcMap ) + { + let butKey = filterRoutines[ arrayLikeIs ]( s ); + if( butKey === undefined ) + result[ s ] = srcMap[ s ]; + } + } + else + { + for( let s in srcMap ) + { + if( propertyCondition( butMap, srcMap, s ) ) + result[ s ] = srcMap[ s ]; + } + } + + return result; + + /* */ + + function filterWithVectorButMap( s ) + { + for( let but of butMap ) + if( !propertyCondition( but, srcMap, s ) ) + return s; + } + + /* */ + + function filterWithArrayLikeButMap( s ) + { + for( let m = 0 ; m < butMap.length ; m++ ) + if( !propertyCondition( butMap[ m ], srcMap, s ) ) + return s; + } +} + +// + +function mapButConditional_( /* propertyCondition, dstMap, srcMap, butMap */ ) +{ + // _.assert( arguments.length === 3 || arguments.length === 4, 'Expects three or four arguments' ); + + _.assert( arguments.length === 4, 'Not clear how to construct {-dstMap-}. Please, specify exactly 4 arguments' ); + + let propertyCondition = arguments[ 0 ]; + let dstMap = arguments[ 1 ]; + let srcMap = arguments[ 2 ]; + let butMap = arguments[ 3 ]; + + if( dstMap === null ) + dstMap = arguments[ 1 ] = Object.create( null ); + + // if( arguments.length === 3 ) + // { + // butMap = arguments[ 2 ]; + // srcMap = arguments[ 1 ]; + // } + + /* */ + + let o = + { + filter : propertyCondition, + dstMap, + srcMap, + butMap, + }; + + o = _._mapBut_VerifyMapFields( o ); + _.assert( _.routineIs( o.filter ) && o.filter.length === 3, 'Expects filter {-o.filter-}' ); + _.assert( _.props.conditionIs( o.filter ), 'Expects PropertyFilter {-o.filter-}' ); + + let filterRoutine = _._mapBut_FilterFunctor( o ); + + for( let key in o.srcMap ) + filterRoutine( key ); + + return o.dstMap; + + + // return _._mapBut_ + // ({ + // filter : propertyCondition, + // dstMap, + // srcMap, + // butMap, + // }); + + // _.assert( arguments.length === 3 || arguments.length === 4, 'Expects three or four arguments' ); + // _.assert( _.routineIs( propertyCondition ) && propertyCondition.length === 3, 'Expects PropertyFilter {-propertyCondition-}' ); + // _.assert( _.props.conditionIs( propertyCondition ) && !propertyCondition.identity.functor, 'Expects PropertyFilter {-propertyCondition-}' ); + // _.assert( !_.primitive.is( dstMap ), 'Expects map like {-dstMap-}' ); + // _.assert( !_.primitive.is( srcMap ) || _.longIs( srcMap ), 'Expects map {-srcMap-}' ); + // _.assert( !_.primitive.is( butMap ) || _.longIs( butMap ) || _.routineIs( butMap ), 'Expects object like {-butMap-}' ); + // + // if( dstMap === srcMap ) + // { + // + // /* aaa : allow and cover vector */ /* Dmytro : implemented, covered */ + // if( _.vector.is( butMap ) ) + // { + // for( let s in srcMap ) + // { + // for( let m = 0 ; m < butMap.length ; m++ ) + // { + // if( !propertyCondition( butMap[ m ], srcMap, s ) ) + // delete dstMap[ s ]; + // } + // } + // } + // else + // { + // for( let s in srcMap ) + // { + // if( !propertyCondition( butMap, srcMap, s ) ) + // delete dstMap[ s ]; + // } + // } + // + // } + // else + // { + // + // /* aaa : allow and cover vector */ /* Dmytro : implemented, covered */ + // if( _.vector.is( butMap ) ) + // { + // /* aaa : for Dmytro : bad */ /* Dmytro : for butMap types implemented two cyles. Types of elements is checked in filters */ + // for( let s in srcMap ) + // { + // let m; + // for( m = 0 ; m < butMap.length ; m++ ) + // if( !propertyCondition( butMap[ m ], srcMap, s ) ) + // break; + // + // if( m === butMap.length ) + // dstMap[ s ] = srcMap[ s ]; + // } + // } + // else + // { + // for( let s in srcMap ) + // { + // if( propertyCondition( butMap, srcMap, s ) ) + // dstMap[ s ] = srcMap[ s ]; + // } + // } + // + // } + // + // return dstMap; +} + +// + +/** + * Returns new object with unique pairs key-value from {-srcMap-} screened by screen map {-butMap-}. + * + * from the first {-srcMap-} original object. + * Values for result object come from original object {-srcMap-} + * not from second or other one. + * If the first object has same key any other object has + * then this pair( key/value ) will not be included into result object. + * Otherwise pair( key/value ) from the first object goes into result object. + * + * @param{ objectLike } srcMap - original object. + * @param{ ...objectLike } arguments[] - one or more objects. + * Objects to return an object without repeating keys. + * + * @example + * _.mapBut_( null, { a : 7, b : 13, c : 3 }, { a : 7, b : 13 } ); + * // returns { c : 3 } + * + * Returns new object filled by unique keys + * @throws { Error } + * In debug mode it throws an error if any argument is not object like. + * @returns { object } Returns new object made by unique keys. + * @function mapBut + * @namespace Tools + */ + +function mapButOld( srcMap, butMap ) +{ + let result = Object.create( null ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( !_.primitive.is( srcMap ), 'Expects map {-srcMap-}' ); + + /* aaa : allow and cover vector */ /* Dmytro : implemented, covered */ + if( _.countable.is( butMap ) ) + { + let filterRoutines = [ filterWithVectorButMap, filterWithArrayLikeButMap ]; + let arrayLikeIs = _.argumentsArray.like( butMap ) ? 1 : 0; + for( let s in srcMap ) + { + let butKey = filterRoutines[ arrayLikeIs ]( s ); + if( butKey === undefined ) + result[ s ] = srcMap[ s ]; + } + + // /* aaa : for Dmytro : bad */ /* Dmytro : improved, used checks with types */ + // for( let s in srcMap ) + // { + // let m; + // for( m = 0 ; m < butMap.length ; m++ ) + // { + // /* aaa : for Dmytro : write GOOD coverage */ /* Dmytro : coverage extended */ + // if( _.primitive.is( butMap[ m ] ) ) + // { + // if( s === butMap[ m ] ) + // break; + // } + // else + // { + // if( s in butMap[ m ] ) + // break; + // } + // // + // // if( s === butMap[ m ] ) + // // break; + // // if( _.aux.is( butMap[ m ] ) ) + // // if( s in butMap[ m ] ) + // // break; + // } + // + // if( m === butMap.length ) + // result[ s ] = srcMap[ s ]; + // } + } + else if( !_.primitive.is( butMap ) ) + { + for( let s in srcMap ) + { + if( !( s in butMap ) ) + result[ s ] = srcMap[ s ]; + } + } + else + { + _.assert( 0, 'Expects object-like or long-like {-butMap-}' ); /* xxx */ + } + + return result; + + /* */ + + function filterWithVectorButMap( s ) + { + for( let but of butMap ) + { + if( _.primitive.is( but ) ) + { + if( s === but ) + return s; + } + else if( _.aux.is( but ) ) + { + if( s in but ) + return s; + } + else + { + _.assert( 0, 'Unexpected type of element' ); + } + } + } + + /* */ + + function filterWithArrayLikeButMap( s ) + { + for( let m = 0 ; m < butMap.length ; m++ ) + { + if( _.primitive.is( butMap[ m ] ) ) + { + if( s === butMap[ m ] ) + return s; + } + else if( _.aux.is( butMap[ m ] ) ) + { + if( s in butMap[ m ] ) + return s; + } + else + { + _.assert( 0, 'Unexpected type of element' ); + } + } + } +} + +// + +function mapBut_( dstMap, srcMap, butMap ) +{ + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + if( dstMap === null ) + dstMap = arguments[ 0 ] = arguments[ 0 ] || Object.create( null ); + + _.assert( arguments.length === 3, 'Not clear how to construct {-dstMap-}. Please, specify exactly 3 arguments' ); + // if( arguments.length === 2 ) + // { + // butMap = arguments[ 1 ]; + // srcMap = arguments[ 0 ]; + // } + + /* */ + + let o = + { + dstMap, + srcMap, + butMap, + }; + + o = _._mapBut_VerifyMapFields( o ); + + let mapsAreIdentical = o.dstMap === o.srcMap ? 1 : 0; + let butMapsIsCountable = _.countable.is( o.butMap ) ? 2 : 0; + let filterRoutines = + [ + filterNotIdenticalWithAuxScreenMap, + filterIdenticalWithAuxScreenMap, + filterNotIdenticalWithVectorScreenMap, + filterIdenticalWithVectorScreenMap + ]; + let key = mapsAreIdentical + butMapsIsCountable; + let filterRoutine = filterRoutines[ key ]; + let searchingRoutine; + if( butMapsIsCountable ) + searchingRoutine = _screenMapSearchingRoutineFunctor( o.butMap ); + + for( let key in o.srcMap ) + filterRoutine( key ); + + return o.dstMap; + + /* */ + + function filterNotIdenticalWithAuxScreenMap( key ) + { + if( !( key in o.butMap ) ) + o.dstMap[ key ] = o.srcMap[ key ]; + } + + /* */ + + function filterIdenticalWithAuxScreenMap( key ) + { + if( key in o.butMap ) + delete o.dstMap[ key ]; + } + + /* */ + + function filterNotIdenticalWithVectorScreenMap( key ) + { + let butKey = searchingRoutine( o.butMap, key ); + if( butKey !== undefined ) + return; + + o.dstMap[ key ] = o.srcMap[ key ]; + } + + /* */ + + function filterIdenticalWithVectorScreenMap( key ) + { + let butKey = searchingRoutine( o.butMap, key ); + if( butKey !== undefined ) + delete o.dstMap[ key ]; + } + + // let filter = _.props.conditionFrom( filterBut ); + // + // return _._mapBut_ + // ({ + // filter, + // dstMap, + // srcMap, + // butMap, + // }); + // + // /* */ + // + // /* qqq : for Dmytro : bad : not optimal */ + // function filterBut( butMap, srcMap, key ) + // { + // if( _.aux.is( butMap ) ) + // { + // if( !( key in butMap ) ) + // return key; + // } + // else if( _.primitive.is( butMap ) ) + // { + // if( key !== butMap ) + // return key; + // } + // } + // filterBut.identity = { propertyCondition : true, propertyTransformer : true }; + // + // _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + // _.assert( !_.primitive.is( dstMap ), 'Expects map like destination map {-dstMap-}' ); + // _.assert( !_.primitive.is( srcMap ) || _.longIs( srcMap ), 'Expects long or map {-srcMap-}' ); + // _.assert( !_.primitive.is( butMap ) || _.longIs( butMap ) || _.routineIs( butMap ), 'Expects object like {-butMap-}' ); + // + // if( dstMap === srcMap ) + // { + // + // /* aaa : allow and cover vector */ /* Dmytro : implemented, covered */ + // if( _.vector.is( butMap ) ) + // { + // /* aaa : for Dmytro : bad */ /* Dmytro : for butMap types implemented two cyles. Types of elements is checked in filters */ + // for( let s in srcMap ) + // { + // for( let m = 0 ; m < butMap.length ; m++ ) + // { + // /* aaa : for Dmytro : write GOOD coverage */ /* Dmytro : coverage extended */ + // if( _.aux.is( butMap[ m ] ) ) + // { + // if( s in butMap[ m ] ) + // delete dstMap[ s ]; + // } + // else + // { + // if( s === butMap[ m ] ) + // delete dstMap[ s ]; + // } + // } + // } + // } + // else + // { + // for( let s in srcMap ) + // { + // if( s in butMap ) + // delete dstMap[ s ]; + // } + // } + // + // } + // else + // { + // + // /* aaa : allow and cover vector */ /* Dmytro : implemented, covered */ + // if( _.vector.is( butMap ) ) + // { + // /* aaa : for Dmytro : bad */ /* Dmytro : for butMap types implemented two cyles. Types of elements is checked in filters */ + // for( let s in srcMap ) + // { + // let m; + // for( m = 0 ; m < butMap.length ; m++ ) + // { + // /* aaa : for Dmytro : was bad implementation. cover */ /* Dmytro : improved, implemented, covered */ + // if( _.primitiveIs( butMap[ m ] ) ) + // { + // if( s === butMap[ m ] ) + // break; + // } + // else + // { + // if( s in butMap[ m ] ) + // break; + // } + // } + // + // if( m === butMap.length ) + // dstMap[ s ] = srcMap[ s ]; + // } + // } + // else + // { + // for( let s in srcMap ) + // { + // if( !( s in butMap ) ) + // dstMap[ s ] = srcMap[ s ]; + // } + // } + // + // } + // + // return dstMap; +} + +// + +function _mapBut_VerifyMapFields( o ) +{ + _.assert( arguments.length === 1, 'Expects single options map {-o-}' ); + _.assert( !_.primitive.is( o.dstMap ), 'Expects non primitive {-o.dstMap-}' ); + _.assert( !_.primitive.is( o.srcMap ), 'Expects non primitive {-o.srcMap-}' ); + _.assert( !_.primitive.is( o.butMap ), 'Expects object like {-o.butMap-}' ); + _.assert( !_.vector.is( o.dstMap ), 'Expects aux like {-o.dstMap-}' ); + return o; +} + +// + +function _mapBut_FilterFunctor( o ) +{ + let mapsAreIdentical = o.dstMap === o.srcMap ? 1 : 0; + let butMapIsCountable = _.countable.is( o.butMap ) ? 2 : 0; + if( _.argumentsArray.like( o.butMap ) ) + butMapIsCountable += 2; + let filterRoutines = + [ + filterNotIdentical, + filterIdentical, + filterNotIdenticalWithVectorButMap, + filterIdenticalWithVectorButMap, + filterNotIdenticalWithArrayButMap, + filterIdenticalWithArrayButMap, + ]; + + return filterRoutines[ mapsAreIdentical + butMapIsCountable ]; + + /* */ + + function filterNotIdentical( key ) + { + if( o.filter( o.butMap, o.srcMap, key ) ) + o.dstMap[ key ] = o.srcMap[ key ]; + } + + /* */ + + function filterIdentical( key ) + { + if( !o.filter( o.butMap, o.srcMap, key ) ) + delete o.dstMap[ key ]; + } + + /* */ + + function filterNotIdenticalWithArrayButMap( key ) + { + for( let m = 0 ; m < o.butMap.length ; m++ ) + if( _.primitive.is( o.butMap[ m ] ) || _.aux.is( o.butMap[ m ] ) ) + { + if( !o.filter( o.butMap[ m ], o.srcMap, key ) ) + return; + } + o.dstMap[ key ] = o.srcMap[ key ]; + } + + /* */ + + function filterNotIdenticalWithVectorButMap( key ) + { + for( let but of o.butMap ) + if( _.primitive.is( but ) || _.aux.is( but ) ) + { + if( !o.filter( but, o.srcMap, key ) ) + return; + } + o.dstMap[ key ] = o.srcMap[ key ]; + } + + /* */ + + function filterIdenticalWithArrayButMap( key ) + { + for( let m = 0 ; m < o.butMap.length ; m++ ) + if( _.primitive.is( o.butMap[ m ] ) ) + { + if( !o.filter( o.butMap[ m ], o.srcMap, key ) ) + delete o.dstMap[ key ]; + } + } + + /* */ + + function filterIdenticalWithVectorButMap( key ) + { + for( let but of o.butMap ) + if( _.primitive.is( but ) ) + { + if( !o.filter( but, o.srcMap, key ) ) + delete o.dstMap[ key ]; + } + } +} +// +// // +// +// function _mapBut_( o ) +// { +// _.assert( arguments.length === 1, 'Expects single options map {-o-}' ); +// _.assert( _.routineIs( o.filter ) && o.filter.length === 3, 'Expects filter {-o.filter-}' ); +// _.assert( _.props.conditionIs( o.filter ), 'Expects PropertyFilter {-o.filter-}' ); +// _.assert( !_.primitive.is( o.dstMap ), 'Expects non primitive {-o.dstMap-}' ); +// _.assert( !_.primitive.is( o.srcMap ), 'Expects non primitive {-o.srcMap-}' ); +// _.assert( !_.primitive.is( o.butMap ), 'Expects object like {-o.butMap-}' ); +// _.assert( !_.vector.is( o.dstMap ), 'Expects aux like {-o.dstMap-}' ); +// // _.assert( !_.primitive.is( o.butMap ) || _.vector.is( o.butMap ) || _.routineIs( o.butMap ), 'Expects object like {-o.butMap-}' ); +// +// let mapsAreIdentical = o.dstMap === o.srcMap ? 1 : 0; +// let butMapIsVector = _.vector.is( o.butMap ) ? 2 : 0; +// let filterRoutines = +// [ +// filterNotIdentical, +// filterIdentical, +// filterNotIdenticalWithVectorButMap, +// filterIdenticalWithVectorButMap +// ]; +// let key = mapsAreIdentical + butMapIsVector; +// +// for( let s in o.srcMap ) +// filterRoutines[ key ]( s ); +// +// return o.dstMap; +// +// /* */ +// +// function filterNotIdentical( key ) +// { +// if( o.filter( o.butMap, o.srcMap, key ) ) +// o.dstMap[ key ] = o.srcMap[ key ]; +// } +// +// /* */ +// +// function filterIdentical( key ) +// { +// if( !o.filter( o.butMap, o.srcMap, key ) ) +// delete o.dstMap[ key ]; +// } +// +// /* */ +// +// function filterNotIdenticalWithVectorButMap( key ) +// { +// /* aaa : for Dmytro : bad */ /* Dmytro : for butMap types implemented two cyles. Types of elements is checked in filters */ +// if( _.argumentsArray.like( o.butMap ) ) +// { +// for( let m = 0 ; m < o.butMap.length ; m++ ) +// if( _.primitive.is( o.butMap[ m ] ) || _.aux.is( o.butMap[ m ] ) ) +// { +// if( !o.filter( o.butMap[ m ], o.srcMap, key ) ) +// return; +// } +// // if( _.primitive.is( o.butMap[ m ] ) ) +// // { +// // if( !o.filter( o.butMap[ m ], o.srcMap, key ) ) +// // return; +// // } +// o.dstMap[ key ] = o.srcMap[ key ]; +// } +// else +// { +// for( let but of o.butMap ) +// if( _.primitive.is( but ) || _.aux.is( but ) ) +// { +// if( !o.filter( but, o.srcMap, key ) ) +// return; +// } +// // if( _.primitive.is( but ) ) +// // { +// // if( !o.filter( but, o.srcMap, key ) ) +// // return; +// // } +// o.dstMap[ key ] = o.srcMap[ key ]; +// } +// } +// +// /* */ +// +// function filterIdenticalWithVectorButMap( key ) +// { +// if( _.argumentsArray.like( o.butMap ) ) +// { +// for( let m = 0 ; m < o.butMap.length ; m++ ) +// if( _.primitive.is( o.butMap[ m ] ) ) +// { +// if( !o.filter( o.butMap[ m ], o.srcMap, key ) ) +// delete o.dstMap[ key ]; +// } +// } +// else +// { +// for( let but of o.butMap ) +// if( _.primitive.is( but ) ) +// { +// if( !o.filter( but, o.srcMap, key ) ) +// delete o.dstMap[ key ]; +// } +// } +// } +// +// // if( o.dstMap === o.srcMap ) +// // { +// // +// // /* aaa : allow and cover vector */ /* Dmytro : allowed, covered */ +// // if( _.vector.is( o.butMap ) ) +// // { +// // for( let s in o.srcMap ) +// // { +// // for( let m = 0 ; m < o.butMap.length ; m++ ) +// // { +// // if( !o.filter( o.butMap[ m ], o.srcMap, s ) ) +// // delete o.dstMap[ s ]; +// // } +// // } +// // } +// // else +// // { +// // for( let s in o.srcMap ) +// // { +// // if( !o.filter( o.butMap, o.srcMap, s ) ) +// // delete o.dstMap[ s ]; +// // } +// // } +// // +// // } +// // else +// // { +// // +// // /* aaa : allow and cover vector */ /* Dmytro : implemented, covered */ +// // if( _.vector.is( o.butMap ) ) +// // { +// // /* aaa : for Dmytro : bad */ /* Dmytro : for butMap types implemented two cyles. Types of elements is checked in filters */ +// // for( let s in o.srcMap ) +// // { +// // let m; +// // for( m = 0 ; m < o.butMap.length ; m++ ) +// // if( !o.filter( o.butMap[ m ], o.srcMap, s ) ) +// // break; +// // +// // if( m === o.butMap.length ) +// // o.dstMap[ s ] = o.srcMap[ s ]; +// // } +// // } +// // else +// // { +// // for( let s in o.srcMap ) +// // { +// // if( o.filter( o.butMap, o.srcMap, s ) ) +// // o.dstMap[ s ] = o.srcMap[ s ]; +// // } +// // } +// // +// // } +// // +// // return o.dstMap; +// } + +// + +function mapDelete( dstMap, ins ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( !_.primitive.is( dstMap ) ); + if( ins === undefined ) + return _.mapEmpty( dstMap ); + return _.mapBut_( dstMap, dstMap, ins ); +} + +// + +function mapEmpty( dstMap ) +{ + + _.assert( arguments.length === 1 ); + _.assert( !_.primitive.is( dstMap ) ); + + for( let i in dstMap ) + { + delete dstMap[ i ]; + } + + return dstMap; +} + +// + +/** + * Returns new object with unique keys. + * + * Takes any number of objects. + * Returns new object filled by unique keys + * from the first {-srcMap-} original object. + * Values for result object come from original object {-srcMap-} + * not from second or other one. + * If the first object has same key any other object has + * then this pair( key/value ) will not be included into result object. + * Otherwise pair( key/value ) from the first object goes into result object. + * + * @param{ objectLike } srcMap - original object. + * @param{ ...objectLike } arguments[] - one or more objects. + * Objects to return an object without repeating keys. + * + * @example + * _.mapButIgnoringUndefines( { a : 7, b : 13, c : 3 }, { a : 7, b : 13 } ); + * // returns { c : 3 } + * + * @throws { Error } + * In debug mode it throws an error if any argument is not object like. + * @returns { object } Returns new object made by unique keys. + * @function mapButIgnoringUndefines + * @namespace Tools + */ + +// function mapButIgnoringUndefines( srcMap, butMap ) +// { +// let result = Object.create( null ); +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// +// return _.mapButConditional_( null, _.props.condition.dstUndefinedSrcNotUndefined(), srcMap, butMap ); +// } + +// + +function mapButIgnoringUndefines_( dstMap, srcMap, butMap ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + return _.mapButConditional_( _.props.condition.dstUndefinedSrcNotUndefined(), ... arguments ); + +} + +// + +/** + * The mapOnlyOwnBut() returns new object with unique own keys. + * + * Takes any number of objects. + * Returns new object filled by unique own keys + * from the first {-srcMap-} original object. + * Values for (result) object come from original object {-srcMap-} + * not from second or other one. + * If {-srcMap-} does not have own properties it skips rest of code and checks another properties. + * If the first object has same key any other object has + * then this pair( key/value ) will not be included into result object. + * Otherwise pair( key/value ) from the first object goes into result object. + * + * @param { objectLike } srcMap - The original object. + * @param { ...objectLike } arguments[] - One or more objects. + * + * @example + * _.mapBut_( null, { a : 7, 'toString' : 5 }, { b : 33, c : 77 } ); + * // returns { a : 7 } + * + * @returns { object } Returns new (result) object with unique own keys. + * @function mapOnlyOwnBut + * @throws { Error } Will throw an Error if {-srcMap-} is not an object. + * @namespace Tools + */ + +function mapOnlyOwnButOld( srcMap, butMap ) +{ + let result = Object.create( null ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + return _.mapButConditionalOld( _.props.condition.dstNotHasSrcOwn(), srcMap, butMap ); +} + +// + +function mapOnlyOwnBut_( dstMap, srcMap, butMap ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + return _.mapButConditional_( _.props.condition.dstNotHasSrcOwn(), ... arguments ); +} + +// // +// +// /** +// * @typedef screenMaps +// * @property { objectLike } screenMaps.screenMap - The first object. +// * @property { ...objectLike } srcMap.arguments[1, ...] - +// * The pseudo array (arguments[]) from the first [1] index to the end. +// * @property { object } dstMap - The empty object. +// * @namespace Tools +// */ +// +// /** +// * The mapOnly() returns an object filled by unique [ key, value ] +// * from others objects. +// * +// * It takes number of objects, creates a new object by three properties +// * and calls the _mapOnly( {} ) with created object. +// * +// * @see {@link wTools._mapOnly} - See for more information. +// * +// * @param { objectLike } screenMap - The first object. +// * @param { ...objectLike } arguments[] - One or more objects. +// * +// * @example +// * _.mapOnly_( null, { a : 13, b : 77, c : 3, d : 'name' }, { d : 'name', c : 33, a : 'abc' } ); +// * // returns { a : "abc", c : 33, d : "name" }; +// * +// * @returns { Object } Returns the object filled by unique [ key, value ] +// * from others objects. +// * @function mapOnly +// * @throws { Error } Will throw an Error if (arguments.length < 2) or (arguments.length !== 2). +// * @namespace Tools +// */ +// +// function mapOnlyOld( srcMaps, screenMaps ) +// { +// if( arguments.length === 1 ) +// return _.mapsExtend( null, srcMaps ); +// +// _.assert( arguments.length === 2, 'Expects single or two arguments' ); +// +// return _._mapOnly +// ({ +// srcMaps, +// screenMaps, +// dstMap : Object.create( null ), +// }); +// } + +// + +function mapOnly_( dstMap, srcMaps, screenMaps ) +{ + + + if( arguments.length === 1 ) + return _.mapsExtend( null, dstMap ); + + _.assert( arguments.length === 3, 'Not clear how to construct {-dstMap-}. Please, specify exactly 3 arguments' ); + + // else if( arguments.length === 2 ) + // { + // + // // return _.mapOnlyOld( srcMaps, screenMaps ); + // + // // aaa : for Dmytro : bad! /* Dmytro : this condition allow modify srcMaps if passed only 2 arguments */ + // if( dstMap === null ) + // return Object.create( null ); + // screenMaps = arguments[ 1 ]; + // srcMaps = arguments[ 0 ]; + // } + // else if( arguments.length !== 3 ) + // { + // _.assert( 0, 'Expects at least one argument and no more then three arguments' ); + // } + + let o = _._mapOnly_VerifyMapFields + ({ + srcMaps, + screenMaps, + dstMap : dstMap || Object.create( null ), + }); + + let mapsAreIdentical = o.dstMap === o.srcMaps ? 1 : 0; + let screenMapsIsCountable = _.countable.is( o.screenMaps ) ? 2 : 0; + let filterRoutines = + [ + filterNotIdenticalWithAuxScreenMap, + filterIdenticalWithAuxScreenMap, + filterNotIdenticalWithVectorScreenMap, + filterIdenticalWithVectorScreenMap + ]; + let key = mapsAreIdentical + screenMapsIsCountable; + let filterRoutine = filterRoutines[ key ]; + let searchingRoutine; + if( screenMapsIsCountable ) + searchingRoutine = _screenMapSearchingRoutineFunctor( o.screenMaps ); + + if( _.countable.is( o.srcMaps ) ) + { + for( let srcMap of o.srcMaps ) + { + _.assert( !_.primitive.is( srcMap ), 'Expects no primitive in {-o.srcMaps-}' ); + filterRoutine( srcMap ); + } + } + else + { + filterRoutine( o.srcMaps ); + } + + return o.dstMap; + + /* */ + + function filterNotIdenticalWithVectorScreenMap( srcMap ) + { + for( let key in srcMap ) + { + let screenKey = searchingRoutine( o.screenMaps, key ); + if( screenKey !== undefined ) + o.dstMap[ screenKey ] = srcMap[ screenKey ]; + } + } + + /* */ + + function filterIdenticalWithVectorScreenMap( srcMap ) + { + for( let key in srcMap ) + { + let screenKey = searchingRoutine( o.screenMaps, key ); + if( screenKey === undefined ) + delete srcMap[ key ]; + } + } + + /* */ + + function filterNotIdenticalWithAuxScreenMap( srcMap ) + { + for( let key in o.screenMaps ) + { + if( o.screenMaps[ key ] === undefined ) + continue; + + if( key in srcMap ) + o.dstMap[ key ] = srcMap[ key ]; + } + } + + + /* */ + + function filterIdenticalWithAuxScreenMap( srcMap ) + { + for( let key in srcMap ) + { + if( !( key in o.screenMaps ) ) + delete srcMap[ key ]; + } + } + + // return _.mapOnlyOld( srcMaps, screenMaps ); + // aaa : for Dmytro : bad! /* Dmytro : improved, optimized */ + + // return _._mapOnly_ + // ({ + // srcMaps, + // screenMaps, + // dstMap, + // }); + +} + +// // +// +// function mapOnlyOwn( srcMaps, screenMaps ) +// { +// +// if( arguments.length === 1 ) +// return _.mapsExtendConditional( _.props.mapper.srcOwn(), null, srcMaps ); +// +// _.assert( arguments.length === 1 || arguments.length === 2, 'Expects single or two arguments' ); +// +// return _._mapOnly +// ({ +// filter : _.props.mapper.srcOwn(), +// srcMaps, +// screenMaps, +// dstMap : Object.create( null ), +// }); +// +// } + +// + +function mapOnlyOwn_( dstMap, srcMaps, screenMaps ) +{ + + if( arguments.length === 1 ) + return _.mapsExtendConditional( _.props.mapper.srcOwn(), null, _.array.as( dstMap ) ); + + _.assert( arguments.length === 3, 'Not clear how to construct {-dstMap-}. Please, specify exactly 3 arguments' ); + + // else if( arguments.length === 2 ) + // { + // if( dstMap === null ) + // return Object.create( null ); + // + // screenMaps = arguments[ 1 ]; + // srcMaps = arguments[ 0 ]; + // } + // else if( arguments.length !== 3 ) + // { + // _.assert( 0, 'Expects at least one argument and no more then three arguments' ); + // } + + let o = _._mapOnly_VerifyMapFields + ({ + filter : _.props.mapper.srcOwn(), + srcMaps, + screenMaps, + dstMap : dstMap || Object.create( null ), + }); + + _.assert( _.props.mapperIs( o.filter ), 'Expects PropertyFilter {-o.filter-}' ); + + let filterRoutine = _._mapOnly_FilterFunctor( o ); + + if( _.countable.is( o.srcMaps ) ) + { + for( let srcMap of o.srcMaps ) + { + _.assert( !_.primitive.is( srcMap ), 'Expects no primitive in {-o.srcMaps-}' ); + filterRoutine( srcMap ); + } + } + else + { + filterRoutine( o.srcMaps ); + } + + return o.dstMap; + + // return _._mapOnly_ + // ({ + // filter : _.props.mapper.srcOwn(), + // srcMaps, + // screenMaps, + // dstMap, + // }); + +} + +// + +// function mapOnlyComplementing( srcMaps, screenMaps ) +// { +// +// _.assert( arguments.length === 1 || arguments.length === 2, 'Expects single or two arguments' ); +// +// return _._mapOnly +// ({ +// filter : _.props.mapper.dstNotOwnOrUndefinedAssigning(), +// srcMaps, +// screenMaps, +// dstMap : Object.create( null ), +// }); +// +// } + +// + +function mapOnlyComplementing_( dstMap, srcMaps, screenMaps ) +{ + + _.assert( arguments.length === 3, 'Not clear how to construct {-dstMap-}. Please, specify exactly 3 arguments' ); + + // if( arguments.length === 2 ) + // { + // if( dstMap === null ) + // return Object.create( null ); + // + // screenMaps = arguments[ 1 ]; + // srcMaps = arguments[ 0 ]; + // } + // else if( arguments.length !== 3 ) + // { + // _.assert( 0, 'Expects two or three arguments' ); + // } + + let o = _._mapOnly_VerifyMapFields + ({ + filter : _.props.mapper.dstNotOwnOrUndefinedAssigning(), + srcMaps, + screenMaps, + dstMap : dstMap || Object.create( null ), + }); + + _.assert( _.props.mapperIs( o.filter ), 'Expects PropertyFilter {-o.filter-}' ); + + let filterRoutine = _._mapOnly_FilterFunctor( o ); + + if( _.countable.is( o.srcMaps ) ) + { + for( let srcMap of o.srcMaps ) + { + _.assert( !_.primitive.is( srcMap ), 'Expects no primitive in {-o.srcMaps-}' ); + filterRoutine( srcMap ); + } + } + else + { + filterRoutine( o.srcMaps ); + } + + return o.dstMap; + + // return _._mapOnly_ + // ({ + // filter : _.props.mapper.dstNotOwnOrUndefinedAssigning(), + // srcMaps, + // screenMaps, + // dstMap, + // }); + +} + +// // +// +// /** +// * @callback options.filter +// * @param { objectLike } dstMap - An empty object. +// * @param { objectLike } srcMaps - The target object. +// * @param { string } - The key of the (screenMap). +// */ +// +// /** +// * The _mapOnly() returns an object filled by unique [ key, value] +// * from others objects. +// * +// * The _mapOnly() checks whether there are the keys of +// * the (screenMap) in the list of (srcMaps). +// * If true, it calls a provided callback function(filter) +// * and adds to the (dstMap) all the [ key, value ] +// * for which callback function returns true. +// * +// * @param { function } [options.filter = filter.bypass()] options.filter - The callback function. +// * @param { objectLike } options.srcMaps - The target object. +// * @param { objectLike } options.screenMaps - The source object. +// * @param { Object } [options.dstMap = Object.create( null )] options.dstMap - The empty object. +// * +// * @example +// * let options = Object.create( null ); +// * options.dstMap = Object.create( null ); +// * options.screenMaps = { 'a' : 13, 'b' : 77, 'c' : 3, 'name' : 'Mikle' }; +// * options.srcMaps = { 'a' : 33, 'd' : 'name', 'name' : 'Mikle', 'c' : 33 }; +// * _mapOnly( options ); +// * // returns { a : 33, c : 33, name : "Mikle" }; +// * +// * @example +// * let options = Object.create( null ); +// * options.dstMap = Object.create( null ); +// * options.screenMaps = { a : 13, b : 77, c : 3, d : 'name' }; +// * options.srcMaps = { d : 'name', c : 33, a : 'abc' }; +// * _mapOnly( options ); +// * // returns { a : "abc", c : 33, d : "name" }; +// * +// * @returns { Object } Returns an object filled by unique [ key, value ] +// * from others objects. +// * @function _mapOnly +// * @throws { Error } Will throw an Error if (options.dstMap or screenMap) are not objects, +// * or if (srcMaps) is not an array +// * @namespace Tools +// */ +// +// /* xxx : qqq : for Dmytro : comment out */ /* aaa : Dmytro : done */ +// function _mapOnly( o ) +// { +// let self = this; +// +// o.dstMap = o.dstMap || Object.create( null ); +// o.filter = o.filter || _.props.mapper.bypass(); +// +// _.assert( arguments.length === 1, 'Expects single options map {-o-}' ); +// _.assert( _.props.mapperIs( o.filter ), 'Expects PropertyFilter {-o.filter-}' ); +// _.assert( !_.primitive.is( o.dstMap ), 'Expects non primitive {-o.dstMap-}' ); +// _.assert( !_.primitive.is( o.screenMaps ), 'Expects non primitive {-o.screenMaps-}' ); +// _.assert( !_.primitive.is( o.srcMaps ), 'Expects non primitive {-srcMap-}' ); +// _.map.assertHasOnly( o, _mapOnly.defaults ); +// +// /* aaa : allow and cover vector */ /* Dmytro : implemented, covered */ +// if( _.countable.is( o.srcMaps ) ) +// for( let srcMap of o.srcMaps ) +// { +// _.assert( !_.primitive.is( srcMap ), 'Expects non primitive {-srcMap-}' ); +// +// if( _.countable.is( o.screenMaps ) ) +// filterSrcMapWithVectorScreenMap( srcMap ); +// else +// filterSrcMap( srcMap ); +// } +// else +// { +// if( _.countable.is( o.screenMaps ) ) +// filterSrcMapWithVectorScreenMap( o.srcMaps ); +// else +// filterSrcMap( o.srcMaps ); +// } +// +// return o.dstMap; +// +// /* */ +// +// function filterSrcMapWithVectorScreenMap( srcMap ) +// { +// for( let key in srcMap ) +// { +// let screenKey = screenKeySearch( key ); +// if( screenKey ) +// o.filter.call( self, o.dstMap, srcMap, screenKey ); +// } +// } +// +// /* */ +// +// function screenKeySearch( key ) +// { +// if( _.argumentsArray.like( o.screenMaps ) ) +// { +// for( let m = 0 ; m < o.screenMaps.length ; m++ ) +// if( _.primitive.is( o.screenMaps[ m ] ) ) +// { +// if( o.screenMaps[ m ] === key ) +// return key; +// } +// } +// else +// { +// for( let m of o.screenMaps ) +// if( _.primitive.is( m ) ) +// { +// if( m === key ) +// return key; +// } +// } +// +// // let m; +// // if( _.argumentsArray.like( o.screenMaps ) ) +// // { +// // for( m = 0 ; m < o.screenMaps.length ; m++ ) +// // if( _.vector.is( o.screenMaps[ m ] ) && key in o.screenMaps[ m ] ) +// // return key; +// // else if( _.aux.is( o.screenMaps[ m ] ) && key in o.screenMaps[ m ] ) +// // return key; +// // else if( _.primitive.is( o.screenMaps[ m ] ) && o.screenMaps[ m ] === key ) +// // return key; +// // else if( key === String( m ) ) +// // return key; +// // } +// // else +// // { +// // for( m of o.screenMaps ) +// // if( _.vector.is( m ) && key in m ) +// // return key; +// // else if( _.aux.is( m ) && key in m ) +// // return key; +// // else if( _.primitive.is( m ) && m === key ) +// // return key; +// // } +// } +// +// /* */ +// +// function filterSrcMap( srcMap ) +// { +// for( let key in o.screenMaps ) +// { +// if( o.screenMaps[ key ] === undefined ) +// continue; +// +// if( key in srcMap ) +// o.filter.call( this, o.dstMap, srcMap, key ); +// } +// } +// +// // let dstMap = o.dstMap || Object.create( null ); +// // let screenMap = o.screenMaps; +// // let srcMaps = o.srcMaps; +// // +// // /* aaa : for Dmytro : not optimal */ /* Dmytro : optimized */ +// // if( !_.vector.is( srcMaps ) ) +// // srcMaps = [ srcMaps ]; +// // +// // if( !o.filter ) +// // o.filter = _.props.mapper.bypass(); +// // +// // if( Config.debug ) +// // { +// // +// // // _.assert( o.filter.functionFamily === 'PropertyMapper' ); +// // _.assert( _.props.mapperIs( o.filter ), 'Expects PropertyFilter {-propertyCondition-}' ); +// // _.assert( arguments.length === 1, 'Expects single argument' ); +// // _.assert( !_.primitive.is( dstMap ), 'Expects object-like {-dstMap-}' ); +// // _.assert( !_.primitive.is( screenMap ), 'Expects not primitive {-screenMap-}' ); +// // _.assert( _.vector.is( srcMaps ), 'Expects array {-srcMaps-}' ); +// // _.map.assertHasOnly( o, _mapOnly.defaults ); +// // +// // for( let s = srcMaps.length - 1 ; s >= 0 ; s-- ) +// // _.assert( !_.primitive.is( srcMaps[ s ] ), 'Expects {-srcMaps-}' ); +// // +// // } +// // +// // if( _.longIs( screenMap ) ) +// // { +// // for( let k in screenMap ) /* aaa : for Dmytro : bad */ /* Dmytro : improved, used conditions for types */ +// // { +// // +// // if( screenMap[ k ] === undefined ) +// // continue; +// // +// // let s; +// // for( s = srcMaps.length-1 ; s >= 0 ; s-- ) +// // { +// // if( !_.aux.is( screenMap[ k ] ) && screenMap[ k ] in srcMaps[ s ] ) +// // // k = screenMap[ k ]; /* aaa : ? */ /* Dmytro : key definition */ +// // break; +// // if( k in srcMaps[ s ] ) +// // break; +// // } +// // +// // if( s === -1 ) +// // continue; +// // +// // o.filter.call( this, dstMap, srcMaps[ s ], k ); +// // +// // } +// // } +// // else +// // { +// // for( let k in screenMap ) +// // { +// // if( screenMap[ k ] === undefined ) +// // continue; +// // +// // for( let s in srcMaps ) +// // if( k in srcMaps[ s ] ) +// // o.filter.call( this, dstMap, srcMaps[ s ], k ); +// // } +// // } +// // +// // return dstMap; +// } +// +// _mapOnly.defaults = +// { +// dstMap : null, +// srcMaps : null, +// screenMaps : null, +// filter : null, +// } + +// + +function _mapOnly_VerifyMapFields( o ) +{ + _.assert( arguments.length === 1, 'Expects single options map {-o-}' ); + _.assert( !_.primitive.is( o.dstMap ), 'Expects non primitive {-o.dstMap-}' ); + _.assert( !_.primitive.is( o.screenMaps ), 'Expects non primitive {-o.screenMaps-}' ); + _.assert( !_.primitive.is( o.srcMaps ), 'Expects non primitive {-o.srcMaps-}' ); + _.map.assertHasOnly( o, _mapOnly_VerifyMapFields.defaults ); + _.assert( !_.vector.is( o.dstMap ), 'Expects not a vector {-o.dstMap-}' ); + + return o; +} + +_mapOnly_VerifyMapFields.defaults = +{ + dstMap : null, + srcMaps : null, + screenMaps : null, + filter : null, +} + +// + +function _mapOnly_FilterFunctor( o ) +{ + let self = this; + let mapsAreIdentical = o.dstMap === o.srcMaps ? 1 : 0; + let screenMapsIsVector = _.vector.is( o.screenMaps ) ? 2 : 0; + let filterRoutines = + [ + filterNotIdenticalWithAuxScreenMap, + filterIdenticalWithAuxScreenMap, + filterNotIdenticalWithVectorScreenMap, + filterIdenticalWithVectorScreenMap + ]; + let key = mapsAreIdentical + screenMapsIsVector; + let searchingRoutine; + if( screenMapsIsVector ) + searchingRoutine = _screenMapSearchingRoutineFunctor( o.screenMaps ); + + return filterRoutines[ key ]; + + /* */ + + function filterNotIdenticalWithVectorScreenMap( srcMap ) + { + for( let key in srcMap ) + { + let screenKey = searchingRoutine( o.screenMaps, key ); + if( screenKey !== undefined ) + o.filter.call( self, o.dstMap, srcMap, key ); + } + } + + /* */ + + function filterIdenticalWithVectorScreenMap( srcMap ) + { + for( let key in srcMap ) + { + let screenKey = searchingRoutine( o.screenMaps, key ); + if( screenKey === undefined ) + delete srcMap[ key ]; + else + o.filter.call( self, o.dstMap, srcMap, key ); + } + } + + /* */ + + function filterNotIdenticalWithAuxScreenMap( srcMap ) + { + for( let key in o.screenMaps ) + { + if( o.screenMaps[ key ] === undefined ) + continue; + + if( key in srcMap ) + o.filter.call( self, o.dstMap, srcMap, key ); + } + } + + /* */ + + function filterIdenticalWithAuxScreenMap( srcMap ) + { + for( let key in srcMap ) + { + if( !( key in o.screenMaps ) ) + delete srcMap[ key ]; + else + o.filter.call( self, o.dstMap, srcMap, key ); + } + } +} + +/* */ + +function _screenMapSearchingRoutineFunctor( screenMaps ) +{ + let screenMapsIsArray = _.argumentsArray.like( screenMaps ) ? 1 : 0; + let searchingRoutines = + [ + searchKeyInVectorScreenMapWithPrimitives, + searchKeyInArrayScreenMapWithPrimitives, + searchKeyInVectorScreenMapWithMaps, + searchKeyInArrayScreenMapWithMaps, + ]; + + let element; + if( screenMapsIsArray ) + { + element = screenMaps[ 0 ]; + } + else + { + for( let el of screenMaps ) + { + element = el; + break; + } + } + + let screenMapsElementIsAux = _.aux.is( element ) ? 2 : 0; + return searchingRoutines[ screenMapsIsArray + screenMapsElementIsAux ]; + + /* */ + + function searchKeyInArrayScreenMapWithPrimitives( screenMaps, key ) + { + for( let m = 0 ; m < screenMaps.length ; m++ ) + if( screenMaps[ m ] === key ) + return key; + } + + function searchKeyInArrayScreenMapWithMaps( screenMaps, key ) + { + for( let m = 0 ; m < screenMaps.length ; m++ ) + if( key in screenMaps[ m ] ) + return key; + } + + /* */ + + function searchKeyInVectorScreenMapWithPrimitives( screenMaps, key ) + { + for( let m of screenMaps ) + if( m === key ) + return key; + } + + function searchKeyInVectorScreenMapWithMaps( screenMaps, key ) + { + for( let m of screenMaps ) + if( key in m ) + return key; + } +} + +/* */ + +// function _mapOnly_SearchKeyInVectorScreenMap( screenMaps, key ) +// { +// if( _.argumentsArray.like( screenMaps ) ) +// { +// for( let m = 0 ; m < screenMaps.length ; m++ ) +// if( _.primitive.is( screenMaps[ m ] ) ) +// { +// if( screenMaps[ m ] === key ) +// return key; +// } +// else if( _.aux.is( screenMaps[ m ] ) ) +// { +// if( key in screenMaps[ m ] ) +// return key; +// } +// } +// else +// { +// for( let m of screenMaps ) +// if( _.primitive.is( m ) ) +// { +// if( m === key ) +// return key; +// } +// else if( _.aux.is( m ) ) +// { +// if( key in m ) +// return key; +// } +// } +// } +// +// // +// +// function _mapOnly_( o ) +// { +// let self = this; +// o.dstMap = o.dstMap || Object.create( null ); +// o.filter = o.filter || _.props.mapper.bypass(); +// +// _.assert( arguments.length === 1, 'Expects single options map {-o-}' ); +// _.assert( _.props.mapperIs( o.filter ), 'Expects PropertyFilter {-o.filter-}' ); +// _.assert( !_.primitive.is( o.dstMap ), 'Expects non primitive {-o.dstMap-}' ); +// _.assert( !_.primitive.is( o.screenMaps ), 'Expects non primitive {-o.screenMaps-}' ); +// _.assert( !_.primitive.is( o.srcMaps ), 'Expects non primitive {-o.srcMaps-}' ); +// _.map.assertHasOnly( o, _mapOnly_.defaults ); +// _.assert( !_.vector.is( o.dstMap ), 'Expects not a vector {-o.dstMap-}' ); +// +// /* aaa : allow and cover vector */ /* Dmytro : allowed, covered. I think, an optimization for array like vectors has no sense. Otherwise, we need to add single branch with for cycle */ +// +// let mapsAreIdentical = o.dstMap === o.srcMaps ? 1 : 0; +// let screenMapsIsVector = _.vector.is( o.screenMaps ) ? 2 : 0; +// let filterRoutines = [ filterNotIdentical, filterIdentical, filterWithVectorScreenMap, filterWithVectorScreenMap ]; +// let filterCallbacks = [ filterNotIdenticalMaps, filterIdenticalMaps ]; +// let key = mapsAreIdentical + screenMapsIsVector; +// +// if( _.vector.is( o.srcMaps ) ) +// { +// for( let srcMap of o.srcMaps ) +// { +// _.assert( !_.primitive.is( srcMap ), 'Expects no primitive in {-o.srcMaps-}' ); +// filterRoutines[ key ]( srcMap, filterCallbacks[ mapsAreIdentical ] ); +// } +// } +// else +// { +// filterRoutines[ key ]( o.srcMaps, filterCallbacks[ mapsAreIdentical ] ); +// } +// +// return o.dstMap; +// +// /* */ +// +// function filterNotIdenticalMaps( src, key, foundKey ) +// { +// if( foundKey !== undefined ) +// o.filter.call( self, o.dstMap, src, key ); +// } +// +// /* */ +// +// function filterIdenticalMaps( src, key, foundKey ) +// { +// if( foundKey === undefined ) +// delete src[ key ]; +// else +// o.filter.call( self, o.dstMap, src, key ); +// } +// +// /* */ +// +// function filterWithVectorScreenMap( srcMap, filterCallback ) +// { +// for( let key in srcMap ) +// { +// let screenKey = screenMapSearch( key ); +// filterCallback( srcMap, key, screenKey ); +// } +// } +// +// /* */ +// +// function screenMapSearch( key ) +// { +// if( _.argumentsArray.like( o.screenMaps ) ) +// { +// for( let m = 0 ; m < o.screenMaps.length ; m++ ) +// if( _.primitive.is( o.screenMaps[ m ] ) ) +// { +// if( o.screenMaps[ m ] === key ) +// return key; +// } +// else if( _.aux.is( o.screenMaps[ m ] ) ) +// { +// if( key in o.screenMaps[ m ] ) +// return key; +// } +// // if( _.primitive.is( o.screenMaps[ m ] ) ) +// // { +// // if( o.screenMaps[ m ] === key ) +// // return key; +// // } +// } +// else +// { +// for( let m of o.screenMaps ) +// if( _.primitive.is( m ) ) +// { +// if( m === key ) +// return key; +// } +// else if( _.aux.is( m ) ) +// { +// if( key in m ) +// return key; +// } +// // if( _.primitive.is( m ) ) +// // { +// // if( m === key ) +// // return key; +// // } +// } +// // if( _.argumentsArray.like( o.screenMaps ) ) +// // { +// // for( let m = 0 ; m < o.screenMaps.length ; m++ ) +// // if( _.vector.is( o.screenMaps[ m ] ) && key in o.screenMaps[ m ] ) +// // return key; +// // else if( _.aux.is( o.screenMaps[ m ] ) && key in o.screenMaps[ m ] ) +// // return key; +// // else if( _.primitive.is( o.screenMaps[ m ] ) && o.screenMaps[ m ] === key ) +// // return key; +// // else if( key === String( m ) ) +// // return key; +// // } +// // else +// // { +// // for( let e of o.screenMaps ) +// // if( _.vector.is( e ) && key in e ) +// // return key; +// // else if( _.aux.is( e ) && key in e ) +// // return key; +// // else if( _.primitive.is( e ) && e === key ) +// // return key; +// // } +// } +// +// /* */ +// +// function filterNotIdentical( srcMap ) +// { +// for( let key in o.screenMaps ) +// { +// if( o.screenMaps[ key ] === undefined ) +// continue; +// +// if( key in srcMap ) +// o.filter.call( self, o.dstMap, srcMap, key ); +// } +// // for( let key in srcMap ) +// // { +// // if( ( key in o.screenMaps ) && o.screenMaps[ key ] !== undefined ) +// // o.filter.call( self, o.dstMap, srcMap, key ); +// // } +// } +// +// /* */ +// +// function filterIdentical( srcMap ) +// { +// for( let key in srcMap ) +// { +// if( !( key in o.screenMaps ) ) +// delete srcMap[ key ]; +// else +// o.filter.call( self, o.dstMap, srcMap, key ); +// } +// } +// +// // let dstMap = o.dstMap || Object.create( null ); +// // let screenMap = o.screenMaps; +// // let srcMaps = o.srcMaps; +// // +// // /* aaa : for Dmytro : not optimal */ /* Dmytro : optimized */ +// // if( !_.vector.is( srcMaps ) ) +// // srcMaps = [ srcMaps ]; +// // +// // if( !o.filter ) +// // o.filter = _.props.mapper.bypass(); +// // +// // if( Config.debug ) +// // { +// // +// // // _.assert( o.filter.functionFamily === 'PropertyMapper' ); +// // _.assert( _.props.mapperIs( o.filter ), 'Expects PropertyFilter {-propertyCondition-}' ); +// // _.assert( arguments.length === 1, 'Expects single argument' ); +// // _.assert( !_.primitive.is( dstMap ), 'Expects object-like {-dstMap-}' ); +// // _.assert( !_.primitive.is( screenMap ), 'Expects not primitive {-screenMap-}' ); +// // _.assert( _.vector.is( srcMaps ), 'Expects vector {-srcMaps-}' ); +// // _.map.assertHasOnly( o, _mapOnly_.defaults ); +// // _.map.assertHasOnly( o, _mapOnly_.defaults ); +// // +// // for( let s = srcMaps.length - 1 ; s >= 0 ; s-- ) +// // _.assert( !_.primitive.is( srcMaps[ s ] ), 'Expects {-srcMaps-}' ); +// // +// // } +// // +// // /* aaa : allow and cover vector */ /* Dmytro : implemented, covered */ +// // +// // if( o.dstMap === o.srcMaps || o.dstMap === o.srcMaps[ 0 ] ) +// // { +// // if( _.vector.is( screenMap ) ) +// // _mapsFilterWithLongScreenMap.call( this, mapsIdenticalFilterWithLong ); +// // else +// // _mapsIdenticalFilter.call( this ); +// // } +// // else +// // { +// // if( _.vector.is( screenMap ) ) +// // _mapsFilterWithLongScreenMap.call( this, mapsNotIdenticalFilterWithLong ); +// // else +// // _mapsNotIdenticalFilter.call( this ) +// // } +// // +// // return dstMap; +// // +// // /* */ +// // +// // function _mapsFilterWithLongScreenMap( filterCallback ) +// // { +// // for( let s in srcMaps ) +// // { +// // let srcMap = srcMaps[ s ]; +// // +// // for( let k in srcMap ) +// // { +// // let m = iterateKeyOfScreenMap( k ); +// // // for( m = 0 ; m < screenMap.length ; m++ ) /* aaa : for Dmytro : teach to work with any vector here and in similar places */ /* Dmytro : implemented */ +// // // for( m of screenMap ) +// // // { +// // // if( _.vector.is( screenMap[ m ] ) ) +// // // { +// // // /* aaa : for Dmytro : check */ /* Dmytro : covered */ +// // // if( k in screenMap[ m ] ) +// // // break; +// // // } +// // // else +// // // { +// // // if( k === String( m ) ) +// // // break; +// // // } +// // // } +// // +// // filterCallback.call( this, srcMap, m, k ); +// // } +// // } +// // } +// // +// // /* */ +// // +// // function iterateKeyOfScreenMap( k ) +// // { +// // let m; +// // if( _.argumentsArray.like( screenMap ) ) +// // { +// // for( m = 0 ; m < screenMap.length ; m++ ) +// // if( _.vector.is( screenMap[ m ] ) && k in screenMap[ m ] ) +// // return m; +// // else if( _.aux.is( screenMap[ m ] ) && k in screenMap[ m ] ) +// // return m; +// // else if( _.primitive.is( screenMap[ m ] ) && screenMap[ m ] === k ) +// // return m; +// // else if( k === String( m ) ) +// // return m; +// // } +// // else +// // { +// // for( m of screenMap ) +// // if( _.vector.is( m ) && k in m ) +// // return k; +// // else if( _.aux.is( m ) && k in m ) +// // return k; +// // else if( _.primitive.is( m ) && m === k ) +// // return k; +// // +// // return srcMaps.length; +// // } +// // +// // return m; +// // } +// // +// // /* */ +// // +// // function mapsIdenticalFilterWithLong( src, index, key ) +// // { +// // if( index === screenMap.length ) +// // delete src[ key ]; +// // else +// // o.filter.call( this, dstMap, src, key ); +// // } +// // +// // /* */ +// // +// // function mapsNotIdenticalFilterWithLong( src, index, key ) +// // { +// // if( index !== screenMap.length ) +// // o.filter.call( this, dstMap, src, key ); +// // } +// // +// // /* */ +// // +// // function _mapsIdenticalFilter() +// // { +// // for( let s in srcMaps ) +// // { +// // let srcMap = srcMaps[ s ]; +// // +// // for( let k in srcMap ) +// // { +// // if( !( k in screenMap ) ) +// // delete srcMap[ k ]; +// // else +// // o.filter.call( this, dstMap, srcMap, k ); +// // } +// // } +// // } +// // +// // /* */ +// // +// // function _mapsNotIdenticalFilter() +// // { +// // for( let k in screenMap ) +// // { +// // if( screenMap[ k ] === undefined ) +// // continue; +// // +// // for( let s in srcMaps ) +// // if( k in srcMaps[ s ] ) +// // o.filter.call( this, dstMap, srcMaps[ s ], k ); +// // } +// // } +// } +// +// _mapOnly_.defaults = +// { +// dstMap : null, +// srcMaps : null, +// screenMaps : null, +// filter : null, +// } + +// + +/* qqq : cover */ +function mapDiff( dst, src1, src2 ) +{ + if( arguments.length === 2 ) + { + dst = null; + src1 = arguments[ 0 ]; + src2 = arguments[ 1 ]; + } + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( dst === null || _.aux.is( dst ) ); + + dst = dst || Object.create( null ); + + dst.src1 = _.mapBut_( dst.src1 || null, src1, src2 ); + dst.src2 = _.mapBut_( dst.src2 || null, src2, src1 ); + dst.src2 = _.props.extend( null, dst.src1, dst.src2 ); + dst.identical = Object.keys( dst.src1 ).length === 0 && Object.keys( dst.src2 ).length === 0; + + return dst; +} + +// -- +// map sure +// -- + +function sureHasExactly( srcMap, screenMaps, msg ) +{ + let result = true; + + result = result && _.map.sureHasOnly.apply( this, arguments ); + result = result && _.map.sureHasAll.apply( this, arguments ); + + return true; +} + +// + +function sureOwnExactly( srcMap, screenMaps, msg ) +{ + let result = true; + + result = result && _.map.sureOwnOnly.apply( this, arguments ); + result = result && _.map.sureOwnAll.apply( this, arguments ); + + return true; +} + +// + +/** + * Checks if map passed by argument {-srcMap-} has only properties represented in object(s) passed after first argument. Checks all enumerable properties. + * Works only in debug mode. Uses StackTrace level 2. {@link wTools.err See err} + * If routine found some unique properties in source it generates and throws exception, otherwise returns without exception. + * Also generates error using message passed after last object. Message may be a string, an array, or a function. + * + * @param { Object } srcMap - source map. + * @param { Object } screenMaps - object to compare with. + * @param { * } [ msg ] - error message for generated exception. + * @param { * } [ msg ] - error message that adds to the message in third argument. + * + * @example + * let a = { a : 1, b : 3 }; + * let b = { a : 2, b : 3 }; + * _.map.sureHasOnly( a, b ); + * // no exception + * + * @example + * let a = { a : 1, c : 3 }; + * let b = { a : 2, b : 3 }; + * _.map.sureHasOnly( a, b ); + * + * // log + * // caught :3:8 + * // Object should have no fields : c + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureHasOnly (file:///.../wTools/staging/Base.s:4188) + * // at :3 + * + * @example + * let x = { d : 1 }; + * let a = Object.create( x ); + * let b = { a : 1 }; + * _.map.sureHasOnly( a, b, 'message' ) + * + * // log + * // caught :4:8 + * // message Object should have no fields : d + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureHasOnly (file:///.../wTools/staging/Base.s:4188) + * // at :4 + * + * @example + * let x = { d : 1 }; + * let a = Object.create( x ); + * let b = { a : 1 }; + * _.map.sureHasOnly( a, b, () => 'message, ' + 'map`, ' should have no fields :' ) + * + * // log + * // caught :4:8 + * // message Object should have no fields : d + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureHasOnly (file:///.../wTools/staging/Base.s:4188) + * // at :4 + * + * @function sureHasOnly + * @throws {Exception} If no arguments are provided or more than four arguments are provided. + * @throws {Exception} If map {-srcMap-} contains unique property. + * @namespace Tools + * + */ + +function sureHasOnly( srcMap, screenMaps, msg ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4, 'Expects two, three or four arguments' ); + + /* qqq : for Dmytro : bad ! */ + // let but = Object.keys( _.mapBut_( null, srcMap, screenMaps ) ); + let but = Object.keys( _.mapButOld( srcMap, screenMaps ) ); + + if( but.length > 0 ) + { + let err; + if( arguments.length === 2 ) + err = _._err + ({ + args : [ `${ _.entity.strType( srcMap ) } should have no fields :`, _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + else + { + let arr = []; + for( let i = 2; i < arguments.length; i++ ) + { + if( _.routine.is( arguments[ i ] ) ) + arguments[ i ] = ( arguments[ i ] )(); + arr.push( arguments[ i ] ); + } + err = _._err + ({ + args : [ arr.join( ' ' ), _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + debugger; /* eslint-disable-line no-debugger */ + throw err; + return false; + } + + return true; +} + +// + +/** + * Checks if map passed by argument {-srcMap-} has only properties represented in object(s) passed after first argument. Checks only own properties of the objects. + * Works only in debug mode. Uses StackTrace level 2.{@link wTools.err See err} + * If routine found some unique properties in source it generates and throws exception, otherwise returns without exception. + * Also generates error using message passed after last object. Message may be a string, an array, or a function. + * + * @param { Object } srcMap - source map. + * @param { Object } screenMaps - object to compare with. + * @param { * } [ msg ] - error message for generated exception. + * @param { * } [ msg ] - error message that adds to the message in third argument. + * + * @example + * let x = { d : 1 }; + * let a = Object.create( x ); + * a.a = 5; + * let b = { a : 2 }; + * _.map.sureOwnOnly( a, b ); + * //no exception + * + * @example + * let a = { d : 1 }; + * let b = { a : 2 }; + * _.map.sureOwnOnly( a, b ); + * + * // log + * // caught :3:10 + * // Object should have no own fields : d + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureOwnOnly (file:///.../wTools/staging/Base.s:4215) + * // at :3 + * + * @example + * let a = { x : 0, y : 2 }; + * let b = { c : 0, d : 3}; + * let c = { a : 1 }; + * _.map.sureOwnOnly( a, b, 'error msg' ); + * + * // log + * // caught :4:8 + * // error msg Object should have no own fields : x, y + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureOwnOnly (file:///.../wTools/staging/Base.s:4215) + * // at :4 + * + * @example + * let a = { x : 0, y : 2 }; + * let b = { c : 0, d : 3}; + * let c = { a : 1 }; + * _.map.sureOwnOnly( a, b, () => 'error, ' + 'map should', ' no own fields :' ); + * + * // log + * // caught :4:9 + * // error, map should have no own fields : x, y + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureOwnOnly (file:///.../wTools/staging/Base.s:4215) + * // at :3 + * + * @function sureOwnOnly + * @throws {Exception} If no arguments are provided or more than four arguments are provided. + * @throws {Exception} If map {-srcMap-} contains unique property. + * @namespace Tools + * + */ + +function sureOwnOnly( srcMap, screenMaps, msg ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4, 'Expects two, three or four arguments' ); + + /* qqq : for Dmytro : bad! */ + let but = Object.keys( _.mapOnlyOwnButOld( srcMap, screenMaps ) ); + + if( but.length > 0 ) + { + let err; + if( arguments.length === 2 ) + { + err = _._err + ({ + args : [ `${ _.entity.strType( srcMap ) } should own no fields :`, _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + else + { + let arr = []; + for( let i = 2; i < arguments.length; i++ ) + { + if( _.routine.is( arguments[ i ] ) ) + arguments[ i ] = ( arguments[ i ] )(); + arr.push( arguments[ i ] ); + } + err = _._err + ({ + args : [ arr.join( ' ' ), _.strQuote( but ).join( ', ' ) ], + level : 3, + }); + } + debugger; /* eslint-disable-line no-debugger */ + throw err; + return false; + } + + return true; +} + +// + +/** + * Checks if map passed by argument {-srcMap-} has all properties represented in object passed by argument( all ). Checks all enumerable properties. + * Works only in debug mode. Uses StackTrace level 2.{@link wTools.err See err} + * If routine did not find some properties in source it generates and throws exception, otherwise returns without exception. + * Also generates error using message passed after last object. Message may be a string, an array, or a function. + * + * @param { Object } srcMap - source map. + * @param { Object } all - object to compare with. + * @param { * } [ msg ] - error message for generated exception. + * @param { * } [ msg ] - error message that adds to the message in third argument. + * + * @example + * let x = { a : 1 }; + * let a = Object.create( x ); + * let b = { a : 2 }; + * _.map.sureHasAll( a, b ); + * // no exception + * + * @example + * let a = { d : 1 }; + * let b = { a : 2 }; + * _.map.sureHasAll( a, b ); + * + * // log + * // caught :3:10 + * // Object should have fields : a + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureHasAll (file:///.../wTools/staging/Base.s:4242) + * // at :3 + * + * @example + * let a = { x : 0, y : 2 }; + * let b = { x : 0, d : 3}; + * _.map.sureHasAll( a, b, 'error msg' ); + * + * // log + * // caught :4:9 + * // error msg Object should have fields : d + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureHasAll (file:///.../wTools/staging/Base.s:4242) + * // at :3 + * + * @example + * let a = { x : 0 }; + * let b = { x : 1, y : 0}; + * _.map.sureHasAll( a, b, () => 'error, ' + 'map should', ' have fields :' ); + * + * // log + * // caught :4:9 + * // error, map should have fields : y + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureHasAll (file:///.../wTools/staging/Base.s:4242) + * // at :3 + * + * @function sureHasAll + * @throws {Exception} If no arguments are provided or more than four arguments are provided. + * @throws {Exception} If map {-srcMap-} not contains some properties from argument( all ). + * @namespace Tools + * + */ + +function sureHasAll( srcMap, all, msg ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4, 'Expects two, three or four arguments' ); + + let but = Object.keys( _.mapBut_( null, all, srcMap ) ); + + if( but.length > 0 ) + { + let err; + if( arguments.length === 2 ) + { + err = _._err + ({ + args : [ `${ _.entity.strType( srcMap ) } should have fields :`, _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + else + { + let arr = []; + for( let i = 2; i < arguments.length; i++ ) + { + if( _.routine.is( arguments[ i ] ) ) + arguments[ i ] = ( arguments[ i ] )(); + arr.push( arguments[ i ] ); + } + err = _._err + ({ + args : [ arr.join( ' ' ), _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + debugger; /* eslint-disable-line no-debugger */ + throw err; + return false; + } + + return true; +} + +// + +/** + * Checks if map passed by argument {-srcMap-} has all properties represented in object passed by argument( all ). Checks only own properties of the objects. + * Works only in Config.debug mode. Uses StackTrace level 2. {@link wTools.err See err} + * If routine did not find some properties in source it generates and throws exception, otherwise returns without exception. + * Also generates error using message passed after last object. Message may be a string, an array, or a function. + * + * @param { Object } srcMap - source map. + * @param { Object } all - object to compare with. + * @param { * } [ msg ] - error message for generated exception. + * @param { * } [ msg ] - error message that adds to the message in third argument. + * + * @example + * let a = { a : 1 }; + * let b = { a : 2 }; + * wTools.sureMapOwnAll( a, b ); + * // no exception + * + * @example + * let a = { a : 1 }; + * let b = { a : 2, b : 2 } + * _.map.sureOwnAll( a, b ); + * + * // log + * // caught :3:8 + * // Object should have own fields : b + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureOwnAll (file:///.../wTools/staging/Base.s:4269) + * // at :3 + * + * @example + * let a = { x : 0 }; + * let b = { x : 1, y : 0}; + * _.map.sureOwnAll( a, b, 'error, should own fields' ); + * + * // log + * // caught :4:9 + * // error, should own fields : y + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureOwnAll (file:///.../wTools/staging/Base.s:4269) + * // at :3 + * + * @example + * let a = { x : 0 }; + * let b = { x : 1, y : 0}; + * _.map.sureOwnAll( a, b, () => 'error, ' + 'map should', ' own fields :' ); + * + * // log + * // caught :4:9 + * // error, map should own fields : y + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureOwnAll (file:///.../wTools/staging/Base.s:4269) + * // at :3 + * + * @function sureOwnAll + * @throws {Exception} If no arguments are provided or more than four arguments are provided. + * @throws {Exception} If map {-srcMap-} not contains some properties from argument( all ). + * @namespace Tools + * + */ + +function sureOwnAll( srcMap, all, msg ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4, 'Expects two, three or four arguments' ); + + let but = Object.keys( _.mapOnlyOwnBut_( null, all, srcMap ) ); + + if( but.length > 0 ) + { + let err; + if( arguments.length === 2 ) + { + err = _._err + ({ + args : [ `${ _.entity.strType( srcMap ) } should own fields :`, _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + else + { + let arr = []; + for( let i = 2; i < arguments.length; i++ ) + { + if( _.routine.is( arguments[ i ] ) ) + arguments[ i ] = ( arguments[ i ] )(); + arr.push( arguments[ i ] ); + } + err = _._err + ({ + args : [ arr.join( ' ' ), _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + debugger; /* eslint-disable-line no-debugger */ + throw err; + return false; + } + + return true; +} + +// + +/** + * Checks if map passed by argument {-srcMap-} has no properties represented in object(s) passed after first argument. Checks all enumerable properties. + * Works only in debug mode. Uses StackTrace level 2. {@link wTools.err See err} + * If routine found some properties in source it generates and throws exception, otherwise returns without exception. + * Also generates error using message passed after last object. Message may be a string, an array, or a function. + * + * @param { Object } srcMap - source map. + * @param {...Object} screenMaps - object(s) to compare with. + * @param { * } [ msg ] - error message for generated exception. + * @param { * } [ msg ] - error message that adds to the message in third argument. + * + * @example + * let a = { a : 1 }; + * let b = { b : 2 }; + * _.map.sureHasNone( a, b ); + * // no exception + * + * @example + * let x = { a : 1 }; + * let a = Object.create( x ); + * let b = { a : 2, b : 2 } + * _.map.sureHasNone( a, b ); + * + * // log + * // caught :4:8 + * // Object should have no fields : a + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureHasNone (file:///.../wTools/staging/Base.s:4518) + * // at :4 + * + * @example + * let a = { x : 0, y : 1 }; + * let b = { x : 1, y : 0 }; + * _.map.sureHasNone( a, b, 'error, map should have no fields' ); + * + * // log + * // caught :3:9 + * // error, map should have no fields : x, y + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureHasNone (file:///.../wTools/staging/Base.s:4518) + * // at :3 + * + * @example + * let a = { x : 0, y : 1 }; + * let b = { x : 1, y : 0 }; + * _.map.sureHasNone( a, b, () => 'error, ' + 'map should have', 'no fields :' ); + * + * // log + * // caught :3:9 + * // error, map should have no fields : x, y + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureHasNone (file:///.../wTools/staging/Base.s:4518) + * // at :3 + * + * @function sureHasNone + * @throws {Exception} If no arguments are provided or more than four arguments are provided. + * @throws {Exception} If map {-srcMap-} contains some properties from other map(s). + * @namespace Tools + * + */ + +function sureHasNone( srcMap, screenMaps, msg ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4, 'Expects two, three or four arguments' ); + + let but = Object.keys( _.mapOnly_( null, srcMap, screenMaps ) ); + + if( but.length > 0 ) + { + let err; + if( arguments.length === 2 ) + { + err = _._err + ({ + args : [ `${ _.entity.strType( srcMap ) } should have no fields :`, _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + else + { + let arr = []; + for( let i = 2; i < arguments.length; i++ ) + { + if( _.routine.is( arguments[ i ] ) ) + arguments[ i ] = ( arguments[ i ] )(); + arr.push( arguments[ i ] ); + } + err = _._err + ({ + args : [ arr.join( ' ' ), _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + debugger; /* eslint-disable-line no-debugger */ + throw err; + return false; + } + + return true; +} + +// + +function sureOwnNone( srcMap, screenMaps, msg ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4, 'Expects two, three or four arguments' ); + + let but = Object.keys( _.mapOnlyOwn_( null, srcMap, screenMaps ) ); + + if( but.length > 0 ) + { + let err; + if( arguments.length === 2 ) + { + err = _._err + ({ + args : [ `${ _.entity.strType( srcMap ) } should own no fields :`, _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + else + { + let arr = []; + for( let i = 2; i < arguments.length; i++ ) + { + if( _.routine.is( arguments[ i ] ) ) + arguments[ i ] = ( arguments[ i ] )(); + arr.push( arguments[ i ] ); + } + err = _._err + ({ + args : [ arr.join( ' ' ), _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + debugger; /* eslint-disable-line no-debugger */ + throw err; + return false; + } + + return true; +} + +// + +/** + * Checks if map passed by argument {-srcMap-} not contains undefined properties. Works only in debug mode. Uses StackTrace level 2. {@link wTools.err See err} + * If routine found undefined property it generates and throws exception, otherwise returns without exception. + * Also generates error using messages passed after first argument. Message may be a string, an array, or a function. + * + * @param { Object } srcMap - source map. + * @param { * } [ msg ] - error message for generated exception. + * @param { * } [ msg ] - error message that adds to the message in third argument. + * + * @example + * let map = { a : '1', b : 'name' }; + * _.map.sureHasNoUndefine( map ); + * // no exception + * + * @example + * let map = { a : '1', b : undefined }; + * _.map.sureHasNoUndefine( map ); + * + * // log + * // caught :2:8 + * // Object should have no undefines, but has : b + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureHasNoUndefine (file:///.../wTools/staging/Base.s:4087) + * // at :2 + * + * @example + * let map = { a : undefined, b : '1' }; + * _.map.sureHasNoUndefine( map, '"map" has undefines :'); + * + * // log + * // caught :2:8 + * // "map" has undefines : a + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureHasNoUndefine (file:///.../wTools/staging/Base.s:4087) + * // at :2 + * + * @example + * let map = { a : undefined, b : '1' }; + * _.map.sureHasNoUndefine( map, '"map"', () => 'should have ' + 'no undefines, but has :' ); + * + * // log + * // caught :2:8 + * // "map" should have no undefines, but has : a + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at sureHasNoUndefine (file:///.../wTools/staging/Base.s:4087) + * // at :2 + * + * @function sureHasNoUndefine + * @throws {Exception} If no arguments passed or than three arguments passed. + * @throws {Exception} If map {-srcMap-} contains undefined property. + * @namespace Tools + * + */ + +function sureHasNoUndefine( srcMap, msg ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 || arguments.length === 3, 'Expects one, two or three arguments' ) + + let but = []; + + for( let s in srcMap ) + if( srcMap[ s ] === undefined ) + but.push( s ); + + if( but.length > 0 ) + { + let err; + if( arguments.length === 1 ) + { + err = _._err + ({ + args : [ `${ _.entity.strType( srcMap ) } should have no undefines, but has :`, _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + else + { + let arr = []; + for( let i = 1; i < arguments.length; i++ ) + { + if( _.routine.is( arguments[ i ] ) ) + arguments[ i ] = ( arguments[ i ] )(); + arr.push( arguments[ i ] ); + } + err = _._err + ({ + args : [ arr.join( ' ' ), _.strQuote( but ).join( ', ' ) ], + level : 2, + }); + } + debugger; /* eslint-disable-line no-debugger */ + throw err; + return false; + } + + return true; +} + +// -- +// map assert +// -- + +function assertHasExactly( srcMap, screenMaps, msg ) +{ + if( Config.debug === false ) + return true; + return _.map.sureHasExactly.apply( this, arguments ); +} + +// + +function assertOwnExactly( srcMap, screenMaps, msg ) +{ + if( Config.debug === false ) + return true; + return _.map.sureOwnExactly.apply( this, arguments ); +} + +// + +/** + * Checks if map passed by argument {-srcMap-} has only properties represented in object(s) passed after first argument. Checks all enumerable properties. + * Works only in debug mode. Uses StackTrace level 2. {@link wTools.err See err} + * If routine found some unique properties in source it generates and throws exception, otherwise returns without exception. + * Also generates error using message passed after second argument. Message may be a string, an array, or a function. + * + * @param { Object } srcMap - source map. + * @param { Object } screenMaps - object to compare with. + * @param { * } [ msg ] - error message for generated exception. + * @param { * } [ msg ] - error message that adds to the message in third argument. + * + * @example + * let a = { a : 1, b : 3 }; + * let b = { a : 2, b : 3 }; + * _.map.assertHasOnly( a, b ); + * //no exception + * + * @example + * let a = { a : 1, c : 3 }; + * let b = { a : 2, b : 3 }; + * _.map.assertHasOnly( a, b ); + * + * // log + * // caught :3:8 + * // Object should have no fields : c + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertHasOnly (file:///.../wTools/staging/Base.s:4188) + * // at :3 + * + * @example + * let x = { d : 1 }; + * let a = Object.create( x ); + * let b = { a : 1 }; + * _.map.assertHasOnly( a, b, 'map should have no fields :' ) + * + * // log + * // caught :4:8 + * // map should have no fields : d + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertHasOnly (file:///.../wTools/staging/Base.s:4188) + * // at :4 + * + * @example + * let x = { d : 1 }; + * let a = Object.create( x ); + * let b = { a : 1 }; + * _.map.assertHasOnly( a, b, 'map', () => ' should' + ' have no fields :' ) + * + * // log + * // caught :4:8 + * // map should have no fields : d + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertHasOnly (file:///.../wTools/staging/Base.s:4188) + * // at :4 + * + * @function assertHasOnly + * @throws {Exception} If no arguments provided or more than four arguments passed. + * @throws {Exception} If map {-srcMap-} contains unique property. + * @namespace Tools + * + */ + +function assertHasOnly( srcMap, screenMaps, msg ) +{ + if( Config.debug === false ) + return true; + return _.map.sureHasOnly.apply( this, arguments ); + + /* */ + + // _.assert( 2 <= arguments.length && arguments.length <= 4, 'Expects two, three or four arguments' ); + // + // let but = mapButKeys( srcMap, screenMaps ); + // + // if( but.length > 0 ) + // { + // let err; + // let msgKeys = _.strQuote( but ).join( ', ' ); + // if( arguments.length === 2 ) + // err = errFromArgs([ `${ _.entity.strType( srcMap ) } should have no fields : ${ msgKeys }` ]); + // else + // err = errFromArgs([ msgMake( arguments ), msgKeys ]); + // throw err; + // } + // + // return true; + // + // /* */ + // + // function mapButKeys( srcMap, butMap ) + // { + // let result = []; + // _.assert( !_.primitive.is( srcMap ), 'Expects map {-srcMap-}' ); + // + // /* aaa : allow and cover vector */ /* Dmytro : this inlining is not needed, that was mistake */ + // if( _.vector.is( butMap ) ) + // { + // /* aaa : for Dmytro : bad */ /* Dmytro : this inlining is not needed, that was mistake */ + // for( let s in srcMap ) + // { + // let m; + // for( m = 0 ; m < butMap.length ; m++ ) + // { + // /* aaa : for Dmytro : was bad implementation. cover */ /* Dmytro : this inlining is not needed, that was mistake */ + // if( _.primitive.is( butMap[ m ] ) ) + // { + // if( s === butMap[ m ] ) + // break; + // } + // else + // { + // if( s in butMap[ m ] ) + // break; + // } + // } + // + // if( m === butMap.length ) + // result.push( s ); + // } + // } + // else if( !_.primitive.is( butMap ) ) + // { + // for( let s in srcMap ) + // { + // if( !( s in butMap ) ) + // result.push( s ); + // } + // } + // else + // { + // _.assert( 0, 'Expects object-like or long-like {-butMap-}' ); + // } + // + // return result; + // } + // + // /* */ + // + // function errFromArgs( args ) + // { + // return _._err + // ({ + // args, + // level : 2, + // }); + // } + // + // /* */ + // + // function msgMake( args ) + // { + // let arr = []; + // for( let i = 2; i < args.length; i++ ) + // { + // if( _.routineIs( args[ i ] ) ) + // args[ i ] = args[ i ](); + // arr.push( args[ i ] ); + // } + // return arr.join( ' ' ); + // } +} + +// + +/** + * Checks if map passed by argument {-srcMap-} has only properties represented in object(s) passed after first argument. Checks only own properties of the objects. + * Works only in debug mode. Uses StackTrace level 2.{@link wTools.err See err} + * If routine found some unique properties in source it generates and throws exception, otherwise returns without exception. + * Also generates error using message passed after second argument. Message may be a string, an array, or a function. + * + * @param { Object } srcMap - source map. + * @param { Object } screenMaps - object to compare with. + * @param { * } [ msg ] - error message for generated exception. + * @param { * } [ msg ] - error message that adds to the message in third argument. + * + * @example + * let x = { d : 1 }; + * let a = Object.create( x ); + * a.a = 5; + * let b = { a : 2 }; + * _.map.assertOwnOnly( a, b ); + * // no exception + * + * @example + * let a = { d : 1 }; + * let b = { a : 2 }; + * _.map.assertOwnOnly( a, b ); + * + * // log + * // caught :3:10 + * // Object should have no own fields : d + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertOwnOnly (file:///.../wTools/staging/Base.s:4215) + * // at :3 + * + * @example + * let a = { x : 0, y : 2 }; + * let b = { c : 0, d : 3}; + * let c = { a : 1 }; + * _.map.assertOwnOnly( a, b, 'error, map should have no own fields :' ); + * + * // log + * // caught :4:8 + * // error, map should have no own fields : x, y + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertOwnOnly (file:///.../wTools/staging/Base.s:4215) + * // at :4 + * + * @example + * let a = { x : 0, y : 2 }; + * let b = { c : 0, d : 3}; + * let c = { a : 1 }; + * _.map.assertOwnOnly( a, b, () => 'error, ' + 'map', ' should have no own fields :' ); + * + * // log + * // caught :4:8 + * // error, map should have no own fields : x, y + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertOwnOnly (file:///.../wTools/staging/Base.s:4215) + * // at :4 + * + * @function assertOwnOnly + * @throws {Exception} If no arguments provided or more than four arguments passed. + * @throws {Exception} If map {-srcMap-} contains unique property. + * @namespace Tools + * + */ + +function assertOwnOnly( srcMap, screenMaps, msg ) +{ + if( Config.debug === false ) + return true; + return _.map.sureOwnOnly.apply( this, arguments ); +} + +// + +/** + * Checks if map passed by argument {-srcMap-} has no properties represented in object(s) passed after first argument. Checks all enumerable properties. + * Works only in debug mode. Uses StackTrace level 2. {@link wTools.err See err} + * If routine found some properties in source it generates and throws exception, otherwise returns without exception. + * Also generates error using message passed after second argument. Message may be a string, an array, or a function. + * + * @param { Object } srcMap - source map. + * @param { Object } screenMaps - object to compare with. + * @param { * } [ msg ] - error message for generated exception. + * @param { * } [ msg ] - error message that adds to the message in third argument. + * + * @example + * let a = { a : 1 }; + * let b = { b : 2 }; + * _.map.assertHasNone( a, b ); + * // no exception + * + * @example + * let x = { a : 1 }; + * let a = Object.create( x ); + * let b = { a : 2, b : 2 } + * _.map.assertHasNone( a, b ); + * + * // log + * // caught :4:8 + * // Object should have no fields : a + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertHasAll (file:///.../wTools/staging/Base.s:4518) + * // at :4 + * + * @example + * let a = { x : 0, y : 1 }; + * let b = { x : 1, y : 0 }; + * _.map.assertHasNone( a, b, 'map should have no fields :' ); + * + * // log + * // caught :3:9 + * // map should have no fields : x, y + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertHasNone (file:///.../wTools/staging/Base.s:4518) + * // at :3 + * + * @example + * let a = { x : 0, y : 1 }; + * let b = { x : 1, y : 0 }; + * _.map.assertHasNone( a, b, () => 'map ' + 'should ', 'have no fields :' ); + * + * // log + * // caught :3:9 + * // map should have no fields : x, y + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertHasNone (file:///.../wTools/staging/Base.s:4518) + * // at :3 + * + * @function assertHasNone + * @throws {Exception} If no arguments provided or more than four arguments passed. + * @throws {Exception} If map {-srcMap-} contains some properties from other map(s). + * @namespace Tools + * + */ + +function assertHasNone( srcMap, screenMaps, msg ) +{ + if( Config.debug === false ) + return true; + return _.map.sureHasNone.apply( this, arguments ); +} + +// + +function assertOwnNone( srcMap, screenMaps, msg ) +{ + if( Config.debug === false ) + return true; + return _.map.sureOwnNone.apply( this, arguments ); +} + +// + +/** + * Checks if map passed by argument {-srcMap-} has all properties represented in object passed by argument( all ). Checks all enumerable properties. + * Works only in debug mode. Uses StackTrace level 2.{@link wTools.err See err} + * If routine did not find some properties in source it generates and throws exception, otherwise returns without exception. + * Also generates error using message passed after second argument. Message may be a string, an array, or a function. + * + * @param { Object } srcMap - source map. + * @param { Object } all - object to compare with. + * @param { * } [ msg ] - error message for generated exception. + * @param { * } [ msg ] - error message that adds to the message in third argument. + * + * @example + * let x = { a : 1 }; + * let a = Object.create( x ); + * let b = { a : 2 }; + * _.map.assertHasAll( a, b ); + * // no exception + * + * @example + * let a = { d : 1 }; + * let b = { a : 2 }; + * _.map.assertHasAll( a, b ); + * + * // log + * // caught :3:10 + * // Object should have fields : a + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertHasAll (file:///.../wTools/staging/Base.s:4242) + * // at :3 + * + * @example + * let a = { x : 0, y : 2 }; + * let b = { x : 0, d : 3}; + * _.map.assertHasAll( a, b, 'map should have fields :' ); + * + * // log + * // caught :4:9 + * // map should have fields : d + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertHasAll (file:///.../wTools/staging/Base.s:4242) + * // at :3 + * + * @example + * let a = { x : 0, y : 2 }; + * let b = { x : 0, d : 3}; + * _.map.assertHasAll( a, b, () => 'map' + ' should', ' have fields :' ); + * + * // log + * // caught :4:9 + * // map should have fields : d + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertHasAll (file:///.../wTools/staging/Base.s:4242) + * // at :3 + * + * @function assertHasAll + * @throws {Exception} If no arguments provided or more than four arguments passed. + * @throws {Exception} If map {-srcMap-} not contains some properties from argument( all ). + * @namespace Tools + * + */ + +function assertHasAll( srcMap, all, msg ) +{ + if( Config.debug === false ) + return true; + return _.map.sureHasAll.apply( this, arguments ); +} + +// + +/** + * Checks if map passed by argument {-srcMap-} has all properties represented in object passed by argument( all ). Checks only own properties of the objects. + * Works only in Config.debug mode. Uses StackTrace level 2. {@link wTools.err See err} + * If routine did not find some properties in source it generates and throws exception, otherwise returns without exception. + * Also generates error using message passed after second argument. Message may be a string, an array, or a function. + * + * @param { Object } srcMap - source map. + * @param { Object } all - object to compare with. + * @param { * } [ msg ] - error message for generated exception. + * @param { * } [ msg ] - error message that adds to the message in third argument. + * + * @example + * let a = { a : 1 }; + * let b = { a : 2 }; + * _.map.assertOwnAll( a, b ); + * // no exception + * + * @example + * let a = { a : 1 }; + * let b = { a : 2, b : 2 } + * _.map.assertOwnAll( a, b ); + * + * // log + * // caught :3:8 + * // Object should own fields : b + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertHasAll (file:///.../wTools/staging/Base.s:4269) + * // at :3 + * + * @example + * let a = { x : 0 }; + * let b = { x : 1, y : 0}; + * _.map.assertOwnAll( a, b, 'error msg, map should own fields :' ); + * + * // log + * // caught :4:9 + * // error msg, map should own fields : y + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertOwnAll (file:///.../wTools/staging/Base.s:4269) + * // at :3 + * + * @example + * let a = { x : 0 }; + * let b = { x : 1, y : 0}; + * _.map.assertOwnAll( a, b, 'error msg, ', () => 'map' + ' should own fields :' ); + * + * // log + * // caught :4:9 + * // error msg, map should own fields : y + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertOwnAll (file:///.../wTools/staging/Base.s:4269) + * // at :3 + * + * @function assertOwnAll + * @throws {Exception} If no arguments passed or more than four arguments passed. + * @throws {Exception} If map {-srcMap-} not contains some properties from argument( all ). + * @namespace Tools + * + */ + +function assertOwnAll( srcMap, all, msg ) +{ + if( Config.debug === false ) + return true; + return _.map.sureOwnAll.apply( this, arguments ); +} + +// + +/** + * Checks if map passed by argument {-srcMap-} not contains undefined properties. Works only in debug mode. Uses StackTrace level 2. {@link wTools.err See err} + * If routine found undefined property it generates and throws exception, otherwise returns without exception. + * Also generates error using messages passed after first argument. Message may be a string, an array, or a function. + * + * @param { Object } srcMap - source map. + * @param { * } [ msg ] - error message for generated exception. + * @param { * } [ msg ] - error message that adds to the message in second argument. + * + * @example + * let map = { a : '1', b : 'name' }; + * _.map.assertHasNoUndefine( map ); + * // no exception + * + * @example + * let map = { a : '1', b : undefined }; + * _.map.assertHasNoUndefine( map ); + * + * // log + * // caught :2:8 + * // Object should have no undefines, but has : b + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertHasNoUndefine (file:///.../wTools/staging/Base.s:4087) + * // at :2 + * + * @example + * let map = { a : undefined, b : '1' }; + * _.map.assertHasNoUndefine( map, '"map" has undefines :'); + * + * // log + * // caught :2:8 + * // "map" has undefines : a + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertHasNoUndefine (file:///.../wTools/staging/Base.s:4087) + * // at :2 + * + * @example + * let map = { a : undefined, b : '1' }; + * _.map.assertHasNoUndefine( map, 'map', () => ' has ' + 'undefines :'); + * + * // log + * // caught :2:8 + * // map has undefines : a + * // + * // at _err (file:///.../wTools/staging/Base.s:3707) + * // at assertHasNoUndefine (file:///.../wTools/staging/Base.s:4087) + * // at :2 + * + * @function assertHasNoUndefine + * @throws {Exception} If no arguments provided or more than three arguments passed. + * @throws {Exception} If map {-srcMap-} contains undefined property. + * @namespace Tools + * + */ + +function assertHasNoUndefine( srcMap, msg ) +{ + if( Config.debug === false ) + return true; + + /* */ + + _.assert( 1 <= arguments.length && arguments.length <= 3, 'Expects one, two or three arguments' ) + _.assert( !_.primitive.is( srcMap ) ); + + let but = []; + + for( let s in srcMap ) + if( srcMap[ s ] === undefined ) + but.push( s ); + + if( but.length > 0 ) + { + let msgKeys = _.strQuote( but ).join( ', ' ); + if( arguments.length === 1 ) + throw errFromArgs([ `${ _.entity.strType( srcMap ) } should have no undefines, but has : ${ msgKeys }` ]); + else + throw errFromArgs([ msgMake( arguments ), msgKeys ]) + } + + return true; + + /* */ + + function errFromArgs( args ) + { + return _._err + ({ + args, + level : 2, + }); + } + + /* */ + + function msgMake( args ) + { + let arr = []; + for( let i = 1 ; i < args.length ; i++ ) + { + if( _.routine.is( args[ i ] ) ) + args[ i ] = args[ i ](); + arr.push( args[ i ] ); + } + return arr.join( ' ' ); + } +} + +// -- +// extension +// -- + +let Extension = +{ + + // map selector + + /* xxx : review */ + mapFirstPair, + mapAllValsSet, + mapValsWithKeys, + mapValWithIndex, + mapKeyWithIndex, + mapKeyWithValue, + // mapIndexWithKey, + // mapIndexWithValue, + + mapOnlyNulls, + mapButNulls, + + // map checker + + // mapsAreIdentical, /* xxx : remove */ + // mapContain, + + objectSatisfy, + + /* xxx : move routines to another namespace? */ + + /* introduce routine::mapHasKey */ + mapOwn : mapOwnKey, /* qqq : good coverage required! */ + mapOwnKey, + + mapHas : mapHasKey, /* qqq : good coverage required! */ + mapHasKey, + + mapOnlyOwnKey, + mapHasVal, + mapOnlyOwnVal, + + mapHasAll, + mapHasAny, + mapHasNone, + + mapOnlyOwnAll, + mapOnlyOwnAny, + mapOnlyOwnNone, + + mapHasExactly, + mapOnlyOwnExactly, + + mapHasOnly, + mapOnlyOwnOnly, + + mapHasNoUndefine, + + // map extend + + // mapMake, + // mapCloneShallow, + mapCloneAssigning, /* dubious */ + + // mapExtend, + mapsExtend, + mapExtendConditional, + mapsExtendConditional, + + mapExtendHiding, + mapsExtendHiding, + mapExtendAppending, + mapsExtendAppending, + mapExtendPrepending, + mapsExtendPrepending, + mapExtendAppendingOnlyArrays, + mapsExtendAppendingOnlyArrays, + mapExtendByDefined, + mapsExtendByDefined, + mapExtendNulls, /* qqq : cover */ /* qqq : check routine mapExtendNulls. seems does not extend undefined fields */ + mapsExtendNulls, /* qqq : cover */ + mapExtendDstNotOwn, /* qqq : cover */ + mapsExtendDstNotOwn, /* qqq : cover */ + mapExtendNotIdentical, /* qqq : cover */ + mapsExtendNotIdentical, /* qqq : cover */ + + // mapSupplement, + mapSupplementNulls, + mapSupplementNils, + mapSupplementAssigning, + mapSupplementAppending, + mapsSupplementAppending, + + mapSupplementOwnAssigning, + + mapComplement, + mapsComplement, + mapComplementReplacingUndefines, + mapsComplementReplacingUndefines, + mapComplementPreservingUndefines, + mapsComplementPreservingUndefines, + + // map extend recursive + + mapExtendRecursiveConditional, + mapsExtendRecursiveConditional, + _mapExtendRecursiveConditional, + + mapExtendRecursive, + mapsExtendRecursive, + _mapExtendRecursive, + + mapExtendAppendingAnythingRecursive, + mapsExtendAppendingAnythingRecursive, + mapExtendAppendingArraysRecursive, + mapsExtendAppendingArraysRecursive, + mapExtendAppendingOnceRecursive, + mapsExtendAppendingOnceRecursive, + + mapSupplementRecursive, + mapSupplementByMapsRecursive, + mapSupplementOwnRecursive, + mapsSupplementOwnRecursive, + mapSupplementRemovingRecursive, + mapSupplementByMapsRemovingRecursive, + + // map selector + + mapOnlyPrimitives, + + // map manipulator + + /* xxx */ + mapSetWithKeys, + mapSet : mapSetWithKeys, + mapSetWithKeyStrictly, + + // map transformer + + mapInvert, /* qqq : write _mapInvert accepting o-map | aaa : Done. Yevhen S. */ + _mapInvert, + mapInvertDroppingDuplicates, + mapsFlatten, + + // mapToArray, + mapToStr, /* experimental */ + mapFromHashMap : fromHashMap, + + // map logical operator + + mapButConditionalOld, /* !!! : use instead of mapButConditional */ /* qqq : make it accept null in the first argument */ /* Dmytro : covered, coverage is more complex */ + mapButConditional_, + // mapBut, /* !!! : use instead of mapBut */ /* Dmytro : covered, coverage is more complex */ + mapBut_, /* qqq : make it accept null in the first argument */ + mapButOld, + _mapBut_VerifyMapFields, + _mapBut_FilterFunctor, + // _mapBut_, + mapDelete, + mapEmpty, /* xxx : remove */ + // mapButIgnoringUndefines, /* !!! : use instead of mapButIgnoringUndefines */ /* Dmytro : covered, coverage is more complex */ + mapButIgnoringUndefines_, /* qqq : make it accept null in the first argument */ + /* qqq : for Dmytro : cover */ + /* qqq : for Dmytro : mess with problems! */ + /* xxx : use as default mapBut? */ + + mapOnlyOwnButOld, /* !!! : use instead of mapOnlyOwnBut */ /* Dmytro : covered, coverage is more complex */ + mapOnlyOwnBut_, /* qqq : make it accept null in the first argument */ + + // mapOnlyOld, /* !!! : use instead of mapOnly */ /* Dmytro : covered, coverage is more complex */ + mapOnly_, /* qqq : make it accept null in the first argument */ + // mapOnlyOwn, /* !!! : use instead of mapOnlyOwn */ /* Dmytro : covered, coverage is more complex */ + mapOnlyOwn_, /* qqq : make it accept null in the first argument */ + /* qqq : cover */ + // mapOnlyComplementing, /* !!! : use instead of mapOnlyComplementing */ /* Dmytro : covered, coverage is more complex */ + mapOnlyComplementing_, /* qqq : make it accept null in the first argument */ + // _mapOnly, /* xxx : qqq : comment out */ /* aaa : Dmytro : done */ + _mapOnly_VerifyMapFields, + _mapOnly_FilterFunctor, + _screenMapSearchingRoutineFunctor, + // _mapOnly_SearchKeyInVectorScreenMap, + // _mapOnly_, + + mapDiff, + + /* qqq xxx : implement mapDiff(), ask how to */ + +} + +// -- +// +// -- + +/* qqq : for junior : duplicate all routines */ + +let ExtensionMap = +{ + + // transformer + + fromHashMap, + + // sure + + sureHasExactly, + sureOwnExactly, + + sureHasOnly, + sureOwnOnly, + + sureHasAll, + sureOwnAll, + + sureHasNone, + sureOwnNone, + + sureHasNoUndefine, + + // assert + + assertHasExactly, + assertOwnExactly, + + assertHasOnly, + assertOwnOnly, + + assertHasNone, + assertOwnNone, + + assertHasAll, + assertOwnAll, + + assertHasNoUndefine, + +} + +// + +_.props.supplement( _, Extension ); +_.props.supplement( _.map, ExtensionMap ); +_.assert( _.aux.is( _.map ) ); + +})(); + + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Map.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Map_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Map_s */ })(); + +/* */ /* begin of file Number_s */ ( function Number_s() { function Number_s_naked() { ( function _l5_Numbers_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// number +// -- + +function clamp( src, low, high ) +{ + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.number.is( src ) ); + + if( arguments.length === 2 ) + { + _.assert( arguments[ 1 ].length === 2 ); + low = arguments[ 1 ][ 0 ]; + high = arguments[ 1 ][ 1 ]; + } + + if( src > high ) + return high; + + if( src < low ) + return low; + + return src; +} + +// + +function mix( ins1, ins2, progress ) +{ + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + return ins1*( 1-progress ) + ins2*( progress ); +} + +// -- +// extension +// -- + +/* +zzz : review and merge with similar routines _.range.* +*/ + +let ToolsExtension = +{ + + numberClamp : clamp, /* teach it to accept cintervals */ + numberMix : mix, + +} + +Object.assign( _, ToolsExtension ); + +// + +let NumberExtension = +{ + + clamp, + mix, + +} + +Object.assign( _.number, NumberExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Number.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Number_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Number_s */ })(); + +/* */ /* begin of file Object_s */ ( function Object_s() { function Object_s_naked() { ( function _l5_Object_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.object = _.object || Object.create( null ); + +// -- +// dichotomy +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +let ObjectExtension = +{ + +} + +Object.assign( _.object, ObjectExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Object.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Object_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Object_s */ })(); + +/* */ /* begin of file Pair_s */ ( function Pair_s() { function Pair_s_naked() { ( function _l5_Pair_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.pair = _.pair || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +var Extension = +{ +}; + +// + +_.props.supplement( _.pair, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Pair.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Pair_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Pair_s */ })(); + +/* */ /* begin of file Path_s */ ( function Path_s() { function Path_s_naked() { ( function _l5_Path_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.path; + +// -- +// +// -- + +function escape( filePath ) +{ + let self = this; + let splits = self.split( filePath ); + + splits = splits.map( ( split ) => + { + + { + let i = 0; + while( split[ i ] === '"' ) + i += 1; + if( i > 0 ) + split = split.substring( 0, i ) + split; + } + + { + let i = split.length-1; + while( split[ i ] === '"' ) + i -= 1; + if( i < split.length-1 ) + split = split + split.substring( i+1, split.length ); + } + + let left = _.strLeft_( split, self.escapeTokens ) + if( left.entry ) + return `"${split}"`; + return split; + + }); + + return splits.join( self.upToken ); +} + +// -- +// extension +// -- + +let Extension = +{ + escape, +} + +_.props.supplement( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Path.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Path_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Path_s */ })(); + +/* */ /* begin of file Permutation_s */ ( function Permutation_s() { function Permutation_s_naked() { ( function _l5_Permutation_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.permutation = _.permutation || Object.create( null ); + +// -- +// +// -- + +/** + * Routine eachSample() accepts the container {-sets-} with scalar or vector elements. + * Routine returns an array of vectors. Each vector is a unique combination of elements of vectors + * that is passed in option {-sets-}. + * + * Routine eachSample() accepts the options map {-o-} or two arguments. If options map + * is used, all parameters can be set. If passed two arguments, first of them is ( sets ) + * and second is ( onEach ). + * + * Routine eachSample() accepts the callback {-onEach-}. Callback accepts two arguments. The first is + * template {-sample-} and second is index of vector in returned array. Callback can change template {-sample-} + * and corrupt the building of vectors. + * + * @param {Array|Map} sets - Container with vector and scalar elements to combine new vectors. + * @param {Routine|Null} onEach - Callback that accepts template {-sample-} and index of new vector. + * @param {Array|Map} sample - Template for new vectors. If not passed, routine create empty container. + * If sample.length > vector.length, then vector elements replace template elements with the same indexes. + * @param {boolean} leftToRight - Sets the direction of reading {-sets-}. 1 - left to rigth, 0 - rigth to left. By default is 1. + * @param {boolean} result - Sets retuned value. 1 - routine returns array with verctors, 0 - routine returns index of last element. By default is 1. + * + * @example + * var got = _.permutation.eachSample( { sets : [ [ 0, 1 ], 2 ] }); + * console.log( got ); + * // log [ [ 0, 2 ], [ 1, 2 ] ] + * + * @example + * var got = _.permutation.eachSample( { sets : [ [ 0, 1 ], [ 2, 3 ] ], result : 0 }); + * console.log( got ); + * // log 3 + * + * @example + * var got = _.permutation.eachSample( { sets : [ [ 0, 1 ], [ 2, 3 ] ] }); + * console.log( got ); + * // log [ [ 0, 2 ], [ 1, 2 ], + * [ 0, 3 ], [ 1, 3 ] ] + * + * @example + * var got = _.permutation.eachSample( { sets : { a : [ 0, 1 ], b : [ 2, 3 ] } }); + * console.log( got ); + * // log [ { a : 0, b : 2}, { a : 1, b : 2}, + * { a : 0, b : 3}, { a : 1, b : 3} ] + * + * @example + * var got = _.permutation.eachSample( { sets : [ [ 0, 1 ], [ 2, 3 ] ], leftToRight : 0 } ); + * console.log( got ); + * // log [ [ 3, 0 ], [ 2, 0 ], + * [ 3, 1 ], [ 2, 1 ] ] + * + * @example + * var got = _.permutation.eachSample + * ({ + * sets : [ [ 0, 1 ], [ 2, 3 ] ], + * sample : [ 2, 3, 4, 5 ] + * }); + * console.log( got ); + * // log [ [ 3, 0, 4, 5 ], [ 2, 0, 4, 5 ], + * [ 3, 1, 4, 5 ], [ 2, 1, 4, 5 ] ] + * + * @example + * function onEach( sample, i ) + * { + * _.arrayAppend( got, sample[ i ] ); + * } + * var got = []; + * _.permutation.eachSample + * ({ + * sets : [ [ 0, 1 ], [ 2, 3 ] ], + * onEach : onEach, + * sample : [ 'a', 'b', 'c', 'd' ] + * }); + * console.log( got ); + * // log [ 0, 2, 'c', 'd' ] + * + * @function eachSample + * @returns {Array} Returns array contained check function. + * @throws {exception} If ( arguments.length ) is less then one or more then two. + * @throws {exception} If( onEach ) is not a Routine or null. + * @throws {exception} If( o.sets ) is not array or objectLike. + * @throws {exception} If ( sets ) is aixiliary and ( onEach ) not passed. + * @throws {exception} If( o.base ) or ( o.add) is undefined. + * @namespace Tools + */ + +function eachSample( o ) +{ + + if( arguments.length === 2 ) + o = + { + sets : arguments[ 0 ], + onEach : arguments[ 1 ], + } + else if( _.argumentsArray.like( arguments[ 0 ] ) ) + o = + { + sets : arguments[ 0 ], + } + + _.routine.options( eachSample, o ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.routine.is( o.onEach ) || o.onEach === null ); + _.assert( _.longLike( o.sets ) || _.aux.is( o.sets ) ); + _.assert( o.base === undefined && o.add === undefined ); + + if( o.result === null ) + o.result = o.onEach === null; + + /* sample */ + + if( !o.sample ) + o.sample = _.entity.makeUndefined( o.sets ); + + /* */ + + let keys = _.longLike( o.sets ) ? _.longFromRange([ 0, o.sets.length ]) : _.props.keys( o.sets ); + if( _.bool.likeTrue( o.result ) && !_.arrayIs( o.result ) ) + o.result = []; + if( keys.length === 0 ) + return o.result ? o.result : 0; + let len = []; + let indexnd = []; + let index = 0; + let l = _.entity.lengthOf( o.sets ); + + /* sets */ + + let sindex = 0; + let breaking = 0; + + o.sets = _.filter_( null, o.sets, function( set, k ) + { + _.assert( _.longIs( set ) || _.primitive.is( set ) ); + + if( breaking === 0 ) + { + if( _.primitive.is( set ) ) + set = [ set ]; + + if( set.length === 0 ) + breaking = 1; + + len[ sindex ] = _.entity.lengthOf( o.sets[ k ] ); + indexnd[ sindex ] = 0; + sindex += 1; + } + return set; + + }); + + if( breaking === 1 ) + return o.result ? o.result : 0; + + /* */ + + if( !firstSample() ) + return o.result; + + let iterate = o.leftToRight ? iterateLeftToRight : iterateRightToLeft; + do + { + if( o.onEach ) + o.onEach.call( o.sample, o.sample, index ); + } + while( iterate() ); + + if( o.result ) + return o.result; + else + return index; + + /* */ + + function firstSample() + { + let sindex = 0; + + _.each( o.sets, function( e, k ) + { + o.sample[ k ] = o.sets[ k ][ indexnd[ sindex ] ]; + sindex += 1; + if( !len[ k ] ) + return 0; + }); + + if( o.result ) + if( _.aux.is( o.sample ) ) + o.result.push( _.props.extend( null, o.sample ) ); + else + // o.result.push( _.longSlice( o.sample ) ); /* Dmytro : routine _.longSlice is the common interface for slicing of longs */ + o.result.push( _.longSlice( o.sample ) ); + + return 1; + } + + /* */ + + function nextSample( i ) + { + + let k = keys[ i ]; + indexnd[ i ]++; + + if( indexnd[ i ] >= len[ i ] ) + { + indexnd[ i ] = 0; + o.sample[ k ] = o.sets[ k ][ indexnd[ i ] ]; + } + else + { + o.sample[ k ] = o.sets[ k ][ indexnd[ i ] ]; + index += 1; + + if( o.result ) + if( _.aux.is( o.sample ) ) + o.result.push( _.props.extend( null, o.sample ) ); + else + // o.result.push( o.sample.slice() ); + o.result.push( _.longSlice( o.sample ) ); + + return 1; + } + + return 0; + } + + /* */ + + function iterateLeftToRight() + { + for( let i = 0 ; i < l ; i++ ) + if( nextSample( i ) ) + return 1; + + return 0; + } + + /* */ + + function iterateRightToLeft() + { + for( let i = l - 1 ; i >= 0 ; i-- ) + if( nextSample( i ) ) + return 1; + + return 0; + } + +} + +eachSample.defaults = +{ + leftToRight : 1, + onEach : null, + + sets : null, + sample : null, + + result : null, /* was 1 */ +}; + +// + +function eachPermutation( o ) +{ + + _.routine.options( eachPermutation, arguments ); + + if( o.result === null ) + o.result = o.onEach === null; + + if( _.number.is( o.sets ) ) + { + if( o.sets < 0 ) + o.sets = 0; + let sets = Array( o.sets ); + for( let i = o.sets-1 ; i >= 0 ; i-- ) + sets[ i ] = i; + o.sets = sets; + } + + if( _.bool.likeTrue( o.result ) && !_.arrayIs( o.result ) ) + o.result = []; + + const add = ( _.argumentsArray.like( o.result ) || _.routineIs( o.result.push ) ) ? append1 : append0; + const dst = o.result ? o.result : undefined; + const sets = o.sets; + const length = o.sets.length; + const last = length - 1; + const plast = length - 2; + const slast = length - 3; + const iterateAll = o.onEach === null ? iterateWithoutCallback : iterateWithCallback; + let left = last; + let swaps = 0; + let iteration = 0; + + if( length <= 1 ) + { + if( length === 1 ) + { + if( o.onEach ) + o.onEach( sets, iteration, left, last, swaps ); + add(); + } + return; + } + + let iterations = 1; + for( let i = plast-1 ; i >= 0 ; i-- ) + { + iterations *= ( last - i ); + } + iterations *= length; + + let counter = []; + for( let i = plast ; i >= 0 ; i-- ) + counter[ i ] = last-i; + + _.assert( _.longIs( sets ) ); + _.assert( length >= 0 ); + _.assert( length <= 30 ); + + iterateAll(); + + return dst; + + /* */ + + function append0() + { + } + + function append1() + { + dst.push( sets.slice() ); + } + + function swap( left, right ) + { + _.assert( sets[ right ] !== undefined ); + _.assert( sets[ left ] !== undefined ); + let ex = sets[ right ]; + sets[ right ] = sets[ left ]; + sets[ left ] = ex; + } + + function reverse() + { + if( left >= slast ) + { + swaps = 1; + swap( left, last ); + counter[ left ] -= 1; + } + else + { + swaps = last - left; + if( swaps % 2 === 1 ) + swaps -= 1; + swaps /= 2; + for( let i = swaps ; i >= 0 ; i-- ) + swap( left + i, last - i ); + counter[ left ] -= 1; + swaps += 1; + } + } + + function nextCounter() + { + while( counter[ left ] === 0 && left !== 0 ) + left -= 1; + for( let i = left + 1 ; i < counter.length ; i++ ) + counter[ i ] = last - i; + } + + function onEachDefault() + { + } + + function iterateWithoutCallback() + { + + while( iteration < iterations ) + { + add(); + left = plast; + nextCounter(); + reverse(); + iteration += 1; + } + } + + function iterateWithCallback() + { + _.assert( _.routineIs( o.onEach ), 'Expects routine {-o.onEach-}' ); + + while( iteration < iterations ) + { + o.onEach( sets, iteration, left, last, swaps ); + add(); + left = plast; + nextCounter(); + reverse(); + iteration += 1; + } + } + +} + +eachPermutation.defaults = +{ + onEach : null, + sets : null, /* was container */ + result : null, /* was dst */ +} + +/* + +== number:3 + += log + +0 . 2..2 . 0 1 2 +1 . 1..2 . 0 2 1 +2 . 0..2 . 1 2 0 +3 . 1..2 . 1 0 2 +4 . 0..2 . 2 0 1 +5 . 1..2 . 2 1 0 + +== number:4 + += log + +0 . 3..3 . 0 1 2 3 +1 . 2..3 . 0 1 3 2 +2 . 1..3 . 0 2 3 1 +3 . 2..3 . 0 2 1 3 +4 . 1..3 . 0 3 1 2 +5 . 2..3 . 0 3 2 1 + +6 . 0..3 . 1 2 3 0 +7 . 2..3 . 1 2 0 3 +8 . 1..3 . 1 3 0 2 +9 . 2..3 . 1 3 2 0 +10 . 1..3 . 1 0 2 3 +11 . 2..3 . 1 0 3 2 + +12 . 0..3 . 2 3 0 1 +13 . 2..3 . 2 3 1 0 +14 . 1..3 . 2 0 1 3 +15 . 2..3 . 2 0 3 1 +16 . 1..3 . 2 1 3 0 +17 . 2..3 . 2 1 0 3 + +18 . 0..3 . 3 0 1 2 +19 . 2..3 . 3 0 2 1 +20 . 1..3 . 3 1 2 0 +21 . 2..3 . 3 1 0 2 +22 . 1..3 . 3 2 0 1 +23 . 2..3 . 3 2 1 0 + +== number:5 + += count + +120 +24 +6 +2 +1 + +4 +3 +2 + += log + +0 . 4..4 . 0 1 2 3 4 +1 . 3..4 . 0 1 2 4 3 +2 . 2..4 . 0 1 3 4 2 +3 . 3..4 . 0 1 3 2 4 +4 . 2..4 . 0 1 4 2 3 +5 . 3..4 . 0 1 4 3 2 +6 . 1..4 . 0 2 3 4 1 +7 . 3..4 . 0 2 3 1 4 +8 . 2..4 . 0 2 4 1 3 +9 . 3..4 . 0 2 4 3 1 +10 . 2..4 . 0 2 1 3 4 +11 . 3..4 . 0 2 1 4 3 +12 . 1..4 . 0 3 4 1 2 +13 . 3..4 . 0 3 4 2 1 +14 . 2..4 . 0 3 1 2 4 +15 . 3..4 . 0 3 1 4 2 +16 . 2..4 . 0 3 2 4 1 +17 . 3..4 . 0 3 2 1 4 +18 . 1..4 . 0 4 1 2 3 +19 . 3..4 . 0 4 1 3 2 +20 . 2..4 . 0 4 2 3 1 +21 . 3..4 . 0 4 2 1 3 +22 . 2..4 . 0 4 3 1 2 +23 . 3..4 . 0 4 3 2 1 + +24 . 0..4 . 1 2 3 4 0 +25 . 3..4 . 1 2 3 0 4 +26 . 2..4 . 1 2 4 0 3 +27 . 3..4 . 1 2 4 3 0 +28 . 2..4 . 1 2 0 3 4 +29 . 3..4 . 1 2 0 4 3 +30 . 1..4 . 1 3 4 0 2 +31 . 3..4 . 1 3 4 2 0 +32 . 2..4 . 1 3 0 2 4 +33 . 3..4 . 1 3 0 4 2 +34 . 2..4 . 1 3 2 4 0 +35 . 3..4 . 1 3 2 0 4 +36 . 1..4 . 1 4 0 2 3 +37 . 3..4 . 1 4 0 3 2 +38 . 2..4 . 1 4 2 3 0 +39 . 3..4 . 1 4 2 0 3 +40 . 2..4 . 1 4 3 0 2 +41 . 3..4 . 1 4 3 2 0 +42 . 1..4 . 1 0 2 3 4 +43 . 3..4 . 1 0 2 4 3 +44 . 2..4 . 1 0 3 4 2 +45 . 3..4 . 1 0 3 2 4 +46 . 2..4 . 1 0 4 2 3 +47 . 3..4 . 1 0 4 3 2 + +48 . 0..4 . 2 3 4 0 1 +49 . 3..4 . 2 3 4 1 0 +50 . 2..4 . 2 3 0 1 4 +51 . 3..4 . 2 3 0 4 1 +52 . 2..4 . 2 3 1 4 0 +53 . 3..4 . 2 3 1 0 4 +54 . 1..4 . 2 4 0 1 3 +55 . 3..4 . 2 4 0 3 1 +56 . 2..4 . 2 4 1 3 0 +57 . 3..4 . 2 4 1 0 3 +58 . 2..4 . 2 4 3 0 1 +59 . 3..4 . 2 4 3 1 0 +60 . 1..4 . 2 0 1 3 4 +61 . 3..4 . 2 0 1 4 3 +62 . 2..4 . 2 0 3 4 1 +63 . 3..4 . 2 0 3 1 4 +64 . 2..4 . 2 0 4 1 3 +65 . 3..4 . 2 0 4 3 1 +66 . 1..4 . 2 1 3 4 0 +67 . 3..4 . 2 1 3 0 4 +68 . 2..4 . 2 1 4 0 3 +69 . 3..4 . 2 1 4 3 0 +70 . 2..4 . 2 1 0 3 4 +71 . 3..4 . 2 1 0 4 3 +72 . 0..4 . 3 4 0 1 2 +73 . 3..4 . 3 4 0 2 1 +74 . 2..4 . 3 4 1 2 0 +75 . 3..4 . 3 4 1 0 2 +76 . 2..4 . 3 4 2 0 1 +77 . 3..4 . 3 4 2 1 0 +78 . 1..4 . 3 0 1 2 4 +79 . 3..4 . 3 0 1 4 2 +80 . 2..4 . 3 0 2 4 1 +81 . 3..4 . 3 0 2 1 4 +82 . 2..4 . 3 0 4 1 2 +83 . 3..4 . 3 0 4 2 1 +84 . 1..4 . 3 1 2 4 0 +85 . 3..4 . 3 1 2 0 4 +86 . 2..4 . 3 1 4 0 2 +87 . 3..4 . 3 1 4 2 0 +88 . 2..4 . 3 1 0 2 4 +89 . 3..4 . 3 1 0 4 2 +90 . 1..4 . 3 2 4 0 1 +91 . 3..4 . 3 2 4 1 0 +92 . 2..4 . 3 2 0 1 4 +93 . 3..4 . 3 2 0 4 1 +94 . 2..4 . 3 2 1 4 0 +95 . 3..4 . 3 2 1 0 4 +96 . 0..4 . 4 0 1 2 3 +97 . 3..4 . 4 0 1 3 2 +98 . 2..4 . 4 0 2 3 1 +99 . 3..4 . 4 0 2 1 3 +100 . 2..4 . 4 0 3 1 2 +101 . 3..4 . 4 0 3 2 1 +102 . 1..4 . 4 1 2 3 0 +103 . 3..4 . 4 1 2 0 3 +104 . 2..4 . 4 1 3 0 2 +105 . 3..4 . 4 1 3 2 0 +106 . 2..4 . 4 1 0 2 3 +107 . 3..4 . 4 1 0 3 2 +108 . 1..4 . 4 2 3 0 1 +109 . 3..4 . 4 2 3 1 0 +110 . 2..4 . 4 2 0 1 3 +111 . 3..4 . 4 2 0 3 1 +112 . 2..4 . 4 2 1 3 0 +113 . 3..4 . 4 2 1 0 3 +114 . 1..4 . 4 3 0 1 2 +115 . 3..4 . 4 3 0 2 1 +116 . 2..4 . 4 3 1 2 0 +117 . 3..4 . 4 3 1 0 2 +118 . 2..4 . 4 3 2 0 1 +119 . 3..4 . 4 3 2 1 0 + +*/ + +// + +function swapsCount( permutation ) +{ + let counter = 0; + let forward = permutation.slice(); + let backward = []; + for( let i = forward.length-1 ; i >= 0 ; i-- ) + { + backward[ forward[ i ] ] = i; + } + for( let i = backward.length-1 ; i >= 0 ; i-- ) + { + if( backward[ i ] !== i ) + { + let forward1 = forward[ i ]; + let backward1 = backward[ i ]; + forward[ backward1 ] = forward1; + backward[ forward1 ] = backward1; + counter += 1; + } + } + return counter; +} + +// + +/* Calculates the factorial of an integer number ( >= 0 ) */ + +function _factorial( src ) +{ + let result = 1; + while( src > 1 ) + { + result = result * src; + src -= 1; + } + return result; +} + +// + +/** + * @summary Returns factorial for number `src`. + * @description Number `src` + * @param {Number} src Source number. Should be less than 10000. + * @function factorial + * @namespace Tools + * @module wTools + */ + +function factorial( src ) +{ + _.assert( src < 10000 ); + _.assert( _.intIs( src ) ); + _.assert( src >= 0 ); + _.assert( arguments.length === 1, 'Expects single argument' ); + if( src === 0 ) + return 1; + return _.permutation._factorial( src ) +} + +// -- +// extend permutation +// -- + +let PermutationExtension = +{ + + eachSample, /* xxx : review */ + eachPermutation, + swapsCount, + _factorial, + factorial, + +} + +// + +Object.assign( _.permutation, PermutationExtension ); + +// -- +// extend tools +// -- + +let ToolsExtension = +{ + + // eachSample, /* xxx : review */ + // eachPermutation, + // swapsCount, + // _factorial, + factorial, + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Permutation.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Permutation_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Permutation_s */ })(); + +/* */ /* begin of file Primitive_s */ ( function Primitive_s() { function Primitive_s_naked() { ( function _l5_Primitive_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +// + +let PrimitiveExtension = +{ +} + +Object.assign( _.primitive, PrimitiveExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Primitive.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Primitive_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Primitive_s */ })(); + +/* */ /* begin of file Printer_s */ ( function Printer_s() { function Printer_s_naked() { ( function _l5_Printer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.printer = _.printer || Object.create( null ); + +// -- +// printer +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +// + +let Extension = +{ + +} + +Object.assign( Self, Extension ); +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Printer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Printer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Printer_s */ })(); + +/* */ /* begin of file Process_s */ ( function Process_s() { function Process_s_naked() { ( function _l5_Process_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.process = _.process || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// declaration +// -- + +let Extension = +{ + +} + +_.props.supplement( _.process, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Process.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Process_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Process_s */ })(); + +/* */ /* begin of file PropertyTransformer_s */ ( function PropertyTransformer_s() { function PropertyTransformer_s_naked() { ( function _l5_PropertyTransformer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +function mapperFromCondition( routine ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.routine.is( routine ), 'Expects routine but got', _.entity.strType( routine ) ); + _.assert( !!routine.identity ); + + if( routine.identity.propertyCondition ) + { + if( routine.identity.functor ) + { + functor.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + return functor; + } + else + { + mapper.identity = { propertyMapper : true, propertyTransformer : true }; + return mapper; + } + } + else if( routine.identity.propertyMapper ) + { + return routine; + } + else _.assert( 0, 'Expects PropertyTransformer' ); + + function mapper( dstContainer, srcContainer, key ) + { + let result = routine( dstContainer, srcContainer, key ); + _.assert( _.bool.is( result ) ); + if( result === false ) + return; + dstContainer[ key ] = srcContainer[ key ]; + } + + function functor() + { + let routine2 = routine( ... arguments ); + _.assert( _.props.conditionIs( routine2 ) && !routine2.identity.functor ); + mapper.identity = { propertyMapper : true, propertyTransformer : true }; + return mapper; + function mapper( dstContainer, srcContainer, key ) + { + let result = routine2( dstContainer, srcContainer, key ); + _.assert( _.bool.is( result ) ); + if( result === false ) + return; + dstContainer[ key ] = srcContainer[ key ]; + } + } + +} + +// + +function mapperFrom( routine ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.routine.is( routine ), 'Expects routine but got', _.entity.strType( routine ) ); + + if( routine.identity ) + { + if( routine.identity.propertyMapper ) + { + routine.identity.propertyTransformer = true; + return routine; + } + else + { + return _.props.mapperFromCondition( routine ); + } + } + + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; +} + +// + +function conditionFrom( routine ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.routine.is( routine ), 'Expects routine but got', _.entity.strType( routine ) ); + + if( routine.identity ) + { + if( !routine.identity.propertyCondition ) + { + _.assert( !routine.identity.propertyMapper, 'It is not possible to convert FieldMapper to FieldFilter' ); + _.assert( routine.identity.propertyCondition === undefined ); + routine.identity.propertyCondition = true; + } + routine.identity.propertyTransformer = true; + return routine; + } + + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; +} + +// + +function transformerRegister( fi, name ) +{ + + if( !name ) + name = fi.name; + + _.assert( _.strDefined( name ) ); + _.assert( _.object.isBasic( fi.identity ), 'Not property transformer' ); + _.assert( !!fi.identity ); + + if( fi.identity.propertyMapper ) + { + _.assert( _.props.mapper[ name ] === undefined ); + _.props.mapper[ name ] = mapperFrom( fi ); + return; + } + else if( fi.identity.propertyCondition ) + { + _.assert( _.props.condition[ name ] === undefined ); + _.assert( _.props.mapper[ name ] === undefined ); + _.props.mapper[ name ] = _.props.mapperFromCondition( fi ); + _.props.condition[ name ] = fi; + return; + } + else _.assert( 0, 'unexpected' ); + +} + +// + +function transformersRegister( transformers ) +{ + + _.assert( _.mapIs( transformers ) ); + + for( let f in transformers ) + { + let fi = transformers[ f ]; + + // if( fi.length ) + // debugger; + // if( fi.length ) /* xxx*/ + // continue; + // fi = fi(); + + _.assert( !!fi.identity && !!fi.identity.functor, `Routine::${f} is not functor` ); + _.props.transformerRegister( fi, f ); + } + +} + +// + +function transformerUnregister( transformerName, transformerType ) +{ + transformerType = transformerType || 'mapper'; + + _.assert( _.strIs( transformerName ) ); + _.assert( _.strIs( transformerType ) ); + _.assert( _.props[ transformerType ][ transformerName ] !== undefined, 'Transformer must be registered' ); + + delete _.props[ transformerType ][ transformerName ]; + return; +} + +// + +function transformersUnregister( transformerNames, transformerType ) +{ + _.assert( _.arrayIs( transformerNames ) ); + _.assert( _.strIs( transformerType ) ); + + transformerNames.forEach( ( transformerName ) => _.props.transformerUnregister( transformerName, transformerType ) ) + return; +} + +// + +function transformerIs( transformer ) +{ + if( !_.routine.is( transformer ) ) + return false; + if( !_.object.isBasic( transformer.identity ) ) + return false; + + let result = + ( + !!( transformer.identity.propertyTransformer + || transformer.identity.propertyCondition + || transformer.identity.propertyMapper ) + ); + + return result; +} + +// + +function mapperIs( transformer ) +{ + if( !_.routine.is( transformer ) ) + return false; + if( !_.object.isBasic( transformer.identity ) ) + return false; + return !!transformer.identity.propertyMapper; +} + +// + +function conditionIs( transformer ) +{ + if( !_.routine.is( transformer ) ) + return false; + if( !_.object.isBasic( transformer.identity ) ) + return false; + return !!transformer.identity.propertyCondition; +} + +// -- +// extend +// -- + +let PropsExtension = +{ + + mapperFromCondition, + mapperFrom, + conditionFrom, + transformerRegister, + transformersRegister, + transformerUnregister, + transformersUnregister, + transformerIs, + mapperIs, + conditionIs, + +} + +Object.assign( _.props, PropsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/PropertyTransformer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, PropertyTransformer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file PropertyTransformer_s */ })(); + +/* */ /* begin of file Props_s */ ( function Props_s() { function Props_s_naked() { ( function _l5_Property_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.props = _.props || Object.create( null ); + +// -- +// implementation +// -- + +// function identical( src1, src2 ) +// { +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// _.assert( !_.primitive.is( src1 ) ); +// _.assert( !_.primitive.is( src2 ) ); +// +// if( Object.keys( src1 ).length !== Object.keys( src2 ).length ) +// return false; +// +// for( let s in src1 ) +// { +// if( src1[ s ] !== src2[ s ] ) +// return false; +// } +// +// return true; +// } + +// + +function hasAll( src, screen ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( !_.primitive.is( src ) ); + _.assert( !_.primitive.is( screen ) ); + + if( _.argumentsArray.like( screen ) ) + { + for( let s = 0 ; s < screen.length ; s++ ) + if( !( screen[ s ] in src ) ) + return false; + } + else if( _.vector.is( screen ) ) + { + for( let value of screen ) + if( !( value in src ) ) + return false; + } + else if( _.aux.is( screen ) ) + { + for( let k in screen ) + if( !( k in src ) ) + return false; + } + + return true; + +} + +// + +function hasAny( src, screen ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( !_.primitive.is( src ) ); + _.assert( !_.primitive.is( screen ) ); + + if( _.argumentsArray.like( screen ) ) + { + for( let s = 0 ; s < screen.length ; s++ ) + if( screen[ s ] in src ) + return true; + } + else if( _.vector.is( screen ) ) + { + for( let value of screen ) + if( value in src ) + return true; + } + else if( _.aux.is( screen ) ) + { + for( let k in screen ) + if( k in src ) + return true; + } + + return false; +} + +// + +function hasNone( src, screen ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( !_.primitive.is( src ) ); + _.assert( !_.primitive.is( screen ) ); + + if( _.argumentsArray.like( screen ) ) + { + for( let s = 0 ; s < screen.length ; s++ ) + if( screen[ s ] in src ) + return false; + } + else if( _.vector.is( screen ) ) + { + for( let value of screen ) + if( value in src ) + return false; + } + else if( _.aux.is( screen ) ) + { + for( let k in screen ) + if( k in src ) + return false; + } + + return true; +} + +// // -- +// // property implicit +// // -- +// +// const prototypeSymbol = Symbol.for( 'prototype' ); +// const constructorSymbol = Symbol.for( 'constructor' ); +// +// _.assert( _.props.implicit === undefined ); +// _.assert( _.props.Implicit === undefined ); +// _.props.implicit = _.wrap.declare({ name : 'Implicit' }).namespace; +// _.props.Implicit = _.props.implicit.class; +// _.assert( _.mapIs( _.props.implicit ) ); +// _.assert( _.routineIs( _.props.Implicit ) ); +// +// _.props.implicit.prototype = new _.props.Implicit( prototypeSymbol ); +// _.props.implicit.constructor = new _.props.Implicit( constructorSymbol ); + +// -- +// extension +// -- + +let Extension = +{ + + // identical, + hasAll, + hasAny, + hasNone, + +} + +// + +Object.assign( _.props, Extension ); +// _.assert( _.routine.is( _.props.filterWithEscape ) ); debugger; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Props.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Props_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Props_s */ })(); + +/* */ /* begin of file Prototype_s */ ( function Prototype_s() { function Prototype_s_naked() { ( function _l5_Prototype_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.prototype = _.prototype || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +var Extension = +{ +} + +// + +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Prototype.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Prototype_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Prototype_s */ })(); + +/* */ /* begin of file Regexp_s */ ( function Regexp_s() { function Regexp_s_naked() { ( function _l5_Regexp_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +// const Self = _global_.wTools; +_.regexp = _.regexp || Object.create( null ); +_.regexp.s = _.regexp.s || Object.create( null ); + +// -- +// regexp +// -- + +function regexpsEquivalent( src1, src2 ) +{ + + _.assert( _.strIs( src1 ) || _.regexpIs( src1 ) || _.longIs( src1 ), 'Expects string/regexp or array of strings/regexps {-src1-}' ); + _.assert( _.strIs( src2 ) || _.regexpIs( src2 ) || _.longIs( src2 ), 'Expects string/regexp or array of strings/regexps {-src2-}' ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + let isLong1 = _.longIs( src1 ); + let isLong2 = _.longIs( src2 ); + + if( isLong1 && isLong2 ) + { + let result = []; + _.assert( src1.length === src2.length ); + for( let i = 0, len = src1.length ; i < len; i++ ) + { + result[ i ] = _.regexp.equivalent( src1[ i ], src2[ i ] ); + } + return result; + } + else if( !isLong1 && isLong2 ) + { + let result = []; + for( let i = 0, len = src2.length ; i < len; i++ ) + { + result[ i ] = _.regexp.equivalent( src1, src2[ i ] ); + } + return result; + } + else if( isLong1 && !isLong2 ) + { + let result = []; + for( let i = 0, len = src1.length ; i < len; i++ ) + { + result[ i ] = _.regexp.equivalent( src1[ i ], src2 ); + } + return result; + } + else + { + return _.regexp.equivalent( src1, src2 ); + } + +} + +// + +function _test( regexp, str ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.regexpLike( regexp ) ); + _.assert( _.strIs( str ) ); + + if( _.strIs( regexp ) ) + return regexp === str; + else + return regexp.test( str ); + +} + +// + +function test( regexp, strs ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.regexpLike( regexp ) ); + + if( _.strIs( strs ) ) + return _.regexp._test( regexp, strs ); + else if( _.argumentsArray.like( strs ) ) + return strs.map( ( str ) => _.regexp._test( regexp, str ) ) + else _.assert( 0 ); + +} + +// + +function testAll( regexp, strs ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.regexpLike( regexp ) ); + + if( _.strIs( strs ) ) + return _.regexp._test( regexp, strs ); + else if( _.argumentsArray.like( strs ) ) + return strs.every( ( str ) => _.regexp._test( regexp, str ) ) + else _.assert( 0 ); + +} + +// + +function testAny( regexp, strs ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.regexpLike( regexp ) ); + + if( _.strIs( strs ) ) + return _.regexp._test( regexp, strs ); + else if( _.argumentsArray.like( strs ) ) + return strs.some( ( str ) => _.regexp._test( regexp, str ) ) + else _.assert( 0 ); + +} + +// + +function testNone( regexp, strs ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.regexpLike( regexp ) ); + + if( _.strIs( strs ) ) + return !_.regexp._test( regexp, strs ); + else if( _.argumentsArray.like( strs ) ) + return !strs.some( ( str ) => _.regexp._test( regexp, str ) ) + else _.assert( 0 ); + +} + +// + +function regexpsTestAll( regexps, strs ) +{ + _.assert( arguments.length === 2 ); + + if( !_.arrayIs( regexps ) ) + return _.regexpTestAll( regexps, strs ); + + _.assert( _.regexpsLikeAll( regexps ) ); + + return regexps.every( ( regexp ) => _.regexpTestAll( regexp, strs ) ); +} + +// + +function regexpsTestAny( regexps, strs ) +{ + _.assert( arguments.length === 2 ); + + if( !_.arrayIs( regexps ) ) + return _.regexpTestAny( regexps, strs ); + + _.assert( _.regexpsLikeAll( regexps ) ); + + return regexps.some( ( regexp ) => _.regexpTestAny( regexp, strs ) ); +} + +// + +function regexpsTestNone( regexps, strs ) +{ + _.assert( arguments.length === 2 ); + + if( !_.arrayIs( regexps ) ) + return _.regexpTestNone( regexps, strs ); + + _.assert( _.regexpsLikeAll( regexps ) ); + + return regexps.every( ( regexp ) => _.regexpTestNone( regexp, strs ) ); +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + + regexpsEquivalent : regexpsEquivalent, + regexpsEquivalentAll : _.vectorizeAll( _.regexp.equivalentShallow.bind( _.regexp ), 2 ), + regexpsEquivalentAny : _.vectorizeAny( _.regexp.equivalentShallow.bind( _.regexp ), 2 ), + regexpsEquivalentNone : _.vectorizeNone( _.regexp.equivalentShallow.bind( _.regexp ), 2 ), + + regexpsEscape : _.vectorize( _.regexpEscape ), + + _regexpTest : _test, + regexpTest : test, + + regexpTestAll : testAll, + regexpTestAny : testAny, + regexpTestNone : testNone, + + regexpsTestAll, + regexpsTestAny, + regexpsTestNone, + + +} + +_.props.supplement( _, ToolsExtension ); /* qqq for junior : create namespace _.regexp. stand-alone PR | aaa : Done. */ + +// + +let RegexpExtension = +{ + + // regexp + + _test, + test, + + testAll, + testAny, + testNone, + +} + +_.props.supplement( _.regexp, RegexpExtension ); + +// + +let RegexpsExtension = +{ + + // regexps + + regexpsEquivalent, + + escape : _.vectorize( _.regexpEscape ), + + testAll : regexpsTestAll, + testAny : regexpsTestAny, + testNone : regexpsTestNone, + +} + +// + +_.props.supplement( _.regexp.s, RegexpsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Regexp.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Regexp_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Regexp_s */ })(); + +/* */ /* begin of file Routine_s */ ( function Routine_s() { function Routine_s_naked() { ( function _l5_Routine_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// extension +// -- + +let RoutineExtension = +{ + +} + +// + +Object.assign( _.routine, RoutineExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Routine.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Routine_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Routine_s */ })(); + +/* */ /* begin of file Set_s */ ( function Set_s() { function Set_s_naked() { ( function _l5_Set_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +function butElement( dst, src1, element ) +{ + + if( dst === null ) + dst = new Set(); + else if( dst === _.self ) + dst = src1; + + _.assert( arguments.length === 3 ); + _.assert( _.set.is( dst ) || dst === null ); + _.assert( _.countable.is( src1 ) ); + + if( dst === src1 ) + { + dst.delete( element ); + } + else + { + for( let e of src1 ) + if( e !== element ) + dst.add( e ); + } + + return dst; +} + +// + +/* qqq : cover */ +/* qqq : add test cases src1/src2 is set/countable/array/unrolls */ +function but( dst, src1, src2 ) +{ + + if( dst === null ) + dst = new Set(); + else if( dst === _.self ) + dst = src1; + + _.assert( arguments.length === 3 ); + _.assert( _.set.is( dst ) || dst === null ); + _.assert( _.countable.is( src1 ) ); + _.assert( _.countable.is( src2 ) ); + + if( dst === src1 ) + { + for( let e of src2 ) + if( dst.has( e ) ) + dst.delete( e ); + } + else + { + if( !_.set.is( src2 ) ) + src2 = [ ... src2 ]; + for( let e of src1 ) + if( !src2.has( e ) ) + dst.add( e ); + } + + return dst; +} + +// + +/* qqq : cover */ +/* qqq : src1 could be countable or unroll */ +/* qqq : src2 could be countable or unroll */ +function only( dst, src1, src2 ) +{ + // if( arguments.length === 2 ) + // { + // dst = null; + // src1 = arguments[ 0 ]; + // src2 = arguments[ 1 ]; + // } + + _.assert( arguments.length === 3 ); + _.assert( dst === null || _.set.is( dst ) ); + _.assert( _.countable.is( src1 ) ); + _.assert( _.countable.is( src2 ) ); + + if( dst === null ) + dst = new Set(); + + for( let e of src1 ) + if( src2.has( e ) ) + dst.add( e ); + + return dst; +} + +// + +/* qqq : cover */ +/* qqq : src1 could be countable or unroll */ +/* qqq : src2 could be countable or unroll */ +function union( dst, src1, src2 ) +{ + + // if( arguments.length === 2 ) + // { + // dst = null; + // src1 = arguments[ 0 ]; + // src2 = arguments[ 1 ]; + // } + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( dst === null || _.set.is( dst ) ); + _.assert( _.countable.is( src1 ) ); + _.assert( _.countable.is( src2 ) ); + + if( dst === null ) + dst = new Set(); + + if( _.unrollIs( src1 ) ) + { + _.assert( 0, 'not implemented' ); + for( let set of src1 ) + { + _.assert( _.set.is( set ) ); + for( let e of set ) + dst.add( e ); + } + } + else + { + for( let e of src1 ) + dst.add( e ); + } + + if( src2 !== undefined ) + if( _.unrollIs( src2 ) ) + { + xxx + for( let set of src2 ) + { + _.assert( _.set.is( set ) ); + for( let e of set ) + dst.add( e ); + } + } + else + { + for( let e of src2 ) + dst.add( e ); + } + + return dst; +} + +// + +/* qqq : cover */ +function diff( dst, src1, src2 ) +{ + + if( arguments.length === 2 ) + { + dst = null; + src1 = arguments[ 0 ]; + src2 = arguments[ 1 ]; + } + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( dst === null || _.aux.is( dst ) ); + _.assert( _.set.is( src1 ) ); + _.assert( _.set.is( src2 ) ); + + dst = dst || Object.create( null ); + dst.src1 = _.set.but( dst.src1 || null, src1, src2 ); + dst.src2 = _.set.but( dst.src2 || null, src2, src1 ); + dst.diff = new Set([ ... dst.src1, ... dst.src2 ]); + dst.identical = dst.src1.size === 0 && dst.src2.size === 0; + + return dst; +} + +// + +function appendContainer( dst, src ) +{ + if( dst === null ) + dst = new Set; + + _.assert( arguments.length === 2 ); + + if( _.countable.is( src ) ) + { + dst.add( ... src ); + } + else + { + dst.add( src ); + } + + return dst; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +// + +let SetExtension = +{ + + /* xxx2 : review */ + butElement, + but, + only, + union, + diff, + + appendContainer, + +} + +Object.assign( _.set, SetExtension ); + +// + +let SetsExtension = +{ + +} + +// + +Object.assign( _.set.s, SetsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Set.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Set_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Set_s */ })(); + +/* */ /* begin of file Sorted_s */ ( function Sorted_s() { function Sorted_s_naked() { ( function _l5_Sorted_s_() +{ + +'use strict'; + +// + +const _global = _global_; +const _ = _global_.wTools; +_.sorted = _.sorted || Object.create( null ); + +// -- +// implementation +// -- + +function searchFirstIndex( srcArr, ins ) +{ + let l = 0; + let r = srcArr.length; + let m; + if( srcArr.length ) + + do + { + m = Math.floor( ( l + r ) / 2 ); + if( srcArr[ m ] < ins ) + l = m+1; + else if( srcArr[ m ] > ins ) + r = m; + else + return m; + } + while( l < r ); + if( srcArr[ m ] < ins ) + return m+1; + + return m; +} + +// -- +// extension +// -- + +let Extension = +{ + + searchFirstIndex, + // searchFirst, + +} + +_.props.supplement( _.sorted, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Sorted.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Sorted_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Sorted_s */ })(); + +/* */ /* begin of file Str_s */ ( function Str_s() { function Str_s_naked() { ( function _l5_Str_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// exporter +// -- + +function _exportStringDiagnosticShallow( src, o ) +{ + return src; +} + +// + +function exportStringDiagnosticShallow( src, o ) +{ + let result; + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects 1 or 2 arguments' ); + _.assert( this.like( src ) ); + return this._exportStringDiagnosticShallow( ... arguments ); +} + +// + +function _exportStringCodeShallow( src, o ) +{ + return `'${src}'`; +} + +// + +function exportStringCodeShallow( src, o ) +{ + let result; + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects 1 or 2 arguments' ); + _.assert( this.like( src ) ); + return this._exportStringCodeShallow( ... arguments ); +} + +// -- +// decorator +// -- + +function quote( o ) +{ + + if( !_.mapIs( o ) ) + o = { src : arguments[ 0 ], quote : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + if( o.quote === undefined || o.quote === null ) + o.quote = quote.defaults.quote; + _.map.assertHasOnly( o, quote.defaults ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( _.arrayIs( o.src ) ) + { + let result = []; + for( let s = 0 ; s < o.src.length ; s++ ) + result.push( _.strQuote({ src : o.src[ s ], quote : o.quote }) ); + return result; + } + + let src = o.src; + + if( !_.primitive.is( src ) ) + src = _.entity.exportString( src ); + + _.assert( _.primitive.is( src ) ); + + let result = o.quote + String( src ) + o.quote; + + return result; +} + +quote.defaults = +{ + src : null, + quote : '"', +} + +// + +function unquote( o ) +{ + + if( !_.mapIs( o ) ) + o = { src : arguments[ 0 ], quote : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + if( o.quote === undefined || o.quote === null ) + o.quote = unquote.defaults.quote; + _.map.assertHasOnly( o, unquote.defaults ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( _.arrayIs( o.src ) ) + { + let result = []; + for( let s = 0 ; s < o.src.length ; s++ ) + result.push( _.strUnquote({ src : o.src[ s ], quote : o.quote }) ); + return result; + } + + let result = o.src; + let isolated = _.strIsolateInside( result, o.quote ); + if( isolated[ 0 ] === '' && isolated[ 4 ] === '' ) + result = isolated[ 2 ]; + + return result; +} + +unquote.defaults = +{ + src : null, + quote : [ '"', '`', '\'' ], +} + +// + +/** + * The routine `strQuotePairsNormalize` analyzes source String or Array and creates an Array of arrays of pairs of quotes. + * Returns an array with arrays of pairs of quotes. + * + * @param { String|Array|_.bool.likeTrue } quote - + * String : String to add matching pairs to. + * _.bool.likeTrue : Returnes an array of arrays of 2 elements ( 3 types of quotes: ', ", ` ). + * Array of strings : Creates matching quotes for strings. + * Array of arrays of strings : Checks to be exactly 2 elements in array & adds them to the result array. + * + * @example + * _.strQuotePairsNormalize( true ); + * // returns + * [ + * [ '"', '"' ], + * [ '`', '`' ], + * [ '\'', '\'' ] + * ] + * + * @example + * _.strQuotePairsNormalize( '' ); + * // returns [ [ '', '' ] ] + * + * @example + * _.strQuotePairsNormalize( 'str' ); + * // returns [ [ 'str', 'str' ] ] + * + * @example + * _.strQuotePairsNormalize( [ '', ' ', '\n', 'str' ] ); + * // returns + * [ + * [ '', '' ], + * [ ' ', ' ' ], + * [ '\n', '\n' ], + * [ 'str', 'str' ] + * ] + * + * @example + * _.strQuotePairsNormalize( [ [ '', '' ], [ ' ', ' ' ], [ '\n', '\n' ], [ 'str', 'str' ] ] ) + * // returns + * [ + * [ '', '' ], + * [ ' ', ' ' ], + * [ '\n', '\n' ], + * [ 'str', 'str' ] + * ] + * + * @example + * _.strQuotePairsNormalize( [ [ '', '' ], '', [ ' ', ' ' ], '""', [ '\n', '\n' ], '\t', [ 'str', 'str' ], 'src' ] ) + * // returns + * [ + * [ '', '' ], [ '', '' ], + * [ ' ', ' ' ], [ '""', '""' ], + * [ '\n', '\n' ], [ '\t', '\t' ], + * [ 'str', 'str' ], [ 'src', 'src' ] + * ] + * + * @returns { Array } Returns an array of arrays with pair of quotes. + * @throws { Exception } If { -quote- } is not of String or Array type. + * @throws { Exception } If { -quote- } is of Array type and includes an array with not exactly 2 elements. + * @throws { Exception } If ( arguments.length ) is not exactly equals 1. + * @function quotePairsNormalize + * @namespace Tools + */ + +function quotePairsNormalize( quote ) +{ + + if( ( _.bool.like( quote ) && quote ) ) + quote = quoteAnalyze.defaults.quote; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( quote ) || _.arrayIs( quote ) ); + + quote = _.array.as( quote ); + for( let q = 0 ; q < quote.length ; q++ ) + { + let quotingPair = quote[ q ]; + _.assert( _.pair.is( quotingPair ) || _.strIs( quotingPair ) ); + if( _.strIs( quotingPair ) ) + quotingPair = quote[ q ] = [ quotingPair, quotingPair ]; + _.assert( _.strIs( quotingPair[ 0 ] ) && _.strIs( quotingPair[ 1 ] ) ); + } + + return quote; +} + +// + +/** + * The routine `strQuoteAnalyze` analyzes source string and quotes within it. + * Returns a map with 2 arrays: + * ranges - indexes of quotes in a source string, + * quotes - types of quotes used in a source string. + * + * @param { Object } o - Options map. + * @param { String } src - Source string to analyze. + * @param { String } quote - Quotes to be found in a source string. + * + * @example + * _.strQuoteAnalyze( 'a b c' ); + * // returns { ranges : [], quotes : [] } + * + * @example + * _.strQuoteAnalyze( '"a b" c' ); + * // returns { ranges : [ 0, 4 ], quotes : [ '"' ] } + * + * @example + * _.strQuoteAnalyze( '`a `"b c"`' ); + * // returns { ranges : [ 0, 3, 4, 8 ], quotes : [ '`', '"' ] } + * + * @example + * _.strQuoteAnalyze('""`a `"""b c"``""' ); + * // returns { ranges : [ 0, 1, 2, 5, 6, 7, 8, 12, 13, 14, 15, 16 ], quotes : [ '"', '`', '"', '"', '`', '"' ] } + * + * @example + * _.strQuoteAnalyze( "a', b'`,c` \"", [ [ '\'', '\'' ], '`' ] ) + * // returns { ranges : [ 1, 5, 6, 9 ], quotes : [ "'", "`" ] } + * + * @example + * _.strQuoteAnalyze( "--aa-- --bb--``''\"\",,cc,,", '--' ) + * // returns { ranges : [ 0, 4, 7, 11 ], quotes : [ '--', '--' ] } + * + * @returns { Object } Returns a map with 2 arrays: ranges, quotes. + * @throws { Exception } If redundant arguments are provided. + * @throws { Exception } If ( arguments.length ) is not equal 1 or 2. + * @function quoteAnalyze + * @namespace Tools + */ + +function quoteAnalyze( o ) +{ + let i = -1; + let result = Object.create( null ); + result.ranges = []; + result.quotes = []; + + if( !_.mapIs( o ) ) + o = { src : arguments[ 0 ], quote : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + if( o.quote === undefined || o.quote === null ) + o.quote = quoteAnalyze.defaults.quote; + _.map.assertHasOnly( o, quoteAnalyze.defaults ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + o.quote = _.strQuotePairsNormalize( o.quote ); + let maxQuoteLength = 0; + for( let q = 0 ; q < o.quote.length ; q++ ) + { + let quotingPair = o.quote[ q ]; + maxQuoteLength = Math.max( maxQuoteLength, quotingPair[ 0 ].length, quotingPair[ 1 ].length ); + } + + let isEqual = maxQuoteLength === 1 ? isEqualChar : isEqualString; + let inRange = false + do + { + while( i < o.src.length ) + { + i += 1; + + if( inRange ) + { + if( isEqual( inRange ) ) + { + result.ranges.push( i ); + inRange = false; + } + continue; + } + + for( let q = 0 ; q < o.quote.length ; q++ ) + { + let quotingPair = o.quote[ q ]; + if( isEqual( quotingPair[ 0 ] ) ) + { + result.quotes.push( quotingPair[ 0 ] ); + result.ranges.push( i ); + inRange = quotingPair[ 1 ]; + break; + } + } + } + + if( inRange ) + { + result.quotes.pop(); + i = result.ranges.pop()+1; + inRange = false; + } + + } + while( i < o.src.length ); + + return result; + + function isEqualChar( quote ) + { + _.assert( o.src.length >= i ); + if( o.src[ i ] === quote ) + return true; + return false; + } + + function isEqualString( quote ) + { + if( i+quote.length > o.src.length ) + return false; + let subStr = o.src.substring( i, i+quote.length ); + if( subStr === quote ) + return true; + return false; + } + +} + +quoteAnalyze.defaults = +{ + src : null, + quote : [ '"', '`', '\'' ], +} + +// -- +// splitter +// -- + +function _leftSingle_( src, ins, cinterval ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( _.strIs( src ) ); + + if( _.number.is( cinterval ) ) + cinterval = [ cinterval, src.length - 1 ]; + else if( cinterval === undefined ) + cinterval = [ 0, src.length - 1 ]; + + cinterval[ 0 ] = cinterval[ 0 ] === undefined ? 0 : cinterval[ 0 ]; + cinterval[ 1 ] = cinterval[ 1 ] === undefined ? src.length - 1 : cinterval[ 1 ]; + + if( cinterval[ 0 ] < 0 ) + cinterval[ 0 ] = src.length + cinterval[ 0 ]; + if( cinterval[ 1 ] < -1 ) + cinterval[ 1 ] = src.length + cinterval[ 1 ]; + + _.assert( _.intervalIs( cinterval ) ); + _.assert( 0 <= cinterval[ 0 ] && cinterval[ 0 ] <= src.length ); + _.assert( -1 <= cinterval[ 1 ] && cinterval[ 1 ] <= src.length - 1 ); + + let result = Object.create( null ); + result.index = src.length; + result.instanceIndex = -1; + result.entry = undefined; + + let src1 = src.substring( cinterval[ 0 ], cinterval[ 1 ] + 1 ); + + ins = _.array.as( ins ); + + for( let k = 0 ; k < ins.length ; k++ ) + { + let entry = ins[ k ]; + if( _.strIs( entry ) ) + { + let found = src1.indexOf( entry ); + if( found >= 0 && ( found < result.index || result.entry === undefined ) ) + { + result.instanceIndex = k; + result.index = found; + result.entry = entry; + } + } + else if( _.regexpIs( entry ) ) + { + let found = src1.match( entry ); + if( found && ( found.index < result.index || result.entry === undefined ) ) + { + result.instanceIndex = k; + result.index = found.index; + result.entry = found[ 0 ]; + } + } + else _.assert( 0, 'Expects string-like ( string or regexp )' ); + } + + if( cinterval[ 0 ] !== 0 && result.index !== src.length ) + result.index += cinterval[ 0 ]; + + return result; +} + +// + +function left_( src, ins, cinterval ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( _.argumentsArray.like( src ) ) + { + let result = []; + for( let s = 0 ; s < src.length ; s++ ) + result[ s ] = _._strLeftSingle_( src[ s ], ins, cinterval ); + return result; + } + else + { + return _._strLeftSingle_( src, ins, cinterval ); + } + +} + +// + +function _rightSingle_( src, ins, cinterval ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( _.strIs( src ) ); + + if( _.number.is( cinterval ) ) + cinterval = [ cinterval, src.length - 1 ]; + else if( cinterval === undefined ) + cinterval = [ 0, src.length - 1 ]; + + cinterval[ 0 ] = cinterval[ 0 ] === undefined ? 0 : cinterval[ 0 ]; + cinterval[ 1 ] = cinterval[ 1 ] === undefined ? src.length - 1 : cinterval[ 1 ]; + + if( cinterval[ 0 ] < 0 ) + cinterval[ 0 ] = src.length + cinterval[ 0 ]; + if( cinterval[ 1 ] < -1 ) + cinterval[ 1 ] = src.length + cinterval[ 1 ]; + + _.assert( _.intervalIs( cinterval ) ); + _.assert( 0 <= cinterval[ 0 ] && cinterval[ 0 ] <= src.length ); + _.assert( -1 <= cinterval[ 1 ] && cinterval[ 1 ] <= src.length - 1 ); + + let olength = src.length; + + let result = Object.create( null ); + result.index = -1; + result.instanceIndex = -1; + result.entry = undefined; + + let src1 = src.substring( cinterval[ 0 ], cinterval[ 1 ] + 1 ); + + ins = _.array.as( ins ); + + for( let k = 0, len = ins.length ; k < len ; k++ ) + { + let entry = ins[ k ]; + if( _.strIs( entry ) ) + { + let found = src1.lastIndexOf( entry ); + if( found >= 0 && found > result.index ) + { + result.instanceIndex = k; + result.index = found; + result.entry = entry; + } + } + else if( _.regexpIs( entry ) ) + { + + let regexp1 = _.regexpsJoin([ '.*', '(', entry, ')' ]); + let match1 = src1.match( regexp1 ); + if( !match1 ) + continue; + + let regexp2 = _.regexpsJoin([ entry, '(?!(?=.).*', entry, ')' ]); + let match2 = src1.match( regexp2 ); + _.assert( !!match2 ); + + let found; + let found1 = match1[ 1 ]; + let found2 = match2[ 0 ]; + let index; + let index1 = match1.index + match1[ 0 ].length; + let index2 = match2.index + match2[ 0 ].length; + + if( index1 === index2 ) + { + if( found1.length < found2.length ) + { + found = found2; + index = index2 - found.length; + } + else + { + found = found1; + index = index1 - found.length; + } + } + else if( index1 < index2 ) + { + found = found2; + index = index2 - found.length; + } + else + { + found = found1; + index = index1 - found.length; + } + + if( index > result.index ) + { + result.instanceIndex = k; + result.index = index; + result.entry = found; + } + + } + else _.assert( 0, 'Expects string-like ( string or regexp )' ); + } + + if( cinterval[ 0 ] !== 0 && result.index !== -1 ) + result.index += cinterval[ 0 ]; + + return result; +} + +// + +function right_( src, ins, cinterval ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( _.argumentsArray.like( src ) ) + { + let result = []; + for( let s = 0 ; s < src.length ; s++ ) + result[ s ] = _._strRightSingle_( src[ s ], ins, cinterval ); + return result; + } + else + { + return _._strRightSingle_( src, ins, cinterval ); + } + +} + +// + +/** + * Routine strInsideOf() returns part of a source string {-src-} between first occurrence of {-begin-} and last occurrence of {-end-}. + * Returns result if {-begin-} and {-end-} exists in the {-src-} and index of {-end-} is bigger the index of {-begin-}. + * Otherwise returns undefined. + * + * @example + * _.strInsideOf({ src : 'abcd', begin : 'a', end : 'd', pairing : 0 }); + * // returns : 'bc' + * + * @example + * _.strInsideOf({ src : 'abcd', begin : 'a', end : 'd', pairing : 1 }); + * // returns : undefined + * + * @example + * // index of begin is bigger then index of end + * _.strInsideOf( 'abcd', 'c', 'a' ) + * // returns : undefined + * + * @example + * _.strInsideOf( 'abc', 'a', 'a' ); + * // returns : undefined + * + * @example + * _.strInsideOf( 'abcd', 'x', 'y' ) + * // returns : undefined + * + * @example + * _.strInsideOf( 'a', 'a', 'a' ); + * // returns : 'a' + * + * Basic parameter set : + * @param { String } src - The source string. + * @param { String|Array } begin - String or array of strings to find from begin of source. + * @param { String|Array } end - String or array of strings to find from end source. + * Alternative parameter set : + * @param { String } o - Options map. + * @param { String } o.src - The source string. + * @param { String|Array } o.begin - String or array of strings to find from begin of source. + * @param { String|Array } o.end - String or array of strings to find from end source. + * @param { BoolLike } o.pairing - If option is enabled and {-begin-} ( or {-end-} ) is an Array of strings, then + * both containerized {-begin-} and {-end-} should have equivalent lengths. + * @returns { String|Undefined } - Returns part of source string between {-begin-} and {-end-} or undefined. + * @throws { Exception } If arguments.length is 1 and argument is not an options map {-o-}. + * @throws { Exception } If arguments.length is 3 and any of arguments is not a String. + * @throws { Exception } If arguments.length neither is 1 nor 3. + * @throws { Exception } If {-o.pairing-} is true like and containerized version of {-o.begin-} and {-o.end-} + * have different length. + * @throws { Exception } If options map {-o-} has unknown properties. + * @function strInsideOf + * @namespace Tools + */ + +function strInsideOf_head( routine, args ) +{ + + let o = args[ 0 ] + if( _.mapIs( o ) ) + { + _.assert( args.length === 1, 'Expects exactly one argument' ); + } + else + { + o = Object.create( null ); + o.src = args[ 0 ]; + o.begin = args[ 1 ]; + o.end = args[ 2 ]; + _.assert( args.length === 3, 'Expects exactly three arguments' ); + } + + _.routine.options( routine, o ); + _.assert( _.strIs( o.src ), 'Expects string {-o.src-}' ); + + // if( _.longIs( o.begin ) && o.begin.length === 1 ) + // o.begin = o.begin[ 0 ]; + // if( _.longIs( o.end ) && o.end.length === 1 ) + // o.end = o.end[ 0 ]; + if( _.longIs( o.begin || _.longIs( o.end )) ) + { + o.begin = _.array.as( o.begin ); + o.end = _.array.as( o.end ); + } + + _.assert + ( + !o.pairing || !_.longIs( o.begin ) || o.begin.length === o.end.length, + `If option::o.paring is true then length of o.begin should be equal to length of o.end` + ); + + return o; +} + +function strInsideOf_body( o ) +{ + let beginOf, endOf; + + beginOf = _.strBeginOf( o.src, o.begin ); + if( beginOf === undefined ) + return undefined; + + endOf = _.strEndOf( o.src, o.end ); + if( endOf === undefined ) + return undefined; + + if( o.pairing && _.longIs( o.begin ) ) + { + let beginIndex = _.longLeftIndex( o.begin, beginOf ); + let endIndex = _.longLeftIndex( o.end, endOf ); + + if( beginIndex !== endIndex ) + return undefined; + } + let result = o.src.substring( beginOf.length, o.src.length - endOf.length ); + + return result; +} + +strInsideOf_body.defaults = +{ + src : null, + begin : null, + end : null, + pairing : 0, /* xxx : set to 1 */ +} + +// + +let insideOf = _.routine.unite( strInsideOf_head, strInsideOf_body ); + +// + +/** + * Routine strInsideOf_() founds parts of a source string {-src-} between first occurrence of {-begin-} at the begin of {-src-} + * and first occurrence of {-end-} at the end of {-src-}. + * Returns result if {-begin-} and {-end-} exists in the {-src-} and index of {-end-} is bigger the index of {-begin-}. + * The format of returned value : [ begin, mid, end ]. + * If {-src-} has not {-begin-} or {-end-} routine returns : [ undefined, undefined, undefined ]. + * If option {-o.pairing-} is true and founded {-begin-} is not equivalent to founded {-end-}, + * then routine returns : [ undefined, undefined, undefined ]. + * + * @example + * _.strInsideOf_( 'abc', 'a', 'a' ); + * // returns :[ undefined, undefined, undefined ] + * + * @example + * _.strInsideOf_( 'abcd', 'x', 'y' ) + * // returns : [ undefined, undefined, undefined ] + * + * @example + * _.strInsideOf_( 'abc', 'abc', 'abc' ); + * // returns : 'abc' + * + * @example + * _.strInsideOf_({ src : 'abcd', begin : 'a', end : 'd', pairing : 0 }); + * // returns : [ 'a', 'bc', 'd' ] + * + * @example + * _.strInsideOf_({ src : 'abcd', begin : 'a', end : 'd', pairing : 1 }); + * // returns : [ undefined, undefined, undefined ] + * + * Basic parameter set : + * @param { String } src - The source string. + * @param { String|Array } begin - String or array of strings to find from begin of source. + * @param { String|Array } end - String or array of strings to find from end source. + * Alternative parameter set : + * @param { String } o - Options map. + * @param { String } o.src - The source string. + * @param { String|Array } o.begin - String or array of strings to find from begin of source. + * @param { String|Array } o.end - String or array of strings to find from end source. + * @param { BoolLike } o.pairing - If option is enabled, then founded begin of {-src-} and + * founded end of {-src-} should be identical. + * @returns { Array } - Returns array with parts of source string {-src-} in format : [ begin, mid, end ]. + * If any of part has no entry, routine returns array : [ undefined, undefined, undefined ]. + * If pairing is enabled, and founded begin and end is not equivalent, then routine returns : [ undefined, undefined, undefined ]. + * @throws { Exception } If arguments.length is 1 and argument is not an options map {-o-}. + * @throws { Exception } If arguments.length is 3 and any of arguments is not a String. + * @throws { Exception } If arguments.length neither is 1 nor 3. + * @throws { Exception } If {-src-} ( {-o.src-} ) is not a String. + * @throws { Exception } If any of {-begin-} ( {-o.begin-} ) or {-end-} ( {-o.end-} ) is not a String or array of Strings. + * @throws { Exception } If options map {-o-} has unknown properties. + * @function strInsideOf_ + * @namespace Tools + */ + +function strInsideOf__head( routine, args ) +{ + + let o = args[ 0 ]; + if( _.mapIs( o ) ) + { + _.assert( args.length === 1, 'Expects exactly one argument' ); + } + else + { + o = Object.create( null ); + o.src = args[ 0 ]; + o.begin = args[ 1 ]; + o.end = args[ 2 ]; + _.assert( args.length === 3, 'Expects exactly three arguments' ); + } + + _.assert( _.strIs( o.src ), 'Expects string {-o.src-}' ); + _.routine.options( routine, o ); + + o.begin = _.array.as( o.begin ); + o.end = _.array.as( o.end ); + + _.assert + ( + !o.pairing || o.begin.length === o.end.length, + `If {-o.paring-} is true then length of o.begin should be equal to length of o.end.` + ); + + return o; +} + +function strInsideOf__body( o ) +{ + + let begin = _.strBeginOf( o.src, o.begin ); + if( begin === undefined ) + return [ undefined, undefined, undefined ]; + + let end = _.strEndOf( o.src, o.end ); + if( end === undefined ) + return [ undefined, undefined, undefined ]; + + if( o.pairing ) + { + let beginIndex = _.longLeftIndex( o.begin, begin ); + let endIndex = _.longLeftIndex( o.end, end ); + + if( beginIndex !== endIndex ) + return [ undefined, undefined, undefined ]; + } + + let mid = o.src.substring( begin.length, o.src.length - end.length ); + + return [ begin, mid, end ]; +} + +strInsideOf__body.defaults = +{ + src : null, + begin : null, + end : null, + pairing : 1, /* xxx : set to 1 */ +} + +let insideOf_ = _.routine.unite( strInsideOf__head, strInsideOf__body ); + +// + +function outsideOf( src, begin, end ) +{ + + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + + let beginOf, endOf; + + beginOf = _.strBeginOf( src, begin ); + if( beginOf === undefined ) + return undefined; + + endOf = _.strEndOf( src, end ); + if( endOf === undefined ) + return undefined; + + let result = beginOf + endOf; + + return result; +} + +//-- +// replacers +//-- + +function _removedBegin( src, begin ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + + let result = src; + let beginOf = _._strBeginOf( result, begin ); + if( beginOf !== undefined ) + result = result.substr( beginOf.length, result.length ); + + return result; +} + +// + +/** + * Finds substring prefix ( begin ) occurrence from the very begining of source ( src ) and removes it. + * Returns original string if source( src ) does not have occurrence of ( prefix ). + * + * @param { String } src - Source string to parse. + * @param { String } prefix - String that is to be dropped. + * @returns { String } Returns string with result of prefix removement. + * + * @example + * _.strRemoveBegin( 'example', 'exa' ); + * // returns mple + * + * @example + * _.strRemoveBegin( 'example', 'abc' ); + * // returns example + * + * @function removeBegin + * @throws { Exception } Throws a exception if( src ) is not a String. + * @throws { Exception } Throws a exception if( prefix ) is not a String. + * @throws { Exception } Throws a exception if( arguments.length ) is not equal 2. + * @namespace Tools + * + */ + +function removeBegin( src, begin ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.longIs( src ) || _.strIs( src ), 'Expects string or array of strings {-src-}' ); + _.assert( _.longIs( begin ) || _.strIs( begin ) || _.regexpIs( begin ), 'Expects string/regexp or array of strings/regexps {-begin-}' ); + + let result = []; + let srcIsArray = _.longIs( src ); + + if( _.strIs( src ) && !_.longIs( begin ) ) + return _._strRemovedBegin( src, begin ); + + src = _.array.as( src ); + begin = _.array.as( begin ); + for( let s = 0, slen = src.length ; s < slen ; s++ ) + { + let beginOf = undefined; + let src1 = src[ s ] + for( let b = 0, blen = begin.length ; b < blen ; b++ ) + { + beginOf = _._strBeginOf( src1, begin[ b ] ); + if( beginOf !== undefined ) + break; + } + if( beginOf !== undefined ) + src1 = src1.substr( beginOf.length, src1.length ); + result[ s ] = src1; + } + + if( !srcIsArray ) + return result[ 0 ]; + + return result; +} + +// + +function _removedEnd( src, end ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + + let result = src; + let endOf = _._strEndOf( result, end ); + if( endOf !== undefined ) + result = result.substr( 0, result.length - endOf.length ); + + return result; +} + +// + +/** + * Removes occurrence of postfix ( end ) from the very end of string( src ). + * Returns original string if no occurrence finded. + * @param { String } src - Source string to parse. + * @param { String } postfix - String that is to be dropped. + * @returns { String } Returns string with result of postfix removement. + * + * @example + * _.strRemoveEnd( 'example', 'le' ); + * // returns examp + * + * @example + * _.strRemoveEnd( 'example', 'abc' ); + * // returns example + * + * @function removeEnd + * @throws { Exception } Throws a exception if( src ) is not a String. + * @throws { Exception } Throws a exception if( postfix ) is not a String. + * @throws { Exception } Throws a exception if( arguments.length ) is not equal 2. + * @namespace Tools + * + */ + +function removeEnd( src, end ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.longIs( src ) || _.strIs( src ), 'Expects string or array of strings {-src-}' ); + _.assert( _.longIs( end ) || _.strIs( end ) || _.regexpIs( end ), 'Expects string/regexp or array of strings/regexps {-end-}' ); + + let result = []; + let srcIsArray = _.longIs( src ); + + if( _.strIs( src ) && !_.longIs( end ) ) + return _._strRemovedEnd( src, end ); + + src = _.array.as( src ); + end = _.array.as( end ); + + for( let s = 0, slen = src.length ; s < slen ; s++ ) + { + let endOf = undefined; + let src1 = src[ s ] + for( let b = 0, blen = end.length ; b < blen ; b++ ) + { + endOf = _._strEndOf( src1, end[ b ] ); + if( endOf !== undefined ) + break; + } + if( endOf !== undefined ) + src1 = src1.substr( 0, src1.length - endOf.length ); + result[ s ] = src1; + } + + if( !srcIsArray ) + return result[ 0 ]; + + return result; +} + +// + +function replaceBegin( src, begin, ins ) +{ + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + _.assert( _.strIs( ins ) || _.longIs( ins ), 'Expects {-ins-} as string/array of strings' ); + if( _.longIs( begin ) && _.longIs( ins ) ) + _.assert( begin.length === ins.length ); + + begin = _.array.as( begin ); + let result = _.array.as( src ).slice(); + + for( let k = 0, srcLength = result.length; k < srcLength; k++ ) + for( let j = 0, beginLength = begin.length; j < beginLength; j++ ) + if( _.strBegins( result[ k ], begin[ j ] ) ) + { + let prefix = _.longIs( ins ) ? ins[ j ] : ins; + _.assert( _.strIs( prefix ) ); + result[ k ] = prefix + _.strRemoveBegin( result[ k ], begin[ j ] ); + break; + } + + if( result.length === 1 && _.strIs( src ) ) + return result[ 0 ]; + + return result; +} + +// + +function replaceEnd( src, end, ins ) +{ + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + _.assert( _.strIs( ins ) || _.longIs( ins ), 'Expects {-ins-} as string/array of strings' ); + if( _.longIs( end ) && _.longIs( ins ) ) + _.assert( end.length === ins.length ); + + end = _.array.as( end ); + let result = _.array.as( src ).slice(); + + for( let k = 0, srcLength = result.length; k < srcLength; k++ ) + for( let j = 0, endLength = end.length; j < endLength; j++ ) + if( _.strEnds( result[ k ], end[ j ] ) ) + { + let postfix = _.longIs( ins ) ? ins[ j ] : ins; + _.assert( _.strIs( postfix ) ); + result[ k ] = _.strRemoveEnd( result[ k ], end[ j ] ) + postfix; + break; + } + + if( result.length === 1 && _.strIs( src ) ) + return result[ 0 ]; + + return result; +} + +// + +/** +* Finds substring or regexp ( insStr ) occurrence from the source string ( srcStr ) and replaces them +* with the subStr values. +* Returns original string if source( src ) does not have occurrence of ( insStr ). +* +* @param { String } srcStr - Source string to parse. +* @param { String } insStr - String/RegExp that is to be replaced. +* @param { String } subStr - Replacement String/RegExp. +* @returns { String } Returns string with result of substring replacement. +* +* @example +* _.strReplace( 'source string', 's', 'S' ); +* // returns Source string +* +* @example +* _.strReplace( 'example', 's' ); +* // returns example +* +* @function replace +* @throws { Exception } Throws a exception if( srcStr ) is not a String. +* @throws { Exception } Throws a exception if( insStr ) is not a String or a RegExp. +* @throws { Exception } Throws a exception if( subStr ) is not a String. +* @throws { Exception } Throws a exception if( arguments.length ) is not equal 3. +* @namespace Tools +* +*/ + +function replace( src, ins, sub ) +{ + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + _.assert( _.strsAreAll( sub ), 'Expects {-sub-} as string/array of strings' ); + + if( _.longIs( ins ) && _.longIs( sub ) ) + _.assert( ins.length === sub.length ); + + ins = _.array.as( ins ); + for( let i = 0 ; i < ins.length ; i++ ) + _.assert( ins[ i ] !== '', '{-ins-} should be a string with length' ); + + /* */ + + let result = _.array.as( src ).slice(); + + for( let i = 0 ; i < result.length ; i++ ) + { + result[ i ] = _.strSplit + ({ + src : result[ i ], + delimeter : ins, + quoting : 0, + stripping : 0, + preservingEmpty : 1, + preservingDelimeters : 1, + onDelimeter : ( e, k ) => _.strIs( sub ) ? sub : sub[ k ], + }); + result[ i ] = result[ i ].join( '' ); + } + + if( result.length === 1 && _.strIs( src ) ) + return result[ 0 ]; + + return result; +} + +// -- +// stripper +// -- + +/** + * Routine strip() removes entries of leading and trailing characters in source string {-o.src-}, + * which is found by mask {-o.stripper-}. + * If {-o.stripper-} is not defined function removes leading and trailing whitespaces and escaped + * characters from begin and end of source string {-o.src-}. + * + * @example + * _.strStrip( ' abc ' ); + * // returns 'abc' + * + * @example + * _.strStrip({ src : 'ababa', stripper : 'a' }); + * // returns 'bb' + * + * @example + * _.strStrip({ src : ' abc ', stripper : /^\s+/ }); + * // returns 'abc ' + * + * @example + * _.strStrip({ src : 'axc bb cxa', stripper : [ 'a', 'x' ] }); + * // returns 'c bb c' + * + * @example + * _.strStrip({ src : ' abc ', stripper : true }); + * // returns 'abc' + * + * First parameter set : + * @param { String|Array } src - Source string(s) to strip. + * Second parameter set : + * @param { Aux } o - Options map. + * @param { String|Array } o.src - Source string(s) to strip. + * @param { String|RegExp|Array|BoolLike } o.stripper - Defines characters to remove. + * @returns { String|Array } - Returns stripped string. If source string was an Array of strings, then routine + * returns array with stripped strings. + * @function strip + * @throws { Exception } Throw an error if arguments.length is not equal 1. + * @throws { Exception } Throw an error if options map {-o-} has not valid type. + * @throws { Exception } Throw an error if options map {-o-} has unknown property. + * @throws { Exception } Throw an error if {-o.src-} is not a String or not an Array of strings. + * @throws { Exception } Throw an error if {-o.stripper-} has not valid type, or it has value `false`. + * @namespace Tools + */ + +function strip( o ) +{ + + if( _.strIs( o ) || _.arrayIs( o ) ) + o = { src : o }; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options( strip, o ); + + o.stripper = stripperNormalize(); + let stripRoutine = _.regexpIs( o.stripper ) ? singleStripByRegexp : singleStripByArrayOfStrings; + + if( _.arrayIs( o.src ) ) + { + _.assert( _.strsAreAll( o.src ), 'Expects strings {-o.srs-}' ); + + let result = []; + for( let i = 0 ; i < o.src.length ; i++ ) + result[ i ] = stripRoutine( o.src[ i ] ); + return result; + } + + _.assert( _.strIs( o.src ) ); + return stripRoutine( o.src ); + + /* */ + + function stripperNormalize() + { + let stripper = o.stripper; + if( _.bool.likeTrue( o.stripper ) ) + { + stripper = strip.defaults.stripper; + } + else if( _.arrayIs( o.stripper ) ) + { + _.assert( _.strsAreAll( o.stripper ), 'Expects characters in container {-o.stripper-}' ); + } + else if( _.strIs( o.stripper ) ) + { + stripper = _.regexpEscape( o.stripper ); + stripper = new RegExp( stripper, 'g' ); + } + else if( !_.regexpIs( o.stripper ) ) + { + _.assert( 0, 'Unexpected type of {-o.stripper-}. Expects either a String, an Array or a Regexp {-o.stripper-}' ); + } + return stripper; + } + + /* */ + + function singleStripByRegexp( src ) + { + return src.replace( o.stripper, '' ); + } + + /* */ + + function singleStripByArrayOfStrings( src ) + { + let begin = 0; + for( ; begin < src.length ; begin++ ) + if( o.stripper.indexOf( src[ begin ] ) === -1 ) + break; + + let end = src.length-1; + for( ; end >= 0 ; end-- ) + if( o.stripper.indexOf( src[ end ] ) === -1 ) + break; + + if( begin >= end ) + return ''; + + return src.substring( begin, end + 1 ); + } + +} + +strip.defaults = +{ + src : null, + stripper : /^(\s|\n|\0)+|(\s|\n|\0)+$/g, + // stripper : /^(\s|\n|\0)+|(\s|\n|\0)+$/gm, /* Dmytro : multiline replacing should be an option, not for single string */ +} + +// function strStrip( o ) +// { +// +// if( _.strIs( o ) || _.arrayIs( o ) ) +// o = { src : o }; +// +// _.routine.options( strStrip, o ); +// _.assert( arguments.length === 1, 'Expects single argument' ); +// +// if( _.arrayIs( o.src ) ) +// { +// let result = []; +// for( let s = 0 ; s < o.src.length ; s++ ) +// { +// let optionsForStrip = _.props.extend( null, o ); +// optionsForStrip.src = optionsForStrip.src[ s ]; +// result[ s ] = strStrip( optionsForStrip ); +// } +// return result; +// } +// +// if( _.bool.likeTrue( o.stripper ) ) +// { +// o.stripper = strip.defaults.stripper; +// } +// +// _.assert( _.strIs( o.src ), 'Expects string or array o.src, got', _.entity.strType( o.src ) ); +// _.assert( _.strIs( o.stripper ) || _.arrayIs( o.stripper ) || _.regexpIs( o.stripper ), 'Expects string or array or regexp ( o.stripper )' ); +// +// if( _.strIs( o.stripper ) || _.regexpIs( o.stripper ) ) +// { +// let exp = o.stripper; +// if( _.strIs( exp ) ) +// { +// exp = _.regexpEscape( exp ); +// exp = new RegExp( exp, 'g' ); +// } +// return o.src.replace( exp, '' ); +// } +// else +// { +// +// _.assert( _.arrayIs( o.stripper ) ); +// +// if( Config.debug ) +// for( let s of o.stripper ) +// { +// _.assert( _.strIs( s, 'Expects string {-stripper[ * ]-}' ) ); +// } +// +// let b = 0; +// for( ; b < o.src.length ; b++ ) +// if( o.stripper.indexOf( o.src[ b ] ) === -1 ) +// break; +// +// let e = o.src.length-1; +// for( ; e >= 0 ; e-- ) +// if( o.stripper.indexOf( o.src[ e ] ) === -1 ) +// break; +// +// if( b >= e ) +// return ''; +// +// return o.src.substring( b, e+1 ); +// } +// +// } +// +// strStrip.defaults = +// { +// src : null, +// stripper : /^(\s|\n|\0)+|(\s|\n|\0)+$/gm, +// } + +// + +/** + * Same as _.strStrip with one difference: + * If( o.stripper ) is not defined, function removes only leading whitespaces and escaped characters from( o.src ). + * + * @example + * _.strStripLeft( ' a ' ) + * // returns 'a ' + * + * @method stripLeft + * @namespace Tools + * + */ + +function stripLeft( o ) +{ + + if( _.strIs( o ) || _.arrayIs( o ) ) + o = { src : o }; + + _.routine.options( stripLeft, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + return _.strStrip( o ); +} + +stripLeft.defaults = +{ + ... strip.defaults, + stripper : /^(\s|\n|\0)+/gm, +} + +// + +/** + * Same as _.strStrip with one difference: + * If( o.stripper ) is not defined, function removes only trailing whitespaces and escaped characters from( o.src ). + * + * @example + * _.strStripRight( ' a ' ) + * // returns ' a' + * + * @method stripRight + * @namespace Tools + * + */ + +function stripRight( o ) +{ + + if( _.strIs( o ) || _.arrayIs( o ) ) + o = { src : o }; + + _.routine.options( stripRight, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + return _.strStrip( o ); +} + +stripRight.defaults = +{ + ... strip.defaults, + stripper : /(\s|\n|\0)+$/gm, +} + +// + +/** + * Removes whitespaces from source( src ). + * If argument( sub ) is defined, function replaces whitespaces with it. + * + * @param {string} src - Source string to parse. + * @param {string} sub - Substring that replaces whitespaces. + * @returns {string} Returns a string with removed whitespaces. + * + * @example + * _.strRemoveAllSpaces( 'a b c d e' ); + * // returns abcde + * + * @example + * _.strRemoveAllSpaces( 'a b c d e', '*' ); + * // returns a*b*c*d*e + * + * @method _removeAllSpaces + * @namespace Tools + * +*/ + +function _removeAllSpaces( src, sub ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( src ) ); + + if( sub === undefined ) + sub = ''; + + return src.replace( /\s/g, sub ); +} + +// + +/** + * Removes empty lines from the string passed by argument( srcStr ). + * + * @param {string} srcStr - Source string to parse. + * @returns {string} Returns a string with empty lines removed. + * + * @example + * _.strStripEmptyLines( 'first\n\nsecond' ); + * // returns + * // first + * // second + * + * @example + * _.strStripEmptyLines( 'zero\n\nfirst\n\nsecond' ); + * // returns + * // zero + * // first + * // second + * + * @method strStripEmptyLines + * @throws { Exception } Throw an exception if( srcStr ) is not a String. + * @throws { Exception } Throw an exception if( arguments.length ) is not equal 1. + * @namespace Tools + * + */ + +function _stripEmptyLines( srcStr ) +{ + let result = ''; + let lines = srcStr.split( '\n' ); + + _.assert( _.strIs( srcStr ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + for( let l = 0; l < lines.length; l += 1 ) + { + let line = lines[ l ]; + + if( !_.strStrip( line ) ) + continue; + + result += line + '\n'; + } + + result = result.substring( 0, result.length - 1 ); + return result; +} + +// -- +// split +// -- + +function splitsCoupledGroup( o ) +{ + + if( _.arrayIs( o ) ) + o = { splits : o } + + o = _.routine.options( splitsCoupledGroup, o ); + + o.prefix = _.array.as( o.prefix ); + o.postfix = _.array.as( o.postfix ); + + _.assert( arguments.length === 1 ); + _.assert( _.regexpsLikeAll( o.prefix ) ); + _.assert( _.regexpsLikeAll( o.postfix ) ); + + let level = 0; + let begins = []; + for( let i = 0 ; i < o.splits.length ; i++ ) + { + let element = o.splits[ i ]; + + if( _.regexpsTestAny( o.prefix, element ) ) + { + begins.push( i ); + } + else if( _.regexpsTestAny( o.postfix, element ) ) + { + if( begins.length === 0 && !o.allowingUncoupledPostfix ) + throw _.err( `"${ element }" does not have complementing openning\n` ); + + if( begins.length === 0 ) + continue; + + let begin = begins.pop(); + let end = i; + let l = end-begin; + + _.assert( l >= 0 ) + let newElement = o.splits.splice( begin, l+1, null ); + o.splits[ begin ] = newElement; + + i -= l; + } + + } + + if( begins.length && !o.allowingUncoupledPrefix ) + { + debugger; + throw _.err( `"${ begins[ begins.length-1 ] }" does not have complementing closing\n` ); + } + + return o.splits; +} + +splitsCoupledGroup.defaults = +{ + splits : null, + prefix : '"', + postfix : '"', + allowingUncoupledPrefix : 0, + allowingUncoupledPostfix : 0, +} + +// + +function splitsUngroupedJoin( o ) +{ + + if( _.arrayIs( o ) ) + o = { splits : o } + o = _.routine.options( splitsUngroupedJoin, o ); + + let s = o.splits.length-1; + let l = null; + + while( s >= 0 ) + { + let split = o.splits[ s ]; + + if( _.strIs( split ) ) + { + if( l === null ) + l = s; + } + else if( l !== null ) + { + join(); + } + + s -= 1; + } + + if( l !== null ) + join(); + + return o.splits; + + /* */ + + function join() + { + if( s+1 < l ) + { + let element = o.splits.slice( s+1, l+1 ).join( '' ); + o.splits.splice( s+1, l+1, element ); + } + l = null; + } + +} + +splitsUngroupedJoin.defaults = +{ + splits : null, +} + +// + +function strSplitsQuotedRejoin_head( routine, args ) +{ + let o = args[ 0 ]; + + _.routine.options( routine, o ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1, 'Expects one or two arguments' ); + _.assert( _.object.isBasic( o ) ); + + if( o.quoting ) + { + + if( _.bool.like( o.quoting ) ) + { + if( !o.quotingPrefixes ) + o.quotingPrefixes = [ '"' ]; + if( !o.quotingPostfixes ) + o.quotingPostfixes = [ '"' ]; + } + else if( _.strIs( o.quoting ) || _.regexpIs( o.quoting ) || _.arrayIs( o.quoting ) ) + { + _.assert( !o.quotingPrefixes ); + _.assert( !o.quotingPostfixes ); + o.quoting = _.array.as( o.quoting ); + o.quotingPrefixes = o.quoting.map( ( q ) => _.arrayIs( q ) ? q[ 0 ] : q ); + o.quotingPostfixes = o.quoting.map( ( q ) => _.arrayIs( q ) ? q[ 0 ] : q ); + o.quoting = true; + } + else _.assert( 0, 'unexpected type of {-o.quoting-}' ); + + _.assert + ( + !o.pairing || o.quotingPrefixes.length === o.quotingPostfixes.length, + `If option::o.paring is true then the length of o.quotingPrefixes should be equal to the length of o.quotingPostfixes` + ); + + if( Config.debug ) + { + _.assert( o.quotingPrefixes.length === o.quotingPostfixes.length ); + _.assert( _.bool.like( o.quoting ) ); + o.quotingPrefixes.forEach( ( q ) => _.assert( _.strIs( q ) ) ); + o.quotingPostfixes.forEach( ( q ) => _.assert( _.strIs( q ) ) ); + } + + } + + return o; +} + +// + +function strSplitsQuotedRejoin_body( o ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.arrayIs( o.splits ) ); + + /* quoting */ + + // let s = 1; // why was it 1?? + let s = 0; + if( o.quoting ) + { + for( s ; s < o.splits.length ; s += 1 ) + splitsQuote( o.splits[ s ], s ); + } + + return o.splits; + + function splitsQuote( split, i ) + { + let s2; + let q = o.quotingPrefixes.indexOf( split ); + + if( q >= 0 ) + { + let postfix = o.quotingPostfixes[ q ]; + for( s2 = i+2 ; s2 < o.splits.length ; s2 += 1 ) + { + let split2 = o.splits[ s2 ]; + if( split2 === postfix ) + { + if( o.pairing ) + if( o.quotingPrefixes.indexOf( o.splits[ s ] ) !== o.quotingPostfixes.indexOf( o.splits[ s2 ] ) ) + break; + let bextra = 0; + let eextra = 0; + if( o.inliningQuoting ) + { + s -= 1; + bextra += 1; + s2 += 1; + eextra += 1; + } + let splitNew = o.splits.splice( s, s2-s+1, null ); + if( !o.preservingQuoting ) + { + splitNew.splice( bextra, 1 ); + splitNew.splice( splitNew.length-1-eextra, 1 ); + } + splitNew = splitNew.join( '' ); + if( o.onQuoting ) + o.splits[ s ] = o.onQuoting( splitNew, o ); + else + o.splits[ s ] = splitNew; + s2 = s; + break; + } + } + } + + /* if complementing postfix not found */ + + if( s2 >= o.splits.length ) + { + if( !_.longHas( o.delimeter, split ) ) + { + let splitNew = o.splits.splice( s, 2 ).join( '' ); + o.splits[ s-1 ] = o.splits[ s-1 ] + splitNew; + } + else + { + } + } + } +} + +strSplitsQuotedRejoin_body.defaults = +{ + quoting : 1, + quotingPrefixes : null, + quotingPostfixes : null, + preservingQuoting : 1, + inliningQuoting : 1, + splits : null, + delimeter : null, + onQuoting : null, + pairing : 0 +} + +// + +let splitsQuotedRejoin = _.routine.unite( strSplitsQuotedRejoin_head, strSplitsQuotedRejoin_body ); + +// -- +// +// -- + +function strSplitsDropDelimeters_head( routine, args ) +{ + let o = args[ 0 ]; + + _.routine.options( routine, o ); + + if( _.strIs( o.delimeter ) ) + o.delimeter = [ o.delimeter ]; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 ); + _.assert( _.object.isBasic( o ) ); + + return o; +} + +// + +function strSplitsDropDelimeters_body( o ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.arrayIs( o.splits ) ); + + /* stripping */ + + // if( o.delimeter.some( ( d ) => _.regexpIs( d ) ) ) + // debugger; + + for( let s = o.splits.length-1 ; s >= 0 ; s-- ) + { + let split = o.splits[ s ]; + + if( _.regexpsTestAny( o.delimeter, split ) ) /* xxx qqq : ? */ + o.splits.splice( s, 1 ); + + // if( _.longHas( o.delimeter, split ) ) + // o.splits.splice( s, 1 ); + // + // if( s % 2 === 1 ) + // o.splits.splice( s, 1 ); + + } + + return o.splits; +} + +strSplitsDropDelimeters_body.defaults = +{ + splits : null, + delimeter : null, +} + +// + +let splitsDropDelimeters = _.routine.unite( strSplitsDropDelimeters_head, strSplitsDropDelimeters_body ); + +// -- +// +// -- + +function strSplitsStrip_head( routine, args ) +{ + let o = args[ 0 ]; + + _.routine.options( routine, o ); + + if( o.stripping && _.bool.like( o.stripping ) ) + o.stripping = _.strStrip.defaults.stripper; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 ); + _.assert( _.object.isBasic( o ) ); + _.assert( !o.stripping || _.strIs( o.stripping ) || _.regexpIs( o.stripping ) ); + + return o; +} + +// + +function strSplitsStrip_body( o ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.arrayIs( o.splits ) ); + + if( !o.stripping ) + return o.splits; + + /* stripping */ + + for( let s = 0 ; s < o.splits.length ; s++ ) + { + let split = o.splits[ s ]; + + if( _.strIs( split ) ) + split = _.strStrip({ src : split, stripper : o.stripping }); + + o.splits[ s ] = split; + } + + return o.splits; +} + +strSplitsStrip_body.defaults = +{ + stripping : 1, + splits : null, +} + +// + +let splitsStrip = _.routine.unite( strSplitsStrip_head, strSplitsStrip_body ); + +// -- +// +// -- + +function strSplitsDropEmpty_head( routine, args ) +{ + let o = args[ 0 ]; + + _.routine.options( routine, o ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 ); + _.assert( _.object.isBasic( o ) ); + + return o; +} + +// + +function strSplitsDropEmpty_body( o ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.arrayIs( o.splits ) ); + + /* stripping */ + + for( let s = 0 ; s < o.splits.length ; s++ ) + { + let split = o.splits[ s ]; + + if( !split ) + { + o.splits.splice( s, 1 ); + s -= 1; + } + + } + + return o.splits; +} + +strSplitsDropEmpty_body.defaults = +{ + splits : null, +} + +// + +let splitsDropEmpty = _.routine.unite( strSplitsDropEmpty_head, strSplitsDropEmpty_body ); + +// -- +// +// -- + +function strSplitFast_head( routine, args ) +{ + let o = args[ 0 ]; + + if( args.length === 2 ) + o = { src : args[ 0 ], delimeter : args[ 1 ] } + else if( _.strIs( args[ 0 ] ) ) + o = { src : args[ 0 ] } + + _.routine.options( routine, o ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 || args.length === 2, 'Expects one or two arguments' ); + _.assert( _.strIs( o.src ) ); + _.assert( o.delimeter === null || _.regexp.like( o.delimeter ) || _.arrayIs( o.delimeter ) ); + _.assert( _.object.isBasic( o ) ); + + return o; +} + +// + +/* qqq2 : write performance test and optimize */ +function strSplitFast_body( o ) +{ + let result, closests, position, closestPosition, closestIndex, hasEmptyDelimeter, delimeter + + o.delimeter = _.array.as( o.delimeter ); + + let foundDelimeters = o.delimeter.slice(); + + _.assert( arguments.length === 1 ); + _.assert( _.arrayIs( o.delimeter ) ); + _.assert( _.bool.like( o.preservingDelimeters ) ); + + /* */ + + if( !o.preservingDelimeters && o.delimeter.length === 1 ) + { + + result = o.src.split( o.delimeter[ 0 ] ); + + if( !o.preservingEmpty ) + result = result.filter( ( e ) => e ? e : false ); + + } + else + { + + if( !o.delimeter.length ) + { + result = [ o.src ]; + return result; + } + + result = []; + closests = []; + position = 0; + closestPosition = 0; + closestIndex = -1; + hasEmptyDelimeter = false; + + for( let d = 0 ; d < o.delimeter.length ; d++ ) + { + let delimeter = o.delimeter[ d ]; + if( _.regexpIs( delimeter ) ) + { + _.assert( !delimeter.sticky ); + if( delimeter.source === '' || delimeter.source === '()' || delimeter.source === '(?:)' ) + hasEmptyDelimeter = true; + } + else + { + if( delimeter.length === 0 ) + hasEmptyDelimeter = true; + } + closests[ d ] = delimeterNext( d, position ); + } + + do + { + closestWhich(); + + if( closestPosition === o.src.length ) + break; + + if( !delimeter.length ) + position += 1; + + ordinaryAdd( o.src.substring( position, closestPosition ) ); + + if( delimeter.length > 0 || position < o.src.length ) + delimeterAdd( delimeter ); + + position = closests[ closestIndex ] + ( delimeter.length ? delimeter.length : 1 ); + + for( let d = 0 ; d < o.delimeter.length ; d++ ) + if( closests[ d ] < position ) + closests[ d ] = delimeterNext( d, position ); + + } + while( position < o.src.length ); + + if( delimeter || !hasEmptyDelimeter ) + ordinaryAdd( o.src.substring( position, o.src.length ) ); + + } + + return result; + + /* */ + + function delimeterAdd( delimeter ) + { + + if( o.preservingDelimeters ) + if( o.preservingEmpty || delimeter ) + { + result.push( delimeter ); + // if( _.regexpIs( delimeter ) ) + // result.push( delimeter ); + // o.src.substring( position, closestPosition ) + // else + // result.push( delimeter ); + } + + } + + /* */ + + function ordinaryAdd( ordinary ) + { + if( o.preservingEmpty || ordinary ) + result.push( ordinary ); + } + + /* */ + + function closestWhich() + { + + closestPosition = o.src.length; + closestIndex = -1; + for( let d = 0 ; d < o.delimeter.length ; d++ ) + { + if( closests[ d ] < o.src.length && closests[ d ] < closestPosition ) + { + closestPosition = closests[ d ]; + closestIndex = d; + } + } + + delimeter = foundDelimeters[ closestIndex ]; + + } + + /* */ + + function delimeterNext( d, position ) + { + _.assert( position <= o.src.length ); + let delimeter = o.delimeter[ d ]; + let result; + + if( _.strIs( delimeter ) ) + { + result = o.src.indexOf( delimeter, position ); + } + else + { + let execed = delimeter.exec( o.src.substring( position ) ); + if( execed ) + { + result = execed.index + position; + foundDelimeters[ d ] = execed[ 0 ]; + } + } + + if( result === -1 ) + return o.src.length; + return result; + } + +} + +strSplitFast_body.defaults = +{ + src : null, + delimeter : ' ', + preservingEmpty : 1, + preservingDelimeters : 1, +} + +// + +/** + * Divides source string( o.src ) into parts using delimeter provided by argument( o.delimeter ). + * If( o.stripping ) is true - removes leading and trailing whitespace characters. + * If( o.preservingEmpty ) is true - empty lines are saved in the result array. + * If( o.preservingDelimeters ) is true - leaves word delimeters in result array, otherwise removes them. + * Function can be called in two ways: + * - First to pass only source string and use default options; + * - Second to pass map like ( { src : 'a, b, c', delimeter : ', ', stripping : 1 } ). + * Returns result as array of strings. + * + * @param {string|object} o - Source string to split or map with source( o.src ) and options. + * @param {string} [ o.src=null ] - Source string. + * @param {string|array} [ o.delimeter=' ' ] - Word divider in source string. + * @param {boolean} [ o.preservingEmpty=false ] - Leaves empty strings in the result array. + * @param {boolean} [ o.preservingDelimeters=false ] - Puts delimeters into result array in same order how they was in the source string. + * @param {boolean} [ o.stripping=true ] - Removes leading and trailing whitespace characters occurrences from source string. + * @returns {object} Returns an array of strings separated by( o.delimeter ). + * + * @example + * _.strSplitFast( ' first second third ' ); + * // returns [ 'first', 'second', 'third' ] + * + * @example + * _.strSplitFast( { src : 'a, b, c, d', delimeter : ', ' } ); + * // returns [ 'a', 'b', 'c', 'd' ] + * + * @example + * _.strSplitFast( { src : 'a.b, c.d', delimeter : [ '.', ', ' ] } ); + * // returns [ 'a', 'b', 'c', 'd' ] + * + * @example + * _.strSplitFast( { src : ' a, b, c, d ', delimeter : [ ', ' ], stripping : 0 } ); + * // returns [ ' a', 'b', 'c', 'd ' ] + * + * @example + * _.strSplitFast( { src : 'a, b, c, d', delimeter : [ ', ' ], preservingDelimeters : 1 } ); + * // returns [ 'a', ', ', 'b', ', ', 'c', ', ', 'd' ] + * + * @example + * _.strSplitFast( { src : 'a ., b ., c ., d', delimeter : [ ', ', '.' ], preservingEmpty : 1 } ); + * // returns [ 'a', '', 'b', '', 'c', '', 'd' ] + * + * @method splitFast + * @throws { Exception } Throw an exception if( arguments.length ) is not equal 1 or 2. + * @throws { Exception } Throw an exception if( o.src ) is not a String. + * @throws { Exception } Throw an exception if( o.delimeter ) is not a String or an Array. + * @throws { Exception } Throw an exception if object( o ) has been extended by invalid property. + * @namespace Tools + * + */ + +let splitFast = _.routine.unite( strSplitFast_head, strSplitFast_body ); + +_.assert( splitFast.head === strSplitFast_head ); +_.assert( splitFast.body === strSplitFast_body ); +_.assert( _.object.isBasic( splitFast.defaults ) ); + +// + +function strSplit_body( o ) +{ + + o.delimeter = _.array.as( o.delimeter ); + + if( !o.stripping && !o.quoting && !o.onDelimeter ) + { + return _.strSplitFast.body( _.mapOnly_( null, o, _.strSplitFast.defaults ) ); + } + + /* */ + + _.assert( arguments.length === 1 ); + + /* */ + + let result = []; + let fastOptions = _.mapOnly_( null, o, _.strSplitFast.defaults ); + fastOptions.preservingEmpty = 1; + fastOptions.preservingDelimeters = 1; + + if( o.quoting ) + fastOptions.delimeter = _.arrayAppendArraysOnce( [], [ o.quotingPrefixes, o.quotingPostfixes, fastOptions.delimeter ] ); + + o.splits = _.strSplitFast.body( fastOptions ); + + if( o.quoting && o.onQuote ) + { + let quotes = _.arrayAppendArraysOnce( null, [ o.quotingPrefixes, o.quotingPostfixes ] ); + for( let i = 0 ; i < o.splits.length ; i++ ) + { + let index = _.longLeftIndex( quotes, o.splits[ i ], equalizeStrings ); + if( index !== -1 ) + o.splits[ i ] = o.onQuote( o.splits[ i ], index, quotes ); + } + } + if( o.onDelimeter ) + { + let delimeter = _.filter_( null, o.delimeter, function( pattern ) + { + if( _.regexpIs( pattern ) ) + return pattern.test( o.src ) ? pattern : null; + return pattern; + }); + for( let i = 0 ; i < o.splits.length ; i++ ) + { + let index = _.longLeftIndex( delimeter, o.splits[ i ], equalizeStrings ); + if( index !== -1 ) + o.splits[ i ] = o.onDelimeter( o.splits[ i ], index, o.delimeter ); + } + } + + if( o.quoting ) + _.strSplitsQuotedRejoin.body( o ); + + if( !o.preservingDelimeters ) + _.strSplitsDropDelimeters.body( o ); + + if( o.stripping ) + _.strSplitsStrip.body( o ); + + if( !o.preservingEmpty ) + _.strSplitsDropEmpty.body( o ); + + /* */ + + return o.splits; + + /* */ + + function equalizeStrings( pattern, el ) + { + if( _.strIs( pattern ) ) + return pattern === el; + if( pattern !== null ) + return pattern.test( el ); + return false; + } + +} + +var defaults = strSplit_body.defaults = Object.create( strSplitFast_body.defaults ); + +defaults.preservingEmpty = 1; +defaults.preservingDelimeters = 1; +defaults.preservingQuoting = 1; +defaults.inliningQuoting = 1; + +defaults.stripping = 1; +defaults.quoting = 1; +defaults.quotingPrefixes = null; +defaults.quotingPostfixes = null; + +defaults.onDelimeter = null; +defaults.onQuote = null; + +// + +/** + * Divides source string( o.src ) into parts using delimeter provided by argument( o.delimeter ). + * If( o.stripping ) is true - removes leading and trailing whitespace characters. + * If( o.preservingEmpty ) is true - empty lines are saved in the result array. + * If( o.preservingDelimeters ) is true - leaves word delimeters in result array, otherwise removes them. + * Function can be called in two ways: + * - First to pass only source string and use default options; + * - Second to pass map like ( { src : 'a, b, c', delimeter : ', ', stripping : 1 } ). + * Returns result as array of strings. + * + * @param {string|object} o - Source string to split or map with source( o.src ) and options. + * @param {string} [ o.src=null ] - Source string. + * @param {string|array} [ o.delimeter=' ' ] - Word divider in source string. + * @param {boolean} [ o.preservingEmpty=false ] - Leaves empty strings in the result array. + * @param {boolean} [ o.preservingDelimeters=false ] - Puts delimeters into result array in same order how they was in the source string. + * @param {boolean} [ o.stripping=true ] - Removes leading and trailing whitespace characters occurrences from source string. + * @returns {object} Returns an array of strings separated by( o.delimeter ). + * + * @example + * _.strSplit( ' first second third ' ); + * // returns [ 'first', 'second', 'third' ] + * + * @example + * _.strSplit( { src : 'a, b, c, d', delimeter : ', ' } ); + * // returns [ 'a', 'b', 'c', 'd' ] + * + * @example + * _.strSplit( { src : 'a.b, c.d', delimeter : [ '.', ', ' ] } ); + * // returns [ 'a', 'b', 'c', 'd' ] + * + * @example + * _.strSplit( { src : ' a, b, c, d ', delimeter : [ ', ' ], stripping : 0 } ); + * // returns [ ' a', 'b', 'c', 'd ' ] + * + * @example + * _.strSplit( { src : 'a, b, c, d', delimeter : [ ', ' ], preservingDelimeters : 1 } ); + * // returns [ 'a', ', ', 'b', ', ', 'c', ', ', 'd' ] + * + * @example + * _.strSplit( { src : 'a ., b ., c ., d', delimeter : [ ', ', '.' ], preservingEmpty : 1 } ); + * // returns [ 'a', '', 'b', '', 'c', '', 'd' ] + * + * @method split + * @throws { Exception } Throw an exception if( arguments.length ) is not equal 1 or 2. + * @throws { Exception } Throw an exception if( o.src ) is not a String. + * @throws { Exception } Throw an exception if( o.delimeter ) is not a String or an Array. + * @throws { Exception } Throw an exception if object( o ) has been extended by invalid property. + * @namespace Tools + * + */ + +let head = +[ + splitFast.head, + splitsQuotedRejoin.head, + splitsDropDelimeters.head, + splitsStrip.head, + splitsDropEmpty.head +]; +let split = _.routine.unite( head, strSplit_body ); + +_.assert( split.head !== splitFast.head ); +_.assert( _.routine.is( split.head ) ); +_.assert( split.body === strSplit_body ); +_.assert( _.object.isBasic( split.defaults ) ); +_.assert( !!split.defaults.preservingEmpty ); + +// + +let splitNonPreserving = _.routine.uniteCloning( split.head, split.body ); + +var defaults = splitNonPreserving.defaults; + +defaults.preservingEmpty = 0 +defaults.preservingDelimeters = 0; + +// + +function _strSplitInlined_body( o ) +{ + + _.assert( arguments.length === 1, 'Expects single options map' ); + + if( o.delimeter === null ) + o.delimeter = '#'; + + let splitArray = _.strSplit + ({ + src : o.src, + delimeter : o.delimeter, + stripping : o.stripping, + quoting : o.quoting, + preservingEmpty : 1, + preservingDelimeters : 1, + }); + + if( splitArray.length <= 1 ) + { + if( !o.preservingEmpty ) + if( splitArray[ 0 ] === '' ) + splitArray.splice( 0, 1 ); + return splitArray; + } + + /* + first - for tracking index to insert ordinary text + onInlined should be called first and + if undefined returned escaped text shoud be treated as ordinary + so tracking index to insert ordinary text ( in case non undefined returned ) required + */ + + let first = 0; + let result = []; + let i = 0; + for( ; i < splitArray.length; i += 4 ) + { + + if( splitArray.length-i >= 4 ) + { + if( handleTriplet() ) + handleOrdinary(); + } + else + { + if( splitArray.length > i+1 ) + { + splitArray[ i ] = splitArray.slice( i, splitArray.length ).join( '' ); + splitArray.splice( i+1, splitArray.length-i-1 ); + } + handleOrdinary(); + _.assert( i+1 === splitArray.length, 'Openning delimeter', o.delimeter, 'does not have closing' ); + } + + } + + return result; + + /* */ + + function handleTriplet() + { + + let delimeter1 = splitArray[ i+1 ]; + let escaped = splitArray[ i+2 ]; + let delimeter2 = splitArray[ i+3 ]; + + if( o.onInlined ) + escaped = o.onInlined( escaped, o, [ delimeter1, delimeter2 ] ); + + if( escaped === undefined ) + { + _.assert( _.strIs( splitArray[ i+4 ] ) ); + splitArray[ i+2 ] = splitArray[ i+0 ] + splitArray[ i+1 ] + splitArray[ i+2 ]; + splitArray.splice( i, 2 ); + i -= 4; + return false; + } + + first = result.length; + + if( o.preservingDelimeters && delimeter1 !== undefined ) + if( o.preservingEmpty || delimeter1 ) + result.push( delimeter1 ); + + if( o.preservingInlined && escaped !== undefined ) + if( o.preservingEmpty || escaped ) + result.push( escaped ); + + if( o.preservingDelimeters && delimeter2 !== undefined ) + if( o.preservingEmpty || delimeter2 ) + result.push( delimeter2 ); + + return true; + } + + /* */ + + function handleOrdinary() + { + let ordinary = splitArray[ i+0 ]; + + if( o.onOrdinary ) + ordinary = o.onOrdinary( ordinary, o ); + + if( o.preservingOrdinary && ordinary !== undefined ) + if( o.preservingEmpty || ordinary ) + result.splice( first, 0, ordinary ); + + first = result.length; + } + +} + +_strSplitInlined_body.defaults = +{ + + src : null, + delimeter : null, + stripping : 0, + quoting : 0, + + onOrdinary : null, + onInlined : ( e ) => [ e ], + + preservingEmpty : 1, + preservingDelimeters : 0, + preservingOrdinary : 1, + preservingInlined : 1, + +} + +// + +let splitInlined = _.routine.unite( strSplitFast_head, _strSplitInlined_body ); + +// + +/** + * Extracts words enclosed by prefix( o.prefix ) and postfix( o.postfix ) delimeters + * Function can be called in two ways: + * - First to pass only source string and use default options; + * - Second to pass source string and options map like ( { prefix : '#', postfix : '#' } ) as function context. + * + * Returns result as array of strings. + * + * Function extracts words in two attempts: + * First by splitting source string by ( o.prefix ). + * Second by splitting each element of the result of first attempt by( o.postfix ). + * If splitting by ( o.prefix ) gives only single element then second attempt is skipped, otherwise function + * splits all elements except first by ( o.postfix ) into two halfs and calls provided ( o.onInlined ) function on first half. + * If result of second splitting( by o.postfix ) is undefined function appends value of element from first splitting attempt + * with ( o.prefix ) prepended to the last element of result array. + * + * @param {string} src - Source string. + * @param {object} o - Options map. + * @param {string} [ o.prefix = '❮' ] - A delimeter that marks begining of enclosed string. + * @param {string} [ o.postfix = '❯' ] - A ddelimeter that marks ending of enclosed string. + * @param {string} [ o.onInlined = ( el ) => [ el ] ] - Function called on each splitted part of a source string. + * @param {string} [ o.onOrdinary = null ] - Function called on each ordinary part of a source string. + * @param {string} [ o.stripping = 0 ] - If true removes leading and trailing whitespace characters. + * @param {string} [ o.quoting = 0 ] - If true prefixes and postfixes surounded by quotes are treated as ordinary text. + * @param {string} [ o.preservingEmpty = 1 ] - If true empty lines are saved in the result array. + * @param {string} [ o.preservingDelimeters = 0 ] - If true leaves word delimeters in result array, otherwise removes them. + * @param {string} [ o.preservingOrdinary = 1 ] - If true ordinary text is saved in the result array. + * @param {string} [ o.preservingInlined = 1 ] - If true splitted text are saved in the result array. + * @returns {object} Returns an array of strings separated by {- o.prefix -} and {- o.postfix -}. + * + * @example + * _.strSplitInlinedStereo_( '❮abc❯' ); + * // returns [ '', [ 'abc' ], '' ] + * + * @example + * _.strSplitInlinedStereo_({ src : '#abc$', prefix : '#', postfix : '$' }); + * // returns [ '', [ 'abc' ], '' ] + * + * @example + * function onInlined( strip ) + * { + * if( strip.length ) + * return strip.toUpperCase(); + * } + * _.strSplitInlinedStereo_({ src : '', prefix : '<', postfix : '>', onInlined }); + * // returns [ '', [ 'ABC' ], '' ] + * + * @method splitInlinedStereo_ + * @throws { Exception } Throw an exception if( arguments.length ) is not equal 1. + * @throws { Exception } Throw an exception if( o.src ) is not a String. + * @throws { Exception } Throw an exception if object( o ) has been extended by invalid property. + * @namespace Tools + * + */ + +function splitInlinedStereo_( o ) +{ + /* + New delimeter. + was : 'this #background:red#is#background:default# text and is not'. + is : 'this ❮background:red❯is❮background:default❯ text and is not'. + */ + + if( _.strIs( o ) ) + o = { src : o }; + o.quotingPrefixes = o.quotingPrefixes || [ '"' ]; + o.quotingPostfixes = o.quotingPostfixes || [ '"' ]; + + _.assert( this === _ ); + _.assert( _.strIs( o.src ) ); + _.assert( _.object.isBasic( o ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options( splitInlinedStereo_, o ); + + let isDefaultOnInlined = true; + + if( o.onInlined === null ) + { + o.onInlined = ( e ) => [ e ]; + } + else + { + _.assert( _.routine.is( o.onInlined ), 'Expects a routine as option::onInlined' ); + isDefaultOnInlined = false; + } + + /* Trivial cases */ + let end = handleTrivial(); + if( end !== false ) + return end; + + let replacementForPrefix = '\u{20330}'; + let isReplacedPrefix = false; + let splitOptions = _.mapOnly_( null, o, split.defaults ); + splitOptions.preservingDelimeters = 1; /* for distinguishing between inlined and ordinary */ + splitOptions.delimeter = o.prefix === o.postfix ? o.prefix : [ o.prefix, o.postfix ]; + splitOptions.stripping = 0; + splitOptions.preservingEmpty = 1; + + let result = _.strSplit( splitOptions ); /* array with separated ordinary, inlined and delimeters */ + result = preprocessBeforeJoin( result ); + + result = _.strSplitsQuotedRejoin + ({ + splits : result, + delimeter : [ o.prefix, o.postfix ], + quoting : 1, + quotingPrefixes : [ o.prefix ], + quotingPostfixes : [ o.postfix ], + preservingQuoting : o.preservingDelimeters, + inliningQuoting : 0, + onQuoting : o.preservingEmpty ? escapeInlined( o.onInlined ) : o.onInlined + }); + + if( o.preservingEmpty ) + handlePreservingEmpty(); + + unescape(); + + if( o.preservingDelimeters && !o.inliningDelimeters && isDefaultOnInlined ) /* for default onInlined */ + splitInlined(); + + if( isReplacedPrefix ) + result = result.map( ( el ) => + { + if( _.strIs( el ) ) + return el.replace( replacementForPrefix, o.prefix ) + else + return el; + }); + + return result; + + /* - */ + + function handleTrivial() + { + let delimLeftPosition = o.src.indexOf( o.prefix ); + let delimRightPosition = o.src.indexOf( o.postfix ); + + if( delimLeftPosition === -1 || delimRightPosition === -1 ) + { + if( o.preservingOrdinary ) + return [ o.src ]; + else + return []; + } + + if( !o.preservingOrdinary && !o.preservingInlined ) + return []; + + let splitted = o.src.split( o.prefix ); + + if( splitted.length === 1 ) + { + if( o.preservingOrdinary ) + return [ o.src ]; + else + return []; + } + + return false; + } + + /* */ + + function splitInlined() + { + result = result.map( ( el ) => + { + if( _.arrayIs( el ) ) + el = [ o.prefix, el[ 0 ].slice( 1, -1 ), o.postfix ]; + + return el; + }); + } + + /* */ + + function escapeInlined( func ) + { + return function ( el ) + { + return _.escape.wrap( func( el ) ); + } + } + + /* */ + + function preprocessBeforeJoin( array ) + { + let ordinary = ''; + let result = [] + for( let i = 0; i < array.length; i++ ) + { + /* + [ '', '❮', ' ', '❮', ' ', '❮', 'inline1', '❯', ' ', '❯', ' inline2' ] + into + [ '❮ ❮ ', '❮', 'inline1', '❯', ' ❯ inline2' ] + */ + if( array[ i ] === o.prefix ) + { + if( array[ i + 2 ] === o.postfix ) + { + /* push concatenated ordinary string */ + pushOrdinary( result, ordinary ); + /* push inlined : '❮', 'inline1', '❯' */ + if( o.preservingInlined ) + { + result.push( array[ i ] ); + result.push( o.stripping ? array[ i+1 ].trim() : array[ i+1 ] ); + result.push( array[ i+2 ] ); + } + i += 2; + ordinary = ''; + } + else + { + ordinary += array[ i ]; + } + } + else + { + ordinary += array[ i ]; + } + } + + pushOrdinary( result, ordinary ); + + return result; + } + + /* */ + + function pushOrdinary( result, ordinary ) + { + if( o.preservingOrdinary && ordinary ) + { + if( ordinary === o.prefix ) + { + result.push( replacementForPrefix ); + isReplacedPrefix = true; + } + else + { + ordinary = o.stripping ? ordinary.trim() : ordinary; + if( o.onOrdinary ) + { + let ordinary1 = o.onOrdinary( ordinary ); + ordinary = ordinary1 ? ordinary1 : ordinary; + } + + result.push( ordinary ); + } + } + } + + /* */ + + function handlePreservingEmpty() + { + if( _.escape.is( result[ 0 ] ) ) + { + result.unshift( '' ); + } + if( _.escape.is( result[ result.length-1 ] ) ) + { + result.push( '' ); + } + let len = result.length; + for( let i = 0; i < len; i++ ) + { + if( _.escape.is( result[ i ] ) ) + if( _.escape.is( result[ i + 1 ] ) ) + { + result.splice( i + 1, 0, '' ); + len++; + } + } + } + + /* */ + + function unescape() + { + for( let i = 0; i < result.length; i++ ) + { + if( _.escape.is( result[ i ] ) ) + result[ i ] = _.escape.unwrap( result[ i ] ); + } + } + +} + +splitInlinedStereo_.defaults = +{ + src : null, + prefix : '❮', + postfix : '❯', + onInlined : null, + onOrdinary : null, + + stripping : 0, + quoting : 0, + quotingPrefixes : null, + quotingPostfixes : null, + + preservingQuoting : 1, + preservingEmpty : 0, /* changed */ + preservingDelimeters : 0, + inliningDelimeters : 0, /* new */ + preservingOrdinary : 1, + preservingInlined : 1, +} + +// + +// function strSplitInlinedStereo_( o ) +// { +// /* +// New delimeter. +// was : 'this #background:red#is#background:default# text and is not'. +// is : 'this ❮background:red❯is❮background:default❯ text and is not'. +// */ + +// if( _.strIs( o ) ) +// o = { src : o }; +// o.quotingPrefixes = o.quotingPrefixes || [ '"' ]; +// o.quotingPostfixes = o.quotingPostfixes || [ '"' ]; + +// _.assert( this === _ ); +// _.assert( _.strIs( o.src ) ); +// _.assert( _.object.isBasic( o ) ); +// _.assert( arguments.length === 1, 'Expects single argument' ); +// _.routine.options( strSplitInlinedStereo_, o ); + +// /* Trivial cases */ +// let end = handleTrivial(); +// if( end !== false ) +// return end; + +// let replacementForPrefix = '\u{20330}'; +// let isReplacedPrefix = false; +// let splitOptions = _.mapOnly_( null, o, strSplit.defaults ); +// splitOptions.preservingDelimeters = 1; /* for distinguishing between inlined and ordinary */ +// splitOptions.delimeter = o.prefix === o.postfix ? o.prefix : [ o.prefix, o.postfix ]; +// splitOptions.stripping = 0; +// splitOptions.preservingEmpty = 1; + +// let result = _.strSplit( splitOptions ); /* array with separated ordinary, inlined and delimeters */ +// result = preprocessBeforeJoin( result ); + +// if( o.inliningDelimeters ) /* new */ +// result = _.strSplitsQuotedRejoin +// ({ +// splits : result, +// delimeter : [ o.prefix, o.postfix ], +// quoting : 1, +// quotingPrefixes : [ o.prefix ], +// quotingPostfixes : [ o.postfix ], +// preservingQuoting : o.preservingDelimeters, +// inliningQuoting : 0, +// onQuoting : o.preservingEmpty ? escapeInlined( o.onInlined ) : o.onInlined +// }); + +// if( o.preservingEmpty ) +// handlePreservingEmpty(); + +// unescape(); + +// if( isReplacedPrefix ) +// result = result.map( ( el ) => +// { +// if( _.strIs( el ) ) +// return el.replace( replacementForPrefix, o.prefix ) +// else +// return el; +// }); + +// return result; + +// /* - */ + +// function handleTrivial() +// { +// let delimLeftPosition = o.src.indexOf( o.prefix ); +// let delimRightPosition = o.src.indexOf( o.postfix ); + +// if( delimLeftPosition === -1 || delimRightPosition === -1 ) +// { +// if( o.preservingOrdinary ) +// return [ o.src ]; +// else +// return []; +// } + +// if( !o.preservingOrdinary && !o.preservingInlined ) +// return []; + +// let splitted = o.src.split( o.prefix ); + +// if( splitted.length === 1 ) +// { +// if( o.preservingOrdinary ) +// return [ o.src ]; +// else +// return []; +// } + +// return false; +// } + +// /* */ + +// function escapeInlined( func ) +// { +// return function ( el ) +// { +// return _.escape.wrap( func( el ) ); +// } +// } + +// /* */ + +// function preprocessBeforeJoin( array ) +// { +// let ordinary = ''; +// let result = [] +// for( let i = 0; i < array.length; i++ ) +// { +// /* +// [ '', '❮', ' ', '❮', ' ', '❮', 'inline1', '❯', ' ', '❯', ' inline2' ] +// into +// [ '❮ ❮ ', '❮', 'inline1', '❯', ' ❯ inline2' ] +// */ +// if( array[ i ] === o.prefix ) +// { +// if( array[ i + 2 ] === o.postfix ) +// { +// /* push concatenated ordinary string */ +// pushOrdinary( result, ordinary ); +// /* push inlined : '❮', 'inline1', '❯' */ +// if( o.preservingInlined ) +// { +// result.push( array[ i ] ); +// result.push( o.stripping ? array[ i+1 ].trim() : array[ i+1 ] ); +// result.push( array[ i+2 ] ); +// } +// i += 2; +// ordinary = ''; +// } +// else +// { +// ordinary += array[ i ]; +// } +// } +// else +// { +// ordinary += array[ i ]; +// } +// } + +// pushOrdinary( result, ordinary ); + +// return result; +// } + +// /* */ + +// function pushOrdinary( result, ordinary ) +// { +// if( o.preservingOrdinary && ordinary ) +// { +// if( ordinary === o.prefix ) +// { +// result.push( replacementForPrefix ); +// isReplacedPrefix = true; +// } +// else +// { +// ordinary = o.stripping ? ordinary.trim() : ordinary; +// if( o.onOrdinary ) +// { +// let ordinary1 = o.onOrdinary( ordinary ); +// ordinary = ordinary1 ? ordinary1 : ordinary; +// } + +// result.push( ordinary ); +// } +// } +// } + +// /* */ + +// function handlePreservingEmpty() +// { +// if( _.escape.is( result[ 0 ] ) ) +// { +// result.unshift( '' ); +// } +// if( _.escape.is( result[ result.length-1 ] ) ) +// { +// result.push( '' ); +// } +// let len = result.length; +// for( let i = 0; i < len; i++ ) +// { +// if( _.escape.is( result[ i ] ) ) +// if( _.escape.is( result[ i + 1 ] ) ) +// { +// result.splice( i + 1, 0, '' ); +// len++; +// } +// } +// } + +// /* */ + +// function unescape() +// { +// for( let i = 0; i < result.length; i++ ) +// { +// if( _.escape.is( result[ i ] ) ) +// result[ i ] = _.escape.unwrap( result[ i ] ); +// } +// } + +// } + +// strSplitInlinedStereo_.defaults = +// { +// src : null, +// prefix : '❮', +// postfix : '❯', +// onInlined : ( e ) => [ e ], +// onOrdinary : null, + +// stripping : 0, +// quoting : 0, +// quotingPrefixes : null, +// quotingPostfixes : null, + +// preservingQuoting : 1, +// preservingEmpty : 0, /* changed */ +// preservingDelimeters : 0, +// inliningDelimeters : 1, /* new */ +// preservingOrdinary : 1, +// preservingInlined : 1, +// } + + +// -- +// converter +// -- + +function from( src ) +{ + + if( src === null ) + return src; + if( src === undefined ) + return src; + + if( _.primitive.is( src ) ) + return String( src ); + + if( _.bufferAnyIs( src ) ) + return _.bufferToStr( src ); + + _.assert( _.strIs( src ) ); + return src; +} + +// -- +// parser +// -- + +function parseType( src ) +{ + /* + - 'string' + - '5' + - '5n' + - 'null' + - 'undefined' + - 'Escape( 1 )' + - '{- Symbol undefined -}' + - '{- routine name -}' + - '{- routine.anonymous -}' + - '{- Map -}' + - '{- Map name -}' + - '{- Map with 9 elements -}' + - '{- Map.polluted with 9 elements -}' + - '{- Map name with 9 elements -}' + */ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ), 'Expects string' ); + + if( !( /^{- .+ -}$/g.test( src ) ) ) + return Object.create( null ); + + src = src.slice( 3, -3 ); + + return _.str._parseType( src ); + +} + +// + +function _parseType( src ) +{ + /* + + {- with with 2 elements -} 4 + {- with name with 2 elements -} 5 + {- with.with with with 2 elements -} 5 + + */ + _.assert( _.strIs( src ), 'Expects string' ); + + let o = + { + type : '', + traits : [], + } + + let splitted = src.split( ' ' ); + let type = splitted[ 0 ]; + let length; + + if( splitted.length === 2 ) /* with name & no length */ + { + o.name = splitted[ 1 ]; + } + else if( splitted.length === 4 ) /* without name & with length */ + { + length = +splitted[ 2 ]; + } + else if( splitted.length === 5 ) /* with name & with length */ + { + o.name = splitted[ 1 ]; + length = +splitted[ 3 ]; + } + + length = isNaN( length ) ? null : length; + + if( type.indexOf( '.' ) === -1 ) + { + o.type = type; + } + else + { + let [ t, ... traits ] = type.split( '.' ); + o.type = t; + o.traits = traits; + } + + if( length !== null ) + o.length = length; + + return o; + +} + +// -- +// xxx : implement +// -- + +let StrExtension = +{ + + // exporter + + _exportStringDiagnosticShallow, + exportStringDiagnosticShallow, + _exportStringCodeShallow, + exportStringCodeShallow, + exportString : exportStringDiagnosticShallow, + + // parser + + parseType, /* xxx : move */ + _parseType, + + quote, + unquote, + quotePairsNormalize, + quoteAnalyze, + _leftSingle_, + left_, + right_, + + insideOf, + insideOf_, + outsideOf, + + _removedBegin, + removeBegin, + _removedEnd, + removeEnd, + + replaceBegin, + replaceEnd, + replace, + + strip, + stripLeft, + stripRight, + + _removeAllSpaces, + _stripEmptyLines, + + splitsCoupledGroup, + splitsUngroupedJoin, + splitsQuotedRejoin, + splitsDropDelimeters, + splitsStrip, + splitsDropEmpty, + + splitFast, + split, + splitNonPreserving, + + splitInlined, + splitInlinedStereo_, + + from, + +} + +/* xxx : duplicate exportString in namespace::diagnostic? */ + +/* _.props.extend */Object.assign( _.str, StrExtension ); + +// -- +// +// -- + +let EntityExtension = +{ + + // exportStringSimple, /* xxx : deprecate? */ + // exportStringDiagnosticShallow, + // + // _exportStringShallow, + // exportString : exportStringDiagnosticShallow, + // exportStringCodeShallow, + // exportStringDiagnosticShallow, + // + // // exportStringShallowFine : exportStringDiagnosticShallow, /* xxx : remove */ + // // exportStringSolo, + +} + +/* xxx : duplicate exportString in namespace::diagnostic? */ + +// + +/* _.props.extend */Object.assign( _.entity, EntityExtension ); + +// -- +// extension +// -- + +let ToolsExtension = +{ + + // decorator + + strQuote : quote, + strUnquote : unquote, + strQuotePairsNormalize : quotePairsNormalize, + strQuoteAnalyze : quoteAnalyze, + + // splitter + + _strLeftSingle_ : _leftSingle_, + strLeft_ : left_, + _strRightSingle_ : _rightSingle_, + strRight_ : right_, + + strsEquivalentAll : _.vectorizeAll( _.str.equivalent.bind( _.str ), 2 ), + strsEquivalentAny : _.vectorizeAny( _.str.equivalent.bind( _.str ), 2 ), + strsEquivalentNone : _.vectorizeNone( _.str.equivalent.bind( _.str ), 2 ), + + strInsideOf : insideOf, + strInsideOf_ : insideOf_, + strOutsideOf : outsideOf, /* !!! deprecate */ + + // replacers + + _strRemovedBegin : _removedBegin, + strRemoveBegin : removeBegin, + _strRemovedEnd : _removedEnd, + strRemoveEnd : removeEnd, + + strReplaceBegin : replaceBegin, + strReplaceEnd : replaceEnd, + strReplace : replace, + + // stripper + + strStrip : strip, + strStripLeft : stripLeft, + strStripRight : stripRight, + _strRemoveAllSpaces : _removeAllSpaces, + strRemoveAllSpaces : _.vectorize( _removeAllSpaces ), + _strStripEmptyLines : _stripEmptyLines, + strStripEmptyLines : _.vectorize( _stripEmptyLines ), + + // split + + strSplitsCoupledGroup : splitsCoupledGroup, + strSplitsUngroupedJoin : splitsUngroupedJoin, + strSplitsQuotedRejoin : splitsQuotedRejoin, /* qqq : light coverage required */ + strSplitsDropDelimeters : splitsDropDelimeters, /* qqq : light coverage required */ + strSplitsStrip : splitsStrip, + strSplitsDropEmpty : splitsDropEmpty, + + strSplitFast : splitFast, + strSplit : split, + strSplitNonPreserving : splitNonPreserving, + + strSplitInlined : splitInlined, + strSplitInlinedStereo_ : splitInlinedStereo_, + + // converter + + strFrom : from, + +} + +_.props.extend( _, ToolsExtension ); + +_.assert( !!_.strSplit.defaults.preservingEmpty ); + +// + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Str.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Str_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Str_s */ })(); + +/* */ /* begin of file Stringer_s */ ( function Stringer_s() { function Stringer_s_naked() { ( function _l5_Stringer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Parent = _.seeker.Seeker; + +// -- +// implementation +// -- + +/* xxx : add to the list of types */ + +function head( o, o2 ) +{ + + if( o === null ) + o = Object.create( null ); + + if( o2 ) + _.props.supplement( o, o2 ); + + if( _.prototype.has( o, _.stringer.Stringer ) ) + return o; + + if( !o.Seeker ) + o.Seeker = Stringer; + + let it = o.Seeker.optionsToIteration( null, o ); + + _.assert( _.number.is( it.verbosity ) ); + _.assert( _.routine.is( it.tabLevelDown ) ); + + return it; +} + +// + +function iteratorInitBegin( iterator ) +{ + Parent.iteratorInitBegin.call( this, iterator ); + + iterator.dstNode = []; + + return iterator; +} + +// + +function resultExportString() +{ + let it = this; + return it.iterator.result; +} + +// + +function verbosityUp() +{ + let it = this; + let it2 = it.iterationMake(); + it2.tabLevelUp(); + it2.verbosity -= 1; + return it2; +} + +// + +function verbosityDown() +{ + let it = this; + return it; +} + +// + +function tabLevelUp() +{ + let it = this; + it.tab += it.dtab; + it.tabLevel += 1; + it.dstNode = []; + it.iterator.dstNode.push( it.dstNode ); + return it; +} + +// + +function tabLevelDown() +{ + let it = this; + it.tab = it.tab.slice( 0, it.tab.length - it.dtab.length ); + it.tabLevel -= 1; + return it; +} + +// + +function levelUp() +{ + let it = this; + it.level += 1; + return it; +} + +// + +function levelDown() +{ + let it = this; + it.level -= 1; + return it; +} + +// + +function lineWrite( src ) +{ + let it = this; + _.assert( arguments.length === 1 ); + if( it.iterator.result.length ) + it.iterator.result += `${it.eol}${it.tab}${src}`; + else + it.iterator.result += `${it.tab}${src}`; + it.dstNode.push( `${it.tab}${src}` ); + return it; +} + +// + +function titleWrite( src ) +{ + let it = this; + _.assert( arguments.length === 1 ); + + let it2 = it.verbosityUp(); + it2.lineWrite( src ); + return it2; +} + +// + +function elementsWrite( src ) +{ + let it = this; + _.assert( arguments.length === 1 ); + + let it2 = it.verbosityUp(); + for( let e of src ) + { + it2.lineWrite( e ); + } + return it2; +} + +// + +function write( src ) +{ + let it = this; + _.assert( arguments.length === 1 ); + _.assert( _.str.is( src ) ); + it.iterator.result += src; + if( it.dstNode.length ) + it.dstNode[ it.iterator.dstNode.length-1 ] += src; + else + it.dstNode.push( src ); + return it; +} + +// + +function eolWrite() +{ + let it = this; + _.assert( arguments.length === 0 ); + it.write( it.eol ); + return it; +} + +// + +function tabWrite() +{ + let it = this; + _.assert( arguments.length === 0 ); + it.write( it.tab ); + return it; +} + +// + +function nodesExportString( src, o ) +{ + let result = ''; + + o = _.routine.options( nodesExportString, o ); + + act( src, o.tab ); + + return result; + + function act( src, tab ) + { + + if( _.str.is( src ) ) + { + if( result.length ) + result += '\n'; + result += tab + src; + return; + } + + if( _.array.is( src ) ) + { + src.forEach( ( e ) => act( e, tab + o.dtab ) ); + return; + } + + _.assert( 0 ); + } + +} + +nodesExportString.defaults = +{ + tab : '', + dtab : ' ', +} + +// -- +// +// -- + +const StringerClassExtension = Object.create( null ); +StringerClassExtension.constructor = function Stringer(){}; +StringerClassExtension.head = head; +StringerClassExtension.iteratorInitBegin = iteratorInitBegin; +StringerClassExtension.resultExportString = resultExportString; +StringerClassExtension.verbosityUp = verbosityUp; +StringerClassExtension.verbosityDown = verbosityDown; +StringerClassExtension.tabLevelUp = tabLevelUp; +StringerClassExtension.tabLevelDown = tabLevelDown; +StringerClassExtension.levelUp = levelUp; +StringerClassExtension.levelDown = levelDown; +StringerClassExtension.write = write; +StringerClassExtension.eolWrite = eolWrite; +StringerClassExtension.tabWrite = tabWrite; +StringerClassExtension.lineWrite = lineWrite; +StringerClassExtension.titleWrite = titleWrite; +StringerClassExtension.elementsWrite = elementsWrite; + +const Iterator = StringerClassExtension.Iterator = Object.create( null ); +Iterator.result = ''; +Iterator.dstNode = null; +Iterator.dtab = ' '; +Iterator.eol = _.str.lines.Eol.default; +Iterator.recursive = Infinity; +_.assert( !!Iterator.eol ); + +const Iteration = StringerClassExtension.Iteration = Object.create( null ); + +const IterationPreserve = StringerClassExtension.IterationPreserve = Object.create( null ); +IterationPreserve.tab = ''; +IterationPreserve.verbosity = 2; +IterationPreserve.tabLevel = 0; +IterationPreserve.level = 0; +IterationPreserve.dstNode = null; + +const Prime = {}; +const Stringer = _.seeker.classDefine +({ + name : 'Stringer', + parent : Parent, + prime : Prime, + seeker : StringerClassExtension, + iterator : Iterator, + iteration : Iteration, + iterationPreserve : IterationPreserve, +}); + +_.assert( Stringer.constructor.name === 'Stringer' ); +_.assert( Stringer.IterationPreserve.tab === '' ); +_.assert( Stringer.Iteration.tab === '' ); +_.assert( Stringer.Iterator.tab === undefined ); +_.assert( Stringer.tab === undefined ); + +// -- +// stringer extension +// -- + +let StringerExtension = +{ + + Stringer, + it : head, + nodesExportString, + +} + +Object.assign( _.stringer, StringerExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Stringer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Stringer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Stringer_s */ })(); + +/* */ /* begin of file Symbol_s */ ( function Symbol_s() { function Symbol_s_naked() { ( function _l5_Symbol_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.symbol = _.symbol || Object.create( null ); + +// -- +// symbol +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +// + +let Extension = +{ + +} + +Object.assign( _, ToolsExtension ); +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Symbol.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Symbol_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Symbol_s */ })(); + +/* */ /* begin of file Time_s */ ( function Time_s() { function Time_s_naked() { ( function _l5_Time_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +/** + * The routine spent() calculate spent time from time {-time-} and converts + * the value to formatted string with seconds. If the description {-description-} + * is provided, then routine prepend description to resulted string. + * + * @example + * let now = _time.now(); + * _.time.sleep( 500 ); + * let spent = _.time.spent( 'Spent : ', now ); + * console.log( spent ); + * // log : 'Spent : 0.5s' + * + * @param { String } description - The description for spent time. Optional parameter. + * @param { Number } time - The start time. + * @returns { Number } - Returns string with spent seconds. + * @function spent + * @throws { Error } If arguments.length is less than 1 or greater than 2. + * @throws { Error } If {-description-} is not a String. + * @throws { Error } If {-time-} is not a Number. + * @namespace wTools.time + * @extends Tools + */ + +/* qqq : introduce namespace _.units */ +/* xxx : expose units formatter interface in wTools */ +/* qqq xxx : use units formatters */ +function spent( description, time ) +{ + let now = _.time.now(); + + if( arguments.length === 1 ) + { + time = arguments[ 0 ]; + description = ''; + } + + _.assert( 1 <= arguments.length && arguments.length <= 2 ); + _.assert( _.number.is( time ) ); + _.assert( _.strIs( description ) ); + + let result = description + _.time.spentFormat( now-time ); + + return result; +} + +// + +/** + * The routine spentFormat() converts spent time in milliseconds to seconds. + * Routine returns string with seconds. + * + * @example + * let now = _time.now(); + * _.time.sleep( 500 ); + * let spent = _.time.now() - now; + * console.log( _.time.spentFormat( spent ) ); + * // log : '0.5s' + * + * @param { Number } spent - The time to convert, in ms. + * @returns { Number } - Returns string with spent seconds. + * @function spentFormat + * @throws { Error } If arguments.length is not equal to 1. + * @throws { Error } If {-spent-} is not a Number. + * @namespace wTools.time + * @extends Tools + */ + +function spentFormat( spent ) +{ + + _.assert( 1 === arguments.length ); + _.assert( _.number.is( spent ) ); + + let result = ( 0.001*( spent ) ).toFixed( 3 ) + 's'; + + return result; +} + +// -- +// extension +// -- + +let TimeExtension = +{ + + spent, + spentFormat, + +} + +// + +_.props.supplement( _.time, TimeExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Time.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Time_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Time_s */ })(); + +/* */ /* begin of file Type_s */ ( function Type_s() { function Type_s_naked() { ( function _l5_Type_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// +// -- + +// -- +// +// -- + +let Extension = +{ +}; + +// + +_.props.supplement( _, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Type.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Type_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Type_s */ })(); + +/* */ /* begin of file Units_s */ ( function Units_s() { function Units_s_naked() { ( function _l5_Units_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.units = _.units || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +var Extension = +{ + +} + +// + +var ToolsExtension = +{ + +} + +// + +Object.assign( _.units, Extension ); +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Units.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Units_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Units_s */ })(); + +/* */ /* begin of file Unroll_s */ ( function Unroll_s() { function Unroll_s_naked() { ( function _l5_Unroll_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// /** +// * The routine unrollMake() returns a new unroll-array maiden from {-src-}. +// * +// * Unroll constructed by attaching symbol _.unroll Symbol to ordinary array. Making an unroll normalizes its content. +// * +// * @param { Number|Long|Set|Null|Undefined } src - The number or other instance to make unroll-array. If null is provided, +// * then routine returns an empty Unroll. +// * +// * @example +// * let src = _.unroll.make(); +// * // returns [] +// * _.unrollIs( src ); +// * // returns true +// * +// * @example +// * let src = _.unroll.make( null ); +// * // returns [] +// * _.unrollIs( src ); +// * // returns true +// * +// * @example +// * let src = _.unroll.make( null, null ); +// * // returns [] +// * _.unrollIs( src ); +// * // returns true +// * +// * @example +// * let src = _.unroll.make( 3 ); +// * // returns [ undefined, undefined, undefined ] +// * _.unrollIs( src ); +// * // returns true +// * +// * @example +// * let src = _.unroll.make( [ 1, 2, 'str' ] ); +// * // returns [ 1, 2, 'str' ] +// * _.unrollIs( src ); +// * // returns true +// * +// * @returns { Unroll } - Returns a new Unroll maiden from {-src-}. +// * Otherwise, it returns the empty Unroll. +// * @function unrollMake +// * @throws { Error } If arguments.length is more then one. +// * @throws { Error } If {-src-} is not a number, not a Long, not Set, not null, not undefined. +// * @namespace Tools +// */ +// +// function unrollMake( src ) +// { +// let result = _.array.make( src ); +// _.assert( arguments.length === 0 || arguments.length === 1 ); +// _.assert( _.arrayIs( result ) ); +// result[ unrollSymbol ] = true; +// if( !_.unrollIs( src ) ) +// result = _.unroll.normalize( result ); +// return result; +// } +// +// // +// +// /** +// * The routine unrollMakeUndefined() returns a new Unroll with length equal to {-length-}. +// * If the argument {-length-} is not provided, routine returns new Unroll with the length defined from {-src-}. +// * +// * @param { Long|Number|Null } src - Any Long, Number or null. If {-length-} is not provided, then routine defines length from {-src-}. +// * @param { Number|Long|Null } length - Defines length of new Unroll. If null is provided, then length defines by {-src-}. +// * +// * @example +// * _.unroll.makeUndefined(); +// * // returns [] +// * +// * @example +// * _.unroll.makeUndefined( null ); +// * // returns [] +// * +// * @example +// * _.unroll.makeUndefined( null, null ); +// * // returns [] +// * +// * @example +// * _.unroll.makeUndefined( 3 ); +// * // returns [ undefined, undefined, undefined] +// * +// * @example +// * _.unroll.makeUndefined( 3, null ); +// * // returns [ undefined, undefined, undefined] +// * +// * @example +// * _.unroll.makeUndefined( [ 1, 2, 3 ] ); +// * // returns [ undefined, undefined, undefined ] +// * +// * @example +// * _.unroll.makeUndefined( [ 1, 2, 3 ], null ); +// * // returns [ undefined, undefined, undefined ] +// * +// * @example +// * _.unroll.makeUndefined( [ 1, 2, 3 ], 4 ); +// * // returns [ undefined, undefined, undefined, undefined ] +// * +// * @example +// * _.unroll.makeUndefined( [ 1, 2, 3, 4 ], [ 1, 2 ] ); +// * // returns [ undefined, undefined ] +// * +// * @example +// * let src = new F32x( [ 1, 2, 3, 4, 5 ] ); +// * let got = _.unroll.makeUndefined( src, 3 ); +// * console.log( got ); +// * // log [ undefined, undefined, undefined ] +// * +// * @returns { Unroll } Returns a new Unroll with length equal to {-length-} or defined from {-src-}. +// * If null passed, routine returns the empty Unroll. +// * @function unrollMakeUndefined +// * @throws { Error } If arguments.length is less then one or more then two. +// * @throws { Error } If argument {-src-} is not a Long, not null. +// * @throws { Error } If argument {-length-} is not a number, not a Long. +// * @namespace Tools +// */ +// +// function unrollMakeUndefined( src, length ) +// { +// if( arguments.length === 0 ) +// return _.unroll.make(); +// +// if( _.longIs( length ) ) +// { +// length = length.length; +// } +// if( length === undefined || length === null ) +// { +// if( src === null ) +// { +// length = 0; +// } +// else if( _.longLike( src ) ) +// { +// length = src.length; +// } +// else if( _.number.is( src ) ) +// { +// length = src; +// src = null; +// } +// else _.assert( 0 ); +// } +// +// _.assert( arguments.length === 1 || arguments.length === 2 ); +// _.assert( _.number.isFinite( length ) ); +// _.assert( _.longIs( src ) || src === null ); +// +// return _.unroll.make( length ); +// } +// +// // +// +// /** +// * The routine unrollFrom() performs conversion of {-src-} to unroll-array. +// * +// * If {-src-} is not unroll-array, routine unrollFrom() returns new unroll-array. +// * If {-src-} is unroll-array, then routine returns {-src-}. +// * +// * @param { Long|Set|Number|Null|Undefined } src - The number, array-like object or Unroll. If null is provided, +// * then routine returns an empty Unroll. +// * +// * @example +// * let got = _.unroll.from( null ); +// * // returns [] +// * _.unrollIs( got ); +// * // returns true +// * +// * @example +// * let got = _.unroll.from( 3 ); +// * // returns [ undefined, undefined, undefined ] +// * _.unrollIs( got ); +// * // returns true +// * +// * @example +// * let got = _.unroll.from( [ 1, 2, 'str' ] ); +// * // returns [ 1, 2, 'str' ] +// * console.log( _.unrollIs( got ) ); +// * // log true +// * +// * @example +// * let got = _.unroll.from( new F32x( [ 1, 2, 0 ] ) ); +// * // returns [ 1, 2, 0 ] +// * console.log( _.unrollIs( got ) ); +// * // log true +// * +// * @example +// * let got = _.unroll.from( new Set( [ 1, 2, 'str' ] ) ); +// * // returns [ 1, 2, 'str' ] +// * console.log( _.unrollIs( got ) ); +// * // log true +// * +// * @example +// * let src = _.unroll.make( [ 1, 2, 'str' ] ); +// * let got = _.unroll.from( src ); +// * // returns [ 1, 2, 'str' ] +// * console.log ( src === got ); +// * // log true +// * +// * @returns { Unroll } Returns Unroll converted from {-src-}. If {-src-} is Unroll, then routine returns {-src-}. +// * @function unrollFrom +// * @throws { Error } If arguments.length is less or more then one. +// * @throws { Error } If argument {-src-} is not Long, not number, not Set, not null, not undefined. +// * @namespace Tools +// */ +// +// function unrollFrom( src ) +// { +// _.assert( arguments.length === 1 ); +// if( _.unrollIs( src ) ) +// return src; +// return _.unroll.make( src ); +// } + +// // +// +// /** +// * The routine unrollsFrom() performs conversion of each argument to unroll-array. +// * The routine returns unroll-array contained unroll-arrays converted from arguments. +// * +// * @param { Long|Set|Number|Null|Undefined } srcs - The objects to be converted into Unrolls. +// * +// * @example +// * let got = _.unrollsFrom( null ); +// * // returns [ [] ] +// * _.unrollIs( got ); +// * // true true +// * +// * @example +// * let got = _.unrollsFrom( [ 1, 2, 'str' ] ); +// * // returns [ [ 1, 2, 'str' ] ] +// * _.unrollIs( got ); +// * // returns true +// * _.unrollIs( got[ 0 ] ); +// * // returns true +// * +// * @example +// * let got = _.unrollsFrom( [], 1, null, [ 1, 'str' ] ); +// * // returns [ [], [ undefined ], [], [ 1, 'str' ] ] +// * _.unrollIs( got ); +// * // returns true +// * _.unrollIs( got[ 0 ] ); +// * // returns true +// * _.unrollIs( got[ 1 ] ); +// * // returns true +// * _.unrollIs( got[ 2 ] ); +// * // returns true +// * _.unrollIs( got[ 3 ] ); +// * // returns true +// * +// * @returns { Unroll } - Returns Unroll contained Unrolls converted from arguments. +// * @function unrollsFrom +// * @throws { Error } If arguments.length is less then one. +// * @throws { Error } If any of the arguments is not a Long, not a Set, not a Number, not null, not undefined. +// * @namespace Tools +// */ +// +// function unrollsFrom( srcs ) +// { +// _.assert( arguments.length >= 1 ); +// +// let result = _.unroll.make( null ); +// +// for( let i = 0; i < arguments.length; i++ ) +// { +// if( _.unrollIs( arguments[ i ] ) ) +// result.push( arguments[ i ] ); +// else +// result.push( _.unroll.make( arguments[ i ] ) ); +// } +// +// return result; +// } + +// + +// /** +// * The routine unrollFromMaybe() performs conversion of {-src-} to unroll-array. +// * +// * @param { * } src - The object to make Unroll. +// * If {-src-} has incompatible type, then routine returns original {-src-}. +// * If {-src-} is unroll-array, then routine returns original {-src-}. +// * If {-src-} is not unroll-array, and it converts into unroll-array, then routine +// * unrollFromMaybe() returns new unroll-array. +// * +// * @example +// * let got = _.unroll.fromMaybe( 'str' ); +// * // returns 'str' +// * +// * @example +// * let got = _.unroll.fromMaybe( { a : 1 } ); +// * // returns { a : 1 } +// * +// * @example +// * let got = _.unroll.fromMaybe( null ); +// * // returns [] +// * console.log( _.unrollIs( unroll ) ); +// * // log true +// * +// * @example +// * let src = _.unroll.make( [ 1, 2, 'str' ] ); +// * let got = _.unroll.fromMaybe( src ); +// * console.log ( src === got ); +// * // log true +// * +// * @returns { Unroll|* } - If it possible, routine returns Unroll converted from {-src-}. +// * If {-src-} is Unroll or incompatible type, it returns original {-src-}. +// * @function unrollFromMaybe +// * @throws { Error } If arguments.length is less or more then one. +// * @namespace Tools +// */ +// +// function unrollFromMaybe( src ) +// { +// _.assert( arguments.length === 1 ); +// // if( _.unrollIs( src ) || _.strIs( src ) || _.bool.is( src ) || _.mapIs( src ) || src === undefined ) +// // return src; +// // return _.unroll.make( src ); +// if( _.unrollIs( src ) ) /* previous implementation is wrong */ /* Condition of routine can be combined by another order */ +// return src; +// else if( _.longIs( src ) || _.number.is( src ) || src === null ) +// return _.unroll.make( src ); +// else +// return src; +// } + +// + +// /** +// * The routine unrollNormalize() performs normalization of {-dstArray-}. +// * Normalization is unrolling of Unrolls, which is elements of {-dstArray-}. +// * +// * If {-dstArray-} is unroll-array, routine unrollNormalize() returns unroll-array +// * with normalized elements. +// * If {-dstArray-} is array, routine unrollNormalize() returns array with unrolled elements. +// * +// * @param { Array|Unroll } dstArray - The Unroll to be unrolled (normalized). +// * +// * @example +// * let unroll = _.unroll.from( [ 1, 2, _.unroll.make( [ 3, 'str' ] ) ] ); +// * let result = _.unroll.normalize( unroll ) +// * console.log( result ); +// * // log [ 1, 2, 3, 'str' ] +// * console.log( _.unrollIs( result ) ); +// * // log true +// * +// * @example +// * let unroll = _.unroll.from( [ 1,'str' ] ); +// * let result = _.unroll.normalize( [ 1, unroll, [ unroll ] ] ); +// * console.log( result ); +// * // log [ 1, 1, 'str', [ 1, 'str' ] ] +// * console.log( _.unrollIs( result ) ); +// * // log false +// * +// * @returns { Array } If {-dstArray-} is array, routine returns an array with normalized elements. +// * @returns { Unroll } If {-dstArray-} is Unroll, routine returns an Unroll with normalized elements. +// * @function unrollNormalize +// * @throws { Error } If ( arguments.length ) is not equal to one. +// * @throws { Error } If argument ( dstArray ) is not arrayLike. +// * @namespace Tools +// */ +// +// function unrollNormalize( dstArray ) +// { +// +// _.assert( arguments.length === 1 ); +// _.assert( _.arrayIs( dstArray ), () => `Expects array as the first argument {-dstArray-} but got "${ dstArray }"` ); +// +// for( let a = 0 ; a < dstArray.length ; a++ ) +// { +// if( _.unrollIs( dstArray[ a ] ) ) +// { +// let args = [ a, 1 ]; +// args.push.apply( args, dstArray[ a ] ); +// dstArray.splice.apply( dstArray, args ); +// a += args.length - 3; +// /* no normalization of ready unrolls, them should be normal */ +// } +// else if( _.arrayIs( dstArray[ a ] ) ) +// { +// _.unroll.normalize( dstArray[ a ] ); +// } +// } +// +// return dstArray; +// } + +// // +// +// /** +// * The routine unrollSelect() returns a copy of a portion of {-src-} into a new Unroll. The portion of {-src-} selected +// * by {-range-}. If end index of new Unroll is more then src.length, then routine appends elements with {-val-} value. +// * The original {-src-} will not be modified. +// * +// * @param { Long } src - The Long from which makes a shallow copy. +// * @param { Range|Number } range - The two-element src that defines the start index and the end index for copying elements. +// * If {-range-} is number, then it defines the start index, and the end index sets to src.length. +// * If {-range-} is undefined, routine returns Unroll with copy of {-src-}. +// * If range[ 0 ] < 0, then start index sets to 0, the end index increments by absolute value of range[ 0 ]. +// * If range[ 1 ] <= range[ 0 ], then routine returns empty Unroll. +// * @param { * } val - The object of any type for insertion. +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.unrollSelect( src ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5 ] +// * console.log( _.unrollIs( got ) ); +// * // log true +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.unrollSelect( src, 2, [ 'str' ] ); +// * console.log( got ); +// * // log [ 3, 4, 5 ] +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.unrollSelect( src, [ 1, 4 ], [ 'str' ] ); +// * console.log( got ); +// * // log [ 2, 3, 4 ] +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.unrollSelect( src, [ -2, 6 ], [ 'str' ] ); +// * console.log( got ); +// * // log [ 1, 2, 3, 4, 5, 'str', 'str', 'str' ] +// * console.log( got === src ); +// * // log false +// * +// * @example +// * var src = [ 1, 2, 3, 4, 5 ]; +// * var got = _.unrollSelect( src, [ 4, 1 ], [ 'str' ] ); +// * console.log( got ); +// * // log [] +// * console.log( got === src ); +// * // log false +// * +// * @returns { Unroll } Returns a copy of portion of source Long with appended elements that is defined by range. +// * @function unrollSelect +// * @throws { Error } If arguments.length is less then one or more then three. +// * @throws { Error } If argument {-src-} is not an Array or Unroll. +// * @throws { Error } If range.length is less or more then two. +// * @throws { Error } If range elements is not a number / undefined. +// * @namespace Tools +// */ +// +// function unrollSelect( src, range, val ) +// { +// let result; +// +// if( range === undefined ) +// return _.unroll.make( src ); +// +// if( _.number.is( range ) ) +// range = [ range, src.length ]; +// +// let f = range[ 0 ] !== undefined ? range[ 0 ] : 0; +// let l = range[ 1 ] !== undefined ? range[ 1 ] : src.length; +// +// _.assert( _.longIs( src ) ); +// _.assert( _.intervalIs( range ) ) +// _.assert( 1 <= arguments.length && arguments.length <= 3 ); +// +// if( l < f ) +// l = f; +// +// if( f < 0 ) +// { +// l -= f; +// f -= f; +// } +// +// if( f === 0 && l === src.length ) +// return _.unroll.make( src ); +// +// result = _.unroll.makeUndefined( src, l-f ); +// +// /* */ +// +// let f2 = Math.max( f, 0 ); +// let l2 = Math.min( src.length, l ); +// for( let r = f2 ; r < l2 ; r++ ) +// result[ r-f ] = src[ r ]; +// +// /* */ +// +// if( val !== undefined ) +// { +// for( let r = 0 ; r < -f ; r++ ) +// result[ r ] = val; +// for( let r = l2 - f; r < result.length ; r++ ) +// result[ r ] = val; +// } +// +// /* */ +// +// return result; +// } + +// -- +// implementation +// -- + +let unrollSymbol = Symbol.for( 'unroll' ); + +let ToolsExtension = +{ + + /* qqq : for junior : duplicate namespace unroll */ + /* qqq : for junior : make the list of unduplicated namespaces */ + + // unrollMake, + // unrollMakeUndefined, + // unrollFrom, + // unrollsFrom, + // unrollFromMaybe, + // unrollNormalize, + + // unrollSelect, + + // unrollPrepend, + // unrollAppend, + // unrollRemove, + +} + +// + +_.props.supplement( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Unroll.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Unroll_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Unroll_s */ })(); + +/* */ /* begin of file Vector_s */ ( function Vector_s() { function Vector_s_naked() { ( function _l5_Vector_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.vector = _.vector || Object.create( null ); + +// -- +// implementation +// -- + +/** + * The hasLength() routine determines whether the passed value has the property (length). + * + * If {-srcMap-} is equal to the (undefined) or (null) false is returned. + * If {-srcMap-} has the property (length) true is returned. + * Otherwise false is. + * + * @param { * } src - The object to be checked. + * + * @example + * _.hasLength( [ 1, 2 ] ); + * // returns true + * + * @example + * _.hasLength( 'Hello there!' ); + * // returns true + * + * @example + * let isLength = ( function() { + * return _.hasLength( arguments ); + * } )( 'Hello there!' ); + * // returns true + * + * @example + * _.hasLength( 10 ); + * // returns false + * + * @example + * _.hasLength( {} ); + * // returns false + * + * @returns { boolean } Returns true if {-srcMap-} has the property (length). + * @function hasLength + * @namespace Tools + */ + +function hasLength( src ) +{ + if( src === undefined || src === null ) + return false; + if( _.number.is( src.length ) ) + return true; + return false; +} + +// -- +// extension +// -- + +var Extension = +{ + + hasLength, + +} + +// + +Object.assign( _.vector, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/Vector.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Vector_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Vector_s */ })(); + +/* */ /* begin of file zModule_s */ ( function zModule_s() { function zModule_s_naked() { ( function _l5_Module_s_() +{ + +'use strict'; + +// + +const _global = _global_; +const _ = _global_.wTools; +const __ = _realGlobal_.wTools; +let ModuleFileNative = null; + +let __fileNativeInclude; +if( typeof require !== 'undefined' ) +__fileNativeInclude = require; +else if( typeof importScripts !== 'undefined' ) +__fileNativeInclude = importScripts; +else if( _global._remoteRequire ) +__fileNativeInclude = _global._remoteRequire; + +const hasModuleFileDescriptor = !( typeof module === 'undefined' ); + +/* = concepts + +Module +ModuleFile +EntryFile +ModulesEnvironment + +*/ + +// -- +// Module methods +// -- + +function moduleExportString() +{ + return `{- ${this.constructor.name} ${this.name} -}`; +} + +// -- +// Module File methods +// -- + +function moduleFileExportString() +{ + return `{- ${this.constructor.name} ${this.sourcePath} -}`; +} + +// + +function moduleFileReturnedGet() +{ + if( !this.native ) + return; + return this.native.exports; +} + +// xxx : use later +// // +// +// function ModuleFileReturnedSet( val ) +// { +// if( !this.native ) +// return; +// return this.native.exports = val; +// } + +// -- +// module +// -- + +function is( src ) +{ + if( !src ) + return false; + if( Reflect.hasOwnProperty( src, 'constructor' ) ) + return false; + return src[ ModuleSymbol ] === true; +} + +// + +/* xxx : cover */ +function _with( name ) +{ + let module = _.module.withName( name ); + if( module ) + return module; + module = _.module.withPath( name ); + return module; +} + +// + +/* xxx : cover */ +function withName( name ) +{ + let module = _.module.modulesMap.get( name ); + if( !module ) + return null; + return module; +} + +// + +/* xxx : cover */ +function withPath( filePath ) +{ + let normalizedPath = _.path.canonize( filePath ); + let file = _.module.filesMap.get( normalizedPath ); + if( !file ) + return null; + return file.module; +} + +// + +function predeclare_head( routine, args ) +{ + + let o = args[ 0 ] + if( _.strIs( args[ 0 ] ) ) + o = { name : args[ 0 ], entryPath : ( args.length > 1 ? args[ 1 ] : null ) } + + _.routine.options( routine, o ); + + if( _.strIs( o.alias ) ) + o.alias = [ o.alias ]; + else if( o.alias === null ) + o.alias = []; + + if( !o.name ) + o.name = o.alias[ 0 ]; + + o.entryPath = _.array.as( o.entryPath ); + // o.entryPath = o.entryPath.map( ( path ) => _.path.canonize( path ) ); + + _.assert( _.arrayIs( o.alias ) ); + _.assert( _.strDefined( o.name ) ); + _.assert( _.mapIs( o ) ); + _.assert( o.files === undefined ); + + return o; +} + +// + +function predeclare_body( o ) +{ + + _.arrayPrependOnce( o.alias, o.name ); + _.assert( _.arrayIs( o.entryPath ) ); + + // if( o.name === 'wTesting' ) + // { + // console.log( `wTesting : ${o.entryPath}` ); + // debugger; + // } + + o.entryPath.forEach( ( entryPath, i ) => + { + if( _.path.isDotted( entryPath ) ) + { + if( o.basePath === null ) + o.basePath = _.path.dir( _.introspector.location({ level : 4 }).filePath ); + /* xxx : use _.introspector.dirPath */ + /* xxx : qqq : make sure _.introspector.location works properly for built-in routines ( without files ) */ + _.assert( _.strDefined( o.basePath ), '{-o.basePath-} is required if path is relative' ); + entryPath = o.entryPath[ i ] = _.path.canonize( o.basePath + '/' + entryPath ); + } + else + { + let normalized = _.path.canonize( entryPath ); + if( _.path.isAbsolute( normalized ) ) + entryPath = o.entryPath[ i ] = normalized; + } + + if( _.path.isAbsolute( entryPath ) ) + { + let module2 = _.module.predeclaredWithEntryPathMap.get( entryPath ); + _.assert + ( + !module2 || module2.name === o.name, + () => `Module ${o.name} is trying to register entry path ${entryPath} which is registered for ${module2}` + ); + _.module.predeclaredWithEntryPathMap.set( entryPath, o ); + } + else + { + _.assert( !_.path.isDotted( entryPath ) ); + let module2 = _.module.predeclaredWithEntryPathMap.get( entryPath ); + _.assert + ( + !module2 || module2.name === o.name, + () => `Module ${o.name} is trying to register entry path ${entryPath} which is registered for ${module2}` + ); + _.module.predeclaredWithEntryPathMap.set( entryPath, o ); + } + }); + + let module2 = _.module.predeclaredWithNameMap.get( o.name ); + if( module2 ) + { + _.assert( o.name === module2.name ); + _.arrayAppendArrayOnce( module2.entryPath, o.entryPath ); + _.arrayAppendArrayOnce( module2.alias, o.alias ); /* xxx : rename to names */ + _.arrayAppendArrayOnce( module2.filePath, o.entryPath ); + _.arrayAppendArrayOnce( module2.lookPath, o.entryPath ); + _.arrayAppendArrayOnce( module2.lookPath, o.alias ); + + register( module2, o.entryPath, o.alias ); + + let files = _.module._filesWithResolvedPath( o.entryPath ) + _.module._filesUniversalAssociateModule( files, module2, true ); + + return module2; + } + + register( o, o.entryPath, o.alias ); + + _.assert( o.files === undefined ); + o.files = null; + _.assert( o.filePath === undefined ); + o.filePath = o.filePath || []; + _.arrayAppendArray( o.filePath, o.entryPath ); + _.assert( o.lookPath === undefined ); + o.lookPath = [ ... o.entryPath, ... o.alias ]; + o.ups = new Set(); + o.downs = new Set(); + + delete o.basePath; + o.status = 0; + Object.setPrototypeOf( o, _.module.Module.prototype ); + Object.preventExtensions( o ); + + let files = _.module._filesWithResolvedPath( o.entryPath ) + _.module._filesUniversalAssociateModule( files, o, true ); + + return o; + + function register( module, entryPath, alias ) + { + entryPath.forEach( ( entryPath ) => _.module.predeclaredWithEntryPathMap.set( entryPath, module ) ); + alias.forEach( ( name ) => + { + let module3 = _.module.predeclaredWithNameMap.get( name ); + _.assert( module3 === undefined || module3 === module ); + _.module.predeclaredWithNameMap.set( name, module ); + }); + } +} + +predeclare_body.defaults = +{ + name : null, + alias : null, + entryPath : null, + basePath : null, +} + +const predeclare = _.routine.unite( predeclare_head, predeclare_body ); + +// + +function predeclareAll( o ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.mapIs( o.modules ) ); + _.routine.options( predeclareAll, arguments ); + + for( let k in o.modules ) + { + let module = o.modules[ k ]; + _.assert( module.name === k || module.name === undefined ); + _.assert( _.mapIs( module ) ); + module.name = k; + if( !module.basePath ) + module.basePath = o.basePath; + _.module.predeclare( module ); + delete o.modules[ k ]; + } + +} + +predeclareAll.defaults = +{ + modules : null, + basePath : null, +} + +// + +function _predeclaredWithEntryPath( entryPath ) +{ + let predeclaredModule = _.module.predeclaredWithEntryPathMap.get( entryPath ); + if( predeclaredModule ) + return predeclaredModule; +} + +// -- +// file +// -- + +/* qqq xxx : cover */ +function fileIs( src ) +{ + if( !src ) + return false; + if( !src.constructor ) + return false; + if( src.constructor.name === 'ModuleFile' ) + return true; + if( src instanceof ModuleFileNative ); + return true; + return false; +} + +// + +function fileUniversalFrom( src ) +{ + + if( _.module.fileUniversalIs( src ) ) + return src; + if( _.module.fileNativeIs( src ) ) + return src.universal || null; + + _.assert( 0, `Not clear how to deduce module file from ${_.entity.strType( src )}` ); +} + +// + +function _fileUniversalFinit( file ) +{ + _.assert( _.module.fileUniversalIs( file ) ); + + file.status = -1; + + file.native.children.forEach( ( nativeFile, index ) => + { + if( nativeFile.universal ) + _.module._fileUniversalDisassociateFile( nativeFile.universal, file ); + }); + + file.downFiles.forEach( ( file2 ) => + { + _.module._fileUniversalDisassociateFile( file, file2 ); + }); + + _.module._fileUniversalDisassociateModules( file, false ); + + if( Config.debug ) + { + let file2 = _.module.filesMap.get( file.sourcePath ); + _.assert( file2 === undefined || file2 === file ); + _.assert( file.downFiles.size === 0 ); + _.assert( file.upFiles.size === 0 ); + _.assert( file.modules.size === 0 ); + } + + _.module.filesMap.delete( file.sourcePath ); + Object.freeze( file ); +} + +// + +function _fileUniversalInit( o ) +{ + try + { + + o.sourcePath = _.path.canonize( o.sourcePath ); /* zzz : qqq : optimize */ + + let moduleFile2 = _.module.filesMap.get( o.sourcePath ); + if( moduleFile2 ) + { + if( moduleFile2.native !== o.native ) + { + moduleFile2.native = o.native; + } + return moduleFile2; + } + + if( Config.debug ) + verify(); + + o.native.universal = o; + Object.setPrototypeOf( o, _.module.File.prototype ); + _.module.filesMap.set( o.sourcePath, o ); + + o.moduleNativeFilesMap = o.moduleNativeFilesMap || _.module.nativeFilesMap; + o.global = o.global || _global; + o.error = o.error || null; + + pathsAmend(); + modulesAssociate(); + filesAssociate(); + + if( Config.debug ) + validate(); + + Object.preventExtensions( o ); + return o; + } + catch( err ) + { + err = _.err( err, `\nError in _.module._fileUniversalInit of ${o.sourcePath}` ); + throw err; + } + + /* - + + verify, + pathsAmend, + filesAssociate, + modulesAssociate, + validate, + + */ + + function verify() + { + _.assert( o.module === undefined ); + _.assert( o.modules === undefined ); + _.assert( o.downFile === undefined ); + _.assert( o.upFiles === undefined ); + _.assert( _.module.fileNativeIs( o.native ) ); + _.assert( o.native.universal === undefined ); + _.assert( !o.native.universal ); + _.assert( !o.native.moduleNativeFilesMap ); + _.assert + ( + _.module.nativeFilesMap[ _.path.nativizeMinimal( o.sourcePath ) ] === o.native, + `Module file ${o.sourcePath} is not in the current module files list` + ); + } + + /* - */ + + function pathsAmend() + { + /* qqq : cover */ + if( _.module._prependPath ) + _.arrayPrependArrayOnce( o.native.paths, _.module._prependPath ); + if( _.module._appendPath ) + _.arrayAppendArrayOnce( o.native.paths, _.module._appendPath ); + } + + /* - */ + + function filesAssociate() + { + +/* + +o.native.id - "/pro/builder/proto/wtools/atop/testing/include/Base.s" +o.native.parent.id - "/pro/builder/proto/wtools/atop/testing/include/Top.s" +xxx : test to check the parent has the child and the child has the parent + +o.native.id -- "/pro/builder/proto/wtools/atop/testing/include/Top.s" +xxx : test to check the module file has universal file for each children + +*/ + + o.downFiles = new Set; + + let parent = _.module.fileNativeParent( o.native ); + if( parent && parent.universal ) + { + _.module._fileUniversalAssociateFile( o, parent.universal ); + } + else + { + o.downFile = null; + } + + o.upFiles = new Set; + + o.native.children.forEach( ( file, index ) => + { + if( file.universal ) + { + _.module._fileUniversalAssociateFile( file.universal, o ); + } + }); + + } + + /* - */ + + function modulesAssociate() + { + + _.assert( o.module === undefined ); + _.assert( o.modules === undefined ); + + o.module = null; + o.modules = new Set(); + + let predeclaredModule = _.module._predeclaredWithEntryPath( o.sourcePath ); + if( predeclaredModule ) + { + _.module._fileUniversalAssociateModule( o, predeclaredModule ); + } + + if( !predeclaredModule ) + if( o.requestedSourcePath === null || _.path.isRelative( o.requestedSourcePath ) ) + { + + let parentNative = _.module.fileNativeParent( o.native ); + let parentModules; + if + ( + parentNative + && parentNative.universal + && o.moduleNativeFilesMap === parentNative.universal.moduleNativeFilesMap + && parentNative.universal.module + ) + { + _.assert( !!_.module.is( parentNative.universal.module ) ); + _.assert( parentNative.universal.module instanceof _.module.Module ); + _.assert( _.set.is( parentNative.universal.modules ) ); + parentModules = parentNative.universal.modules; + _.assert( parentModules.size > 0 ); + _.module._fileUniversalAssociateModule( o, parentModules ); + } + + } + + } + + /* - */ + + function validate() + { + _.assert( o instanceof _.module.File ); + _.assert( _.module.fileIs( o ) ); + _.assert( _.module.fileUniversalIs( o ) ); + _.assert( o.module !== undefined ); + } + + /* - */ + +} + +_fileUniversalInit.defaults = +{ + sourcePath : null, + nativeSourcePath : null, + requestedSourcePath : null, + native : null, + moduleNativeFilesMap : null, + error : null, + global : null, + status : null, +} + +// + +function _filesUniversalInit( o ) +{ + let visited = new Set; + let stack = []; + + _.routine.options( _filesUniversalInit, o ); + o.files = _.array.as( o.files ); + stack.push( ... o.files ); + + if( _.__GLOBAL_NAME__ === 'test1' ) + debugger; + + for( let i = 0 ; i < stack.length ; i++ ) + up( stack[ i ] ); + + while( stack.length ) + down( stack.pop() ); + + return visited; + + function up( file ) + { + if( visited.has( file ) ) + return; + visited.add( file ); + + stack.push( ... file.children ); + + _.assert( _.module.fileNativeIs( file ) ); + + let fileName = file.filename || file.id ; + if( !file.universal && _.module.nativeFilesMap[ fileName ] === file ) /* yyy */ + _.module._fileUniversalInit + ({ + sourcePath : fileName, + nativeSourcePath : fileName, + requestedSourcePath : null, + native : file, + status : 2, + }); + + } + + function down( file ) + { + + if( file.universal ) + file.children.forEach( ( file2, index ) => + { + if( file2.universal ) + { + _.module._fileUniversalAssociateFile( file2.universal, file.universal ); + if( file.universal.moduleNativeFilesMap === _.module.nativeFilesMap && file.universal.module ) + _.module._filesUniversalAssociateModule( file2.universal, file.universal.module, false ); + } + }); + + } + +} + +_filesUniversalInit.defaults = +{ + files : null, +} + +// + +function _fileUniversalAssociateFile( upFile, downFile ) +{ + + /* + files could belong to different environments! + */ + + if( !_.module.fileUniversalIs( upFile ) ) + debugger; + _.assert( _.module.fileUniversalIs( upFile ) ); + _.assert( _.module.fileUniversalIs( downFile) ); + + upFile.downFile = upFile.downFile || downFile; + upFile.downFiles.add( downFile ); + for( let module of upFile.modules ) + module.downs.add( ... _.set.butElement( null, downFile.modules, module ) ); /* qqq : cover and implement deleting */ + + downFile.upFiles.add( upFile ); + for( let module of downFile.modules ) + module.ups.add( ... _.set.butElement( null, upFile.modules, module ) ); + +} + +// + +function _fileUniversalDisassociateFile( upFile, downFile ) +{ + + /* + files could belong to different environments + */ + + _.assert( _.module.fileUniversalIs( upFile ) ); + _.assert( _.module.fileUniversalIs( downFile) ); + + upFile.downFiles.delete( downFile ); + if( upFile.downFile === downFile ) + upFile.downFile = [ ... upFile.downFiles ][ 0 ] || null; /* qqq : cover */ + + downFile.upFiles.delete( upFile ); + +} + +// + +function _fileUniversalAssociateModule( file, module ) +{ + let result = 0; + + if( Config.debug ) + { + _.assert( arguments.length === 2 ); + let module2 = _.module._predeclaredWithEntryPath( file.sourcePath ); + _.assert + ( + module2 === undefined || module2 === module, + () => `Attempt to associate ${file} with ${module}, but it is entry of ${module2}` + ); + } + + if( _.set.is( module ) ) + { + module.forEach( ( module ) => result += _.module._fileUniversalAssociateModule( file, module ) ); + return result; + } + + _.assert( _.module.fileUniversalIs( file ) ); + _.assert( _.module.is( module ) ); + + file.modules.add( module ); + file.module = file.module || module; + + result += 1; + + module.files = module.files || new HashMap(); + module.files.set( file.sourcePath, file ); + module.alias.forEach( ( name ) => + { + if( Config.debug ) + { + let module2 = _.module.modulesMap.get( name ); + _.assert( module2 === undefined || module2 === module ); + } + _.module.modulesMap.set( name, module ); + }); + + return result; +} + +// + +function _fileUniversalDisassociateModules( file, reassociating ) +{ + let result = 0; + + if( Config.debug ) + { + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.module.fileUniversalIs( file ) ); + } + + result += file.modules.size; + + if( !file.modules.size ) + return result; + + if( reassociating ) + reassociate(); + else + deassociate(); + + return result; + + function moduleDisassociate( module ) + { + module.files.delete( file.sourcePath ); + } + + function deassociate() + { + file.modules.forEach( ( module ) => moduleDisassociate( module ) ); + file.modules.clear(); + file.module = null; + } + + function reassociate() + { + let downModules = new Set(); + + file.downFiles.forEach( ( file2 ) => downModules.add( ... file2.modules ) ); + + file.modules.forEach( ( module ) => + { + if( !downModules.has( module ) ) + { + moduleDisassociate( module, downModules ); + file.modules.delete( module ); + if( module === file.module ) + file.module = null; + } + }); + + if( file.module = null && file.modules.size > 0 ) + { + debugger; /* xxx : qqq : cover */ + file.module = [ ... file.modules ][ 0 ]; + } + + } + +} + +// + +function _filesUniversalAssociateModule( files, modules, disassociating ) +{ + let visited = new Set; + let stack = []; + + files = _.countable.is( files ) ? files : [ files ]; + stack.push( ... files ); + + if( disassociating ) + files.forEach( ( file ) => _.module._fileUniversalDisassociateModules( file, false ) ); + + if( Config.debug ) + { + _.assert( _.module.is( modules ) || _.set.is( modules ) ); + if( _.set.is( modules ) ) + modules.forEach( ( module ) => _.assert( _.module.is( module ) ) ); + } + + if( _.set.is( modules ) ) + { + while( stack.length ) + modulesAssociate( stack.pop() ); + } + else + { + while( stack.length ) + moduleAssociate( stack.pop() ); + } + + return visited; + + /* - */ + + function modulesAssociate( file ) + { + if( visited.has( file ) ) + return; + visited.add( file ); + + _.assert( _.module.fileUniversalIs( file ) ); + _.assert( _.setIs( file.upFiles ) ); + + if( file.moduleNativeFilesMap !== _.module.nativeFilesMap ) + { + return; + } + + let module2 = _.module._predeclaredWithEntryPath( file.sourcePath ); + if( module2 && !modules.has( module2 ) ) + return; + // if( module2 && modules.size > 1 ) /* xxx2 */ + // _.assert( 0, 'not tested' ); /* xxx qqq : cover and fix */ + + if( _.set.identicalShallow( file.modules, modules ) ) + return; + + if( disassociating ) + _.module._fileUniversalDisassociateModules( file, true ); + + modules.forEach( ( module ) => singleAssociate( file, module ) ); + } + + /* - */ + + function moduleAssociate( file ) + { + if( visited.has( file ) ) + return; + visited.add( file ); + + let module = modules; + + _.assert( _.module.fileUniversalIs( file ) ); + _.assert( _.setIs( file.upFiles ) ); + + if( file.moduleNativeFilesMap !== _.module.nativeFilesMap ) + return; + + let module2 = _.module._predeclaredWithEntryPath( file.sourcePath ); + if( module2 && module2 !== module ) + return; + + if( file.modules.has( module ) ) + { + if( file.modules.size === 1 || !disassociating ) + return; + } + + if( disassociating ) + _.module._fileUniversalDisassociateModules( file, true ); + + singleAssociate( file, module ); + } + + /* - */ + + function singleAssociate( file, module ) + { + + file.upFiles.forEach( ( file2 ) => + { + if( file2 === undefined ) + debugger; /* xxx : qqq : cover */ + if( file2 === undefined ) + return; + stack.push( file2 ); + }); + + _.module._fileUniversalAssociateModule( file, module ); + } + + /* - */ + +} + +// + +function _fileWithResolvedPath( caninicalSourcePath ) +{ + _.assert( _.strIs( caninicalSourcePath ) ); + let result = _.module.filesMap.get( caninicalSourcePath ); + return result; +} + +// + +/* +this solution has limitations +is not going to work for special cases of multiple global namespace n > 2 +better solution might not exist +*/ + +function _fileWithResolvedPathAnyNamespace( caninicalSourcePath ) +{ + _.assert( _.strIs( caninicalSourcePath ) ); + let result = _.module.filesMap.get( caninicalSourcePath ); + if( !result ) /* yyy */ + for( let globalName in _globals_ ) + { + if( !_globals_[ globalName ].wTools || !_globals_[ globalName ].wTools.module || !_globals_[ globalName ].wTools.module.filesMap ) + continue; + result = _globals_[ globalName ].wTools.module.filesMap.get( caninicalSourcePath ); + if( result ) + return result; + } + return result; +} + +// + +function _filesWithResolvedPath( caninicalSourcePathCountable ) +{ + let result = new Set(); + if( _.strIs( caninicalSourcePathCountable ) ) + caninicalSourcePathCountable = [ caninicalSourcePathCountable ]; + caninicalSourcePathCountable.forEach( ( sourcePath ) => + { + let file = _.module.filesMap.get( sourcePath ); + if( file ) + result.add( file ); + }); + return result; +} + +// + +function fileWithResolvedPath( sourcePath ) +{ + var result = _.module.filesMap.get( _.path.canonize( sourcePath ) ); + return result; +} + +// + +/* xxx : qqq : cover please */ +function fileWith( relativeSourcePath, relativeLevel ) +{ + let absoluteSourcePath = relativeSourcePath; + + if( _.numberIs( relativeSourcePath ) ) + { + if( relativeLevel !== undefined ) + relativeSourcePath += relativeLevel; + _.assert( relativeSourcePath >= 0 ); + absoluteSourcePath = _.introspector.location({ level : relativeSourcePath + 1 }).filePath; + return _.module._fileWithResolvedPath( absoluteSourcePath ); + } + + if( _.path.isDotted( relativeSourcePath ) ) + { + /* zzz : qqq : optimize _.introspector.location({ level : 1 }).filePath */ + /* zzz : qqq : optimize _.path.dir( _.introspector.location({ level : 1 }).filePath ) */ + let level = 1; + if( relativeLevel !== undefined ) + level += relativeLevel; + let basePath = _.path.dir( _.introspector.location({ level }).filePath ); + absoluteSourcePath = _.path.canonize( basePath + '/' + absoluteSourcePath ); + } + else if( _.path.isGlobal( absoluteSourcePath ) ) + { + absoluteSourcePath = _.path.canonize( absoluteSourcePath ); + } + else + { + let downPath = _.introspector.location({ level : ( relativeLevel || 0 ) + 1 }).filePath; + absoluteSourcePath = this._fileResolve + ({ + sourcePaths : [ absoluteSourcePath ], + downPath : downPath, + withAlternatives : true, + all : false, + }); + } + + let moduleFile = _.module._fileWithResolvedPath( absoluteSourcePath ); + return moduleFile; +} + +// + +function fileInvalidate( relativeSourcePath ) +{ + // if( _.numberIs( relativeSourcePath ) ) + // relativeSourcePath += 1; + + let moduleFile = _.module.fileWith( relativeSourcePath, 1 ); + + if( !moduleFile ) + { + return false; + } + + _.module._fileUniversalFinit( moduleFile ); + delete moduleFile.moduleNativeFilesMap[ moduleFile.nativeSourcePath ]; + + return true; +} + +// + +function _fileNativeWithResolvedNativePath( caninicalSourcePath, nativeFilesMap ) +{ + nativeFilesMap = nativeFilesMap || _.module.nativeFilesMap; + let result = nativeFilesMap[ caninicalSourcePath ]; + return result; +} + +// + +function fileNativeWith( relativeSourcePath, nativeFilesMap ) +{ + let absoluteSourcePath = relativeSourcePath; + + if( _.numberIs( relativeSourcePath ) ) + { + _.assert( relativeSourcePath >= 0 ); + absoluteSourcePath = _.introspector.location({ level : relativeSourcePath + 1 }).filePath; + return _.module._fileNativeWithResolvedNativePath( _.path.nativizeMinimal( absoluteSourcePath ), nativeFilesMap ); + } + + if( _.path.isDotted( relativeSourcePath ) ) + { + let basePath = _.path.dir( _.introspector.location({ level : 1 }).filePath ); + absoluteSourcePath = _.path.nativizeMinimal( _.path.canonize( basePath + '/' + absoluteSourcePath ) ); + } + else + { + absoluteSourcePath = _.path.nativizeMinimal( absoluteSourcePath ); + } + + let moduleFile = _.module._fileNativeWithResolvedNativePath( absoluteSourcePath, nativeFilesMap ); + return moduleFile; +} + +// -- +// export string +// -- + +function _exportString( module, it ) +{ + + if( !it.verbosity ) + return it; + + it.lineWrite( String( module ) ); + + if( it.verbosity === 1 ) + return it; + + if( module.downs.size > 0 ) + it.titleWrite( 'downs' ).elementsWrite( module.downs ); + if( module.ups.size > 0 ) + it.titleWrite( 'ups' ).elementsWrite( module.ups ); + + return it; +} + +_exportString.defaults = +{ + it : null, +} + +// + +function exportString( module, o ) +{ + + o = _.routine.options( exportString, o || null ); + let it = o.it = _.stringer.it( o.it, { verbosity : 1, recursive : 1 } ); + it.opts = o; + it.src = module; + _export( module, it ); + return it; + + function _export( module, it ) + { + _.module._exportString( module, it ); + + // if( it.verbosity > 0 ) + // if( it.recursive - it.level > 1 ) + // if( module.upFiles.size > 0 ) + // { + // let it2 = it.iterationMake().tabLevelUp(); + // if( it.verbosity > 1 ) + // { + // it2.lineWrite( 'ups' ).tabLevelUp(); + // } + // for( let file2 of module.upFiles ) + // { + // _export( file2, it2.iterationMake().levelUp() ); + // } + // } + + } + +} + +exportString.defaults = +{ + format : 'diagnostic', + verbosity : 1, + it : null, +} + +// + +function _fileExportString( file, it ) +{ + + if( !it.verbosity ) + return it; + + it.lineWrite( String( file ) ); + + if( it.verbosity === 1 ) + return it; + + if( file.native._virtualEnvironment ) + it.titleWrite( `virtualEnvironment : ${file.native._virtualEnvironment.global.__GLOBAL_NAME__}` ); + if( file.global ) + it.titleWrite( `global : ${file.global.__GLOBAL_NAME__}` ); + if( file.error ) + it.titleWrite( `error : ${!!file.error}` ); + if( file.modules.size > 0 ) + it.titleWrite( 'modules' ).elementsWrite( file.modules ); + if( file.downFiles.size > 0 ) + it.titleWrite( 'downFiles' ).elementsWrite( file.downFiles ); + if( file.upFiles.size > 0 ) + it.titleWrite( 'upFiles' ).elementsWrite( file.upFiles ); + + return it; +} + +_fileExportString.defaults = +{ + it : null, +} + +// + +function fileExportString( file, o ) +{ + + _.assert( _.module.fileUniversalIs( file ), () => `Expects module file, but got ${_.strType( file )}` ); + o = _.routine.options( fileExportString, o || null ); + let it = o.it = _.stringer.it( o.it, { verbosity : 1, recursive : 1 } ); + _export( file, it ); + return it; + + function _export( file, it ) + { + _.module._fileExportString( file, it ); + + if( it.verbosity > 0 ) + if( it.recursive - it.level > 1 ) + if( file.upFiles.size > 0 ) + { + let it2 = it.iterationMake().tabLevelUp(); + if( it.verbosity > 1 ) + { + it2.lineWrite( 'ups' ).tabLevelUp(); + } + for( let file2 of file.upFiles ) + { + _export( file2, it2.iterationMake().levelUp() ); + } + } + + } + +} + +fileExportString.defaults = +{ + it : null, +} + +// + +function recursiveExportString( src, o ) +{ + let Format = new Set([ 'diagnostic' ]); + + o = _.routine.options( recursiveExportString, o || null ); + _.assert( Format.has( o.format ) ); + + let it = o.it = _.stringer.it( o.it ); + it.opts = o; + _.assert( _.number.is( it.depth ) ); + + if( _.module.fileIs( src ) ) + _.module.fileExport( src, { it } ); + else if( _.module.is( src ) ) + _.module.fileExport( src, { it } ); + + it.lineWrite( operation.clname ); + +} + +recursiveExportString.defaults = +{ + format : 'diagnostic', + it : null, +} + +// -- +// file path +// -- + +/* xxx : cover _.module.fileNativeIs() */ +/* xxx : cover and move on l3 */ +/* qqq : for junior : cover */ +function filePath_head( routine, args ) +{ + + let o = args[ 0 ]; + if( !_.mapIs( o ) ) + o = { paths : o } + if( _.strIs( o.paths ) ) + o.paths = [ o.paths ]; + + _.assert( args.length === 1 ); + _.assert( arguments.length === 2 ); + _.assert( _.arrayIs( o.paths ) ); + _.routine.options( filePathAmend, o ); + + if( _.path.nativizeMinimal && _.path.canonize ) + { + for( var p = 0 ; p < o.paths.length ; p++ ) + { + o.paths[ p ] = _.path.nativizeMinimal( _.path.canonize( o.paths[ p ] ) ); + } + } + + return o; +} + +// + +function filePathAmend_body( o ) +{ + const ModuleFileNative = require( 'module' ); + + if( o.moduleFile ) + if( typeof _ !== 'undefined' ) + o.moduleFile = fileNativeFrom( o.moduleFile ); + + let filePathAmend = o.amending === 'prepend' ? arrayPrependedArrayOnce : arrayAppendedArrayOnce; + + if( o.globally ) + filePathAmend( ModuleFileNative.globalPaths, o.paths ); + + if( o.locally && o.moduleFile ) + filePathAmend( o.moduleFile.paths, o.paths ); + + if( o.locally && o.permanent ) + { + if( o.amending === 'prepend' ) /* qqq : cover please */ + { + _.module._prependPath = _.module._prependPath || []; + filePathAmend( _.module._prependPath, o.paths ); + } + else if( o.amending === 'append' ) /* qqq : cover please */ + { + _.module._appendPath = _.module._appendPath || []; + filePathAmend( _.module._appendPath, o.paths ); + } + } + + if( o.locally && o.recursive && o.moduleFile ) + return _root( o.moduleFile, o.paths, new Set ); + + /* - */ + + function _root( _module, paths, visited ) + { + + if( visited.has( _module ) ) + return; + + if( o.recursive >= 2 ) + while( fileNativeParent( _module ) ) + _module = fileNativeParent( _module ); + + _children1( _module, paths, visited ); + } + + /* - */ + + function fileNativeParent( file ) + { + if( file.parent && file.parent.id !== undefined ) + return file.parent; + } + + /* - */ + + function _children1( _module, paths, visited ) + { + + if( visited.has( _module ) ) + return; + + visited.add( _module ); + + filePathAmend( _module.paths, paths ); + + if( o.recursive >= 2 ) + if( _module.children ) + { + for( var c = 0 ; c < _module.children.length ; c++ ) + _children2( _module.children[ c ], paths, visited ); + } + + } + + /* - */ + + function _children2( _module, paths, visited ) + { + + if( visited.has( _module ) ) + return; + + visited.add( _module ); + + filePathAmend( _module.paths, paths ); + + if( _module.children ) + { + for( var c = 0 ; c < _module.children.length ; c++ ) + _children2( _module.children[ c ], paths, visited ); + } + + } + + /* - */ + + function fileNativeFrom( src ) + { + if( _.module && _.module.fileNativeFrom ) + return _.module.fileNativeFrom( src ); + return src; + } + + /* - */ + + function arrayAppendedArrayOnce( dstArray, insArray ) + { + let result = 0; + + for( let i = 0, len = insArray.length ; i < len ; i++ ) + { + if( dstArray.indexOf( insArray[ i ] ) === -1 ) + { + dstArray.push( insArray[ i ] ); + result += 1; + } + } + + return result; + } + + /* - */ + + function arrayPrependedArrayOnce( dstArray, insArray ) + { + let result = 0; + + for( let i = insArray.length - 1 ; i >= 0 ; i-- ) + { + let index = i; + if( dstArray === insArray ) + index = i + result; + if( dstArray.indexOf( insArray[ index ] ) === -1 ) + { + dstArray.unshift( insArray[ index ] ); + result += 1; + } + } + + return result; + } + + /* - */ + +} + +filePathAmend_body.defaults = +{ + moduleFile : null, + paths : null, + permanent : 0, + globally : 1, + locally : 0, + recursive : 2, + amending : 'append', +} + +let filePathAmend = _.routine.unite( filePath_head, filePathAmend_body ); + +// + +function pathRemove_body( o ) +{ + const ModuleFileNative = require( 'module' ); + + if( o.moduleFile ) + o.moduleFile = _.module.fileNativeFrom( o.moduleFile ); + + if( o.globally ) + remove( ModuleFileNative.globalPaths, o.paths ); + + if( o.locally && o.moduleFile ) + remove( o.moduleFile.paths, o.paths ); + + if( o.locally && o.permanent ) + { + if( _.module._prependPath ) + remove( _.module._prependPath, o.paths ); + if( _.module._appendPath ) + remove( _.module._appendPath, o.paths ); + } + + if( o.locally && o.recursive && o.moduleFile ) + return _root( o.moduleFile, o.paths, new Set ); + + /* - */ + + function _root( _module, paths, visited ) + { + + if( visited.has( _module ) ) + return; + + if( o.recursive >= 2 ) + while( _.module.fileNativeParent( _module ) ) + _module = _.module.fileNativeParent( _module ); + + _children1( _module, paths, visited ); + } + + /* - */ + + function _children1( _module, paths, visited ) + { + + if( visited.has( _module ) ) + return; + + visited.add( _module ); + + remove( _module.paths, paths ); + + if( o.recursive >= 2 ) + if( _module.children ) + { + for( var c = 0 ; c < _module.children.length ; c++ ) + _children2( _module.children[ c ], paths, visited ); + } + + } + + /* - */ + + function _children2( _module, paths, visited ) + { + + if( visited.has( _module ) ) + return; + + visited.add( _module ); + + remove( _module.paths, paths ); + + if( _module.children ) + { + for( var c = 0 ; c < _module.children.length ; c++ ) + _children2( _module.children[ c ], paths, visited ); + } + + } + + /* - */ + + function remove( dst, src ) + { + for( let p = 0 ; p < src.length ; p++ ) + { + if( dst.indexOf( src[ p ] ) !== -1 ) + dst.splice( p, 1 ); + } + } + + /* - */ + +} + +pathRemove_body.defaults = +{ + moduleFile : null, + paths : null, + permanent : 0, + globally : 1, + locally : 0, + recursive : 2, + amending : 'append', +} + +let filePathRemove = _.routine.unite( filePath_head, pathRemove_body ); + +// + +function filePathGet( o ) +{ + const ModuleFileNative = require( 'module' ); + + if( !_.mapIs( o ) ) + o = { moduleFile : o } + + _.assert( arguments.length === 0 || arguments.length === 1 ); + o = _.routine.options( filePathGet, o ); + + if( o.all === null ) + o.all = o.locally && o.globally; + + let result = Object.create( null ); + if( o.locally ) + result.local = []; + if( o.globally ) + result.global = []; + if( o.all ) + result.all = []; + + if( o.moduleFile ) + o.moduleFile = _.module.fileNativeFrom( o.moduleFile ); + o.moduleFile = o.moduleFile || module; + + if( o.globally ) + { + _.assert( _.arrayIs( ModuleFileNative.globalPaths ) ); + result.global.push( ... ModuleFileNative.globalPaths ); + if( result.all ) + result.all.push( ... ModuleFileNative.globalPaths ); + } + + if( o.locally ) + { + _.assert( _.arrayIs( o.moduleFile.paths ) ); + result.local.push( ... o.moduleFile.paths ); + if( result.all ) + result.all.push( ... o.moduleFile.paths ); + } + + return result; +} + +filePathGet.defaults = +{ + moduleFile : null, + globally : 1, + locally : 1, + all : null, +} + +// -- +// +// -- + +function _resolve( o ) +{ + + // _.map.assertHasAll( o, _resolve.defaults ); + + if( _.argumentsArray.like( o.moduleName ) ) + { + let result = []; + for( let a = 0 ; a < o.moduleName.length ; a++ ) + { + let r = _.module._resolve + ({ + // basePath : o.basePath, + downPath : o.downPath, + moduleName : o.moduleName[ a ], + throwing : o.throwing, + withAlternatives : o.withAlternatives, + }); + if( r !== undefined ) + result[ a ] = r; + } + return result; + } + + if( o.moduleName === _.optional ) + return; + + let r = _.module._resolveFirst + ({ + moduleNames : [ o.moduleName ], + downPath : o.downPath, + // basePath : o.basePath, + throwing : o.throwing, + withAlternatives : o.withAlternatives, + }); + + return r; +} + +_resolve.defaults = +{ + // basePath : null, + downPath : null, + moduleName : null, + throwing : 0, + withAlternatives : 1, +} + +// + +function resolve( moduleName ) +{ + let downPath = _.path.normalize( _.introspector.location({ level : 1 }).filePath ); + // let basePath = _.path.dir( downPath ); + /* qqq zzz : optimize for release build for utility::starter */ + let result = _.module._resolve + ({ + // basePath, + downPath, + moduleName : arguments, + throwing : 0, + withAlternatives : 1, + }); + _.assert( _.arrayIs( result ) ); + if( result.length <= 1 ) + return result[ 0 ]; + return result; +} + +// + +function _resolveFirst( o ) +{ + + if( !_.mapIs( o ) ) + o = { moduleNames : arguments } + + _.assert( _.strDefined( o.downPath ) ); + // _.assert( _.strDefined( o.basePath ) ); + + let sourcePaths = this._moduleNamesToPaths( o.moduleNames ); + let resolved = this._fileResolve + ({ + sourcePaths, + // basePath : o.basePath, + downPath : o.downPath, + withAlternatives : o.withAlternatives, + all : 0, + }); + + if( o.throwing ) + if( resolved === undefined && !o.moduleNames.includes( _.optional ) ) + { + /* xxx : take care of section module files stack */ + throw _.err + ( + `Cant resolve module::${Array.prototype.slice.call( o.moduleNames ).join( ' module::' )}.` + + `\nLooked at:\n - ${sourcePaths.join( '\n - ' )}` + ); + } + + return resolved; +} + +_resolveFirst.defaults = +{ + moduleNames : null, + downPath : null, + // basePath : null, + throwing : 0, + withAlternatives : 1, +} + +// + +function resolveFirst() +{ + let downPath = _.path.normalize( _.introspector.location({ level : 1 }).filePath ); + // let basePath = _.path.dir( downPath ); + return _.module._resolveFirst + ({ + moduleNames : arguments, + // basePath, + downPath, + throwing : 0, + }); +} + +// + +function _fileResolve( o ) +{ + let result = []; + + if( !_.mapIs( arguments[ 0 ] ) ) + o = { sourcePaths : arguments[ 0 ] } + + let native = _.module.nativeFilesMap[ _.path.nativizeMinimal( o.downPath ) ]; + native = native || module; /* xxx : comment out and look among namesapces? */ + + _.assert( arguments.length === 1 ); + _.assert( _.longIs( o.sourcePaths ) ); + _.strDefined( o.downPath ); + // _.strDefined( o.basePath ); + _.assert( !!native ); + + for( let a = 0 ; a < o.sourcePaths.length ; a++ ) + { + let sourcePath = o.sourcePaths[ a ]; + let resolved; + + resolved = nativeResolve( sourcePath ); + if( resolved === undefined && o.withAlternatives ) + { + let sourcePath2 = sourcePath.toLowerCase(); + if( sourcePath !== sourcePath2 ) + resolved = nativeResolve( sourcePath2 ); + } + + result.push( resolved ); + if( !o.all ) + return result[ 0 ]; + } + + if( o.all ) + return result; + else + return undefined; + + function nativeResolve( sourcePath ) + { + /* xxx : not optimal */ + try + { + let r; + if( _.path.isAbsolute( sourcePath ) ) + r = ModuleFileNative._resolveFilename( _.path.nativizeMinimal( sourcePath ), native, false, undefined ); + else + r = ModuleFileNative._resolveFilename( sourcePath, native, false, undefined ); + if( r ) + r = _.path.normalize( r ); + return r; + } + catch( err ) + { + return; + } + } +} + +_fileResolve.defaults = +{ + sourcePaths : null, + downPath : null, + // basePath : null, + withAlternatives : 1, + all : 0, +} + +// + +function _moduleNamesToPaths( names ) +{ + let result = []; + + _.assert( arguments.length === 1 ); + _.assert( _.longIs( names ) ); + + for( let a = 0 ; a < names.length ; a++ ) + { + let src = names[ a ]; + if( src === _.optional ) + continue; + _.assert( _.strDefined( src ) ); + var descriptor = _.module.predeclaredWithNameMap.get( src ); + if( descriptor ) + { + _.assert( _.longIs( descriptor.lookPath ) ); + _.arrayAppendArray( result, descriptor.lookPath ); + } + else + { + result.push( src ); + } + } + + return result; +} + +// -- +// include +// -- + +function _fileIncludeSingle( downPath, filePath ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.strIs( filePath ), 'Expects string' ); + + if( !hasModuleFileDescriptor ) + throw _.err( 'Cant include, routine "require" does not exist.' ); + + // if( downPath.endsWith( 'secondary1' ) && filePath.endsWith( 'secondary3' ) ) + // debugger; + + let normalizedPath = _.path.nativizeMinimal( filePath ); + let moduleFile = _.module._fileWithResolvedPathAnyNamespace( downPath ); + if( moduleFile ) + return moduleFile.native.require( normalizedPath ); + return _.module.__fileNativeInclude( normalizedPath ); + +} + +// + +/* xxx : implement _.path._dir */ +/* xxx : qqq3 : optimize _.path.dir */ + +function include() +{ + _.assert( arguments.length === 1 ); + _.assert( _.strIs( arguments[ 0 ] ) ); + + let downPath = _.path.normalize( _.introspector.location({ level : 1 }).filePath ); + // let basePath = _.path.dir( downPath ); + let resolved = _.module._resolve + ({ + // basePath, + downPath, + moduleName : arguments, + throwing : 1, + withAlternatives : 1, + }); + + if( resolved.length === 1 ) + { + return _.module._fileIncludeSingle( downPath, resolved[ 0 ] ); + } + else + { + let result = []; + for( let i = 0 ; i < resolved.length ; i++ ) + result[ i ] = _.module._fileIncludeSingle( downPath, resolved[ i ] ); + return result; + } + +} + +// + +function includeFirst() +{ + let downPath = _.path.normalize( _.introspector.location({ level : 1 }).filePath ); + // let basePath = _.path.dir( downPath ); + let resolved = _.module._resolveFirst + ({ + // basePath, + downPath, + moduleNames : arguments, + throwing : 1, + withAlternatives : 1, + }); + if( resolved ) + { + return _.module._fileIncludeSingle( downPath, resolved ); + } +} + +// + +function isIncluded( src ) +{ + if( _.module.modulesMap.has( src ) ) + return true; + return false; +} + +// -- +// setup +// -- + +function _trackingEnable() +{ + + const ModuleFileNative = require( 'module' ); + const NjsResolveFilename = ModuleFileNative._resolveFilename; + const NjsLoad1 = ModuleFileNative._load; + const NjsLoad2 = ModuleFileNative.prototype.load; + + const resolving = Object.create( null ); + resolving.request = null; + resolving.parent = null; + resolving.resolvedPath = null; + + const loading = Object.create( null ); + loading.request = null; + loading.parent = null; + loading.childrenLength = null; + loading.counter = 0; + + _.assert( _.routineIs( NjsResolveFilename ) ); + _.assert( _.routineIs( NjsLoad1 ) ); + _.assert( _.routineIs( NjsLoad2 ) ); + + ModuleFileNative._resolveFilename = _resolveFilename; + + const dlopen = process.dlopen; + if( !_realGlobal_._modulingGlobal_ ) + { + ModuleFileNative._load = _loadEnvironment; + _realGlobal_._modulingGlobal_ = _global; + process.dlopen = dlopen2; + } + + ModuleFileNative.prototype.load = moduleFileLoad; + + // return process.dlopen(module, path.toNamespacedPath(filename)); + + /* */ + + function dlopen2() + { + let r; + try + { + r = dlopen.apply( this, arguments ); + } + catch( err ) + { + debugger; + // if( err.message === 'Module did not self-register.' ) + // { + // debugger; + // return undefined; + // } + throw err; + } + return r; + } + + /* */ + + function _resolveFilename( /* request, parent, isMain, options */ ) + { + let request = arguments[ 0 ]; + let parent = arguments[ 1 ]; + let isMain = arguments[ 2 ]; + let options = arguments[ 3 ]; + + if( resolving.parent === parent && resolving.request === request ) + return resolving.resolvedPath; + resolving.resolvedPath = NjsResolveFilename.apply( this, arguments ); + resolving.request = request; + resolving.parent = parent; + return resolving.resolvedPath; + } + + /* - */ + + function _loadModuling( request, parent, isMain ) + { + let result, err; + const counter = loading.counter; + + loading.request = request; + loading.parent = parent; + loading.childrenLength = parent ? parent.children.length : 0; + + try + { + result = NjsLoad1.apply( this, arguments ); + } + catch( _err ) + { + err = _err; + } + + if( !err ) + { + try + { + if( loading.counter === counter ) + second( request, parent ); + } + catch( err2 ) + { + console.error( err2 ); + } + } + + loading.request = null; + loading.parent = null; + + if( err ) + throw err; + return result; + } + + /* - */ + + function second( request, parent ) + { + + // if( request.endsWith( 'testing/entry/Main.s' ) ) + // debugger; + // if( request.endsWith( 'secondary3' ) ) + // debugger; + + if( !parent.universal ) + return; + // yyy + // if( parent.universal.moduleNativeFilesMap !== _.module.nativeFilesMap ) + // { + // // debugger; + // return; + // } + // if( parent.universal.moduleNativeFilesMap !== ModuleFileNative._cache ) + // { + // debugger; + // return; + // } + // if( !_.path.isDotted( request ) ) + // { + // _.debugger; + // // debugger; /* xxx : check */ + // return; + // } + + let native; + if( loading.request === request && loading.parent === parent ) + { + _.assert( loading.childrenLength === parent.children.length || loading.childrenLength + 1 === parent.children.length ); + if( loading.childrenLength === parent.children.length ) + return; + else + native = parent.children[ parent.children.length - 1 ]; + } + else + { + let resolvedPath = _resolveFilename( request, parent, false ); + native = ModuleFileNative._cache[ resolvedPath ]; + _.assert( !!_.module.fileNativeParent( native ) ); + _.assert( 0, 'not tested' ); /* xxx : qqq : cover? */ + } + + if( native.universal ) /* xxx2 : yyy : investigate test routine requireElectronProblem */ + if( _.module.fileNativeParent( native ) !== parent ) + { + // if( native.universal.sourcePath.endsWith( 'wFiles' ) ) + // debugger; + // _.debugger; + _.module._fileUniversalAssociateFile( native.universal, parent.universal ); + if( !_.module._predeclaredWithEntryPath( native.universal.sourcePath ) ) /* yyy */ + _.module._filesUniversalAssociateModule( native.universal, parent.universal.modules, false ); + } + } + + /* - */ + + function _loadEnvironment( request, parent, isMain ) + { + let result; + const originalModuleNativeFiles = ModuleFileNative._cache; + const originalGlobal = _realGlobal_._global_; + + // if( request.endsWith( 'wTesting' ) ) + // debugger; + // if( request.endsWith( 'testing/entry/Main.s' ) ) + // debugger; + + if( parent ) + if( parent._virtualEnvironment ) + { + if( parent._virtualEnvironment.moduleNativeFilesMap ) + ModuleFileNative._cache = parent._virtualEnvironment.moduleNativeFilesMap; + if( parent._virtualEnvironment.global ) + _realGlobal_._global_ = parent._virtualEnvironment.global; + } + else if( parent.universal ) + { + if( parent.universal.moduleNativeFilesMap ) + ModuleFileNative._cache = parent.universal.moduleNativeFilesMap; + if( parent.universal.global ) + _realGlobal_._global_ = parent.universal.global; + } + + try + { + result = _loadModuling.apply( this, arguments ); + } + catch( err ) + { + let error; + if( parent && parent.filename ) + { + error = _.err( err, `\nModule file "${parent.filename}" failed to include "${request}"` ); + // console.error( error ); + } + else + { + error = _.err( err, `\nFailed to include "${request}"` ); + } + throw error; + } + finally + { + ModuleFileNative._cache = originalModuleNativeFiles; + _realGlobal_._global_ = originalGlobal; + } + + return result; + } + + /* - */ + + function fileShare( moduleFile ) + { + const nativeSourcePath = moduleFile.fileName || moduleFile.id; + + if( !_.module.filePathIsBin( nativeSourcePath ) ) + return; + for( let name in _globals_ ) + { + let global = _globals_[ name ]; + if( global.wTools && global.wTools.module && global.wTools.module.nativeFilesMap ) + if( !global.wTools.module.nativeFilesMap[ nativeSourcePath ] ) + { + debugger; + global.wTools.module.nativeFilesMap[ nativeSourcePath ] = moduleFile; + } + } + } + + /* - */ + + function moduleFileLoad( nativeSourcePath ) + { + let result; + let native = this; + + loading.counter += 1; + + // yyy + if( _modulingGlobal_ === _global ) + fileShare( native ); + + /* + ignore includes of other global namespaces + */ + if( _.module.nativeFilesMap !== ModuleFileNative._cache ) + { + return NjsLoad2.apply( this, arguments ); + } + + let moduleFile = _.module._fileUniversalInit + ({ + sourcePath : nativeSourcePath, + nativeSourcePath, + requestedSourcePath : resolving.request, + native, + status : 1, + }); + + _.assert( native === ModuleFileNative._cache[ moduleFile.nativeSourcePath ] ); + _.assert( native === moduleFile.native ); + _.assert( resolving.resolvedPath === nativeSourcePath ); + + try + { + if( _.strHas( nativeSourcePath, 'imagemin' ) ) + { + debugger; + console.log( nativeSourcePath, arguments ); + } + result = NjsLoad2.apply( this, arguments ); + } + catch( err ) + { + err = _.err( err ); + try + { + moduleFile.error = moduleFile.error || err; + _.module._fileUniversalFinit( moduleFile ); + } + catch( err2 ) + { + console.error( _.err( err2 ) ); + } + throw err; + } + + if( moduleFile.status !== -1 ) + { + moduleFile.status = 2; + } + + return result; + } + + /* - */ + +} + +// + +function _Setup() +{ + + if( _.module._modulesToPredeclare ) + _.module.predeclareAll({ modules : _.module._modulesToPredeclare, basePath : __dirname }); + + if( typeof require === 'undefined' ) + return; + + if( !ModuleFileNative ) + ModuleFileNative = require( 'module' ); + + if( !_.module.rootFileNative ) + { + let rootFileNative = _.module.rootFileNative = module; + while( _.module.fileNativeParent( rootFileNative ) ) + rootFileNative = _.module.fileNativeParent( rootFileNative ); + _.module.rootFileNative = rootFileNative; + } + + if( !_.module.nativeFilesMap ) + _.module.nativeFilesMap = ModuleFileNative._cache; + + if( _.module._setupRequireDone ) + return; + _.module._setupRequireDone = 1; + + // /* qqq xxx : remove that if-return branch */ + // if( _global_.Config.interpreter === 'browser' ) + // return; + + _.module._trackingEnable(); + _.module._filesUniversalInit({ files : [ _.module.rootFileNative ] }); + + if( _.module.rootFileNative.universal ) + _.module.rootFile = _.module.rootFileNative.universal; + +} + +// -- +// Module +// -- + +const ModuleSymbol = Symbol.for( 'Module' ); + +function Module() +{ + _.assert( 0, 'not implemented' ); + if( arguments.length !== 0 ) + throw new Error( 'Expects no arguments' ); + _.assert( this instanceof Module ); + return this; +} + +_.class.declareBasic +({ + constructor : Module, + exportString : moduleExportString, +}); + +Object.defineProperty( Module.prototype, ModuleSymbol, +{ + enumerable : false, + configurable : false, + writable : false, + value : true, +}); + +// -- +// Module File +// -- + +const ModuleFileSymbol = Symbol.for( 'ModuleFile' ); + +function ModuleFile() +{ + _.assert( 0, 'not implemented' ); + if( arguments.length !== 0 ) + throw new Error( 'Expects no arguments' ); + _.assert( this instanceof ModuleFile ); + return this; +} + +_.class.declareBasic +({ + constructor : ModuleFile, + exportString : moduleFileExportString, +}); + +Object.defineProperty( ModuleFile.prototype, ModuleFileSymbol, +{ + enumerable : false, + configurable : false, + writable : false, + value : true, +}); + +/* xxx : qqq : for junior : cover */ +Object.defineProperty( ModuleFile.prototype, 'returned', +{ + enumerable : true, + configurable : true, + get : moduleFileReturnedGet, + // set : _returnedSet, /* qqq : uncomment later and write test */ +}); + +// -- +// module extension +// -- + +var ModuleExtension = +{ + + // module + + is, + with : _with, + withName, + withPath, + + predeclare, + predeclareAll, + _predeclaredWithEntryPath, + + // file + + fileIs, + fileUniversalIs : __.module.fileUniversalIs, + fileUniversalFrom, + _fileUniversalFinit, + _fileUniversalInit, + _filesUniversalInit, + _fileUniversalAssociateFile, + _fileUniversalDisassociateFile, + _fileUniversalAssociateModule, + _fileUniversalDisassociateModules, + _filesUniversalAssociateModule, + + _filesWithResolvedPath, + _fileWithResolvedPath, + _fileWithResolvedPathAnyNamespace, + fileWithResolvedPath, + fileWith, + fileInvalidate, + + fileNativeIs : __.module.fileNativeIs, + fileNativeFrom : __.module.fileNativeFrom, + fileNativeParent : __.module.fileNativeParent, + _fileNativeWithResolvedNativePath, + fileNativeWith, + + // export string + + _exportString, + exportString, + _fileExportString, + fileExportString, + recursiveExportString, + + // file path + + filePathAmend, + filePathRemove, + filePathGet, + filePathIsBin : __.module.filePathIsBin, + + // resolve + + _resolve, + resolve, + _resolveFirst, + resolveFirst, + _fileResolve, + + _moduleNamesToPaths, + + // include + + _fileIncludeSingle, + + include, + includeFirst, + + isIncluded, + + // setup + + _trackingEnable, + /* qqq : implement and cover routine _trackingDisable */ + _Setup, + + // fields + + Module, + File : ModuleFile, + __fileNativeInclude, + _prependPath : null, + _appendPath : null, + rootFile : null, + rootFileNative : null, + predeclaredWithNameMap : new HashMap, + predeclaredWithEntryPathMap : new HashMap, + modulesMap : new HashMap, + nativeFilesMap : null, + filesMap : new HashMap, + _setupRequireDone : null, + +} + +/* xxx : move to l3/l5 */ +/* xxx : test of include file which deos not exist and reinclude file wich was trying include file which does not exist */ + +Object.assign( _.module, ModuleExtension ); + +// -- +// tools extension +// -- + +var ToolsExtension = +{ + include, + includeFirst, +} + +Object.assign( _, ToolsExtension ); + +_.module._Setup(); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5/zModule.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, zModule_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file zModule_s */ })(); + +/* */ /* begin of file Compose_s */ ( function Compose_s() { function Compose_s_naked() { ( function _Compose_s_() +{ + +'use strict'; /* xxx : deprecate? */ + +const _global = _global_; +const _ = _global_.wTools; +// _.compose = _.compose || Object.create( null ); +_.routine.chainer = _.routine.chainer || Object.create( null ); +_.routine.tail = _.routine.tail || Object.create( null ); + +// -- +// chainer +// -- + +function originalChainer( /* args, result, fo, k */ ) +{ + let args = arguments[ 0 ]; + let result = arguments[ 1 ]; + let fo = arguments[ 2 ]; + let k = arguments[ 3 ]; + _.assert( result !== false ); + return args; +} + +// + +function originalWithDontChainer( /* args, result, fo, k */ ) +{ + let args = arguments[ 0 ]; + let result = arguments[ 1 ]; + let fo = arguments[ 2 ]; + let k = arguments[ 3 ]; + + _.assert( result !== false ); + if( result === _.dont ) + return _.dont; + return args; +} + +// + +function composeAllChainer( /* args, result, fo, k */ ) +{ + let args = arguments[ 0 ]; + let result = arguments[ 1 ]; + let fo = arguments[ 2 ]; + let k = arguments[ 3 ]; + + _.assert( result !== false ); + if( result === _.dont ) + return _.dont; + return args; +} + +// + +function chainingChainer( /* args, result, fo, k */ ) +{ + let args = arguments[ 0 ]; + let result = arguments[ 1 ]; + let fo = arguments[ 2 ]; + let k = arguments[ 3 ]; + + _.assert( result !== false ); + if( result === undefined ) + return args; + if( result === _.dont ) + return _.dont; + return _.unroll.from( result ); +} + +// -- +// tail +// -- + +function returningLastTail( args, fo ) +{ + // let self = arguments[ 0 ]; + // let args = arguments[ 1 ]; + // let act = arguments[ 2 ]; + // let fo = arguments[ 3 ]; + let self = this; + let act = fo.act; + + let result = act.apply( self, args ); + return result[ result.length-1 ]; +} + +// + +function composeAllTail( args, fo ) +{ + // let self = arguments[ 0 ]; + // let args = arguments[ 1 ]; + // let act = arguments[ 2 ]; + // let fo = arguments[ 3 ]; + let self = this; + let act = fo.act; + + let result = act.apply( self, args ); + _.assert( !!result ); + if( !result.length ) + return result; + if( result[ result.length-1 ] === _.dont ) + return false; + if( !_.all( result ) ) + return false; + return result; +} + +// + +function chainingTail( args, fo ) +{ + // let self = arguments[ 0 ]; + // let args = arguments[ 1 ]; + // let act = arguments[ 2 ]; + // let fo = arguments[ 3 ]; + let self = this; + let act = fo.act; + + let result = act.apply( self, args ); + if( result[ result.length-1 ] === _.dont ) + result.pop(); + return result; +} + +// -- +// declare +// -- + +let chainer = +{ + original : originalChainer, + originalWithDont : originalWithDontChainer, + composeAll : composeAllChainer, + chaining : chainingChainer, +} + +Object.assign( _.routine.chainer, chainer ); + +let tail = +{ + returningLast : returningLastTail, + composeAll : composeAllTail, + chaining : chainingTail, +} + +Object.assign( _.routine.tail, tail ); + +// -- +// extend +// -- + +// let Extension = +// { +// +// chainer, +// supervisor +// +// } +// +// Object.assign( Self, Extension ); +// /* xxx : qqq : remove */ + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l6/Compose.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l6' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Compose_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Compose_s */ })(); + +/* */ /* begin of file PropertyTransformers_s */ ( function PropertyTransformers_s() { function PropertyTransformers_s_naked() { ( function _PropertyTransformer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// +// -- + +function bypass() +{ + let routine = bypass; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function bypass( dstContainer, srcContainer, key ) + { + /*dstContainer[ key ] = srcContainer[ key ];*/ + return true; + } +} + +bypass.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function assigning() +{ + let routine = assigning; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + function assigning( dstContainer, srcContainer, key ) + { + _.entity.assign2FieldFromContainer( dstContainer, srcContainer, key ); + } +} + +assigning.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function primitive() +{ + let routine = primitive; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function primitive( dstContainer, srcContainer, key ) + { + if( !_.primitive.is( srcContainer[ key ] ) ) + return false; + + return true; + } +} + +primitive.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function hiding() +{ + let routine = hiding; + + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function hiding( dstContainer, srcContainer, key ) + { + let properties = + { + value : srcContainer[ key ], + enumerable : false, + configurable : true, + }; + Object.defineProperty( dstContainer, key, properties ); + } + +} + +hiding.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function appendingAnything() +{ + let routine = appendingAnything; + + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function appendingAnything( dstContainer, srcContainer, key ) + { + if( dstContainer[ key ] === undefined ) + dstContainer[ key ] = srcContainer[ key ]; + else if( _.arrayIs( dstContainer[ key ] ) ) + dstContainer[ key ] = _.arrayAppendArrays( dstContainer[ key ], [ srcContainer[ key ] ] ); + else + dstContainer[ key ] = _.arrayAppendArrays( [], [ dstContainer[ key ], srcContainer[ key ] ] ); + } + +} + +appendingAnything.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function prependingAnything() +{ + let routine = prependingAnything; + + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function prependingAnything( dstContainer, srcContainer, key ) + { + if( dstContainer[ key ] === undefined ) + dstContainer[ key ] = srcContainer[ key ]; + else if( _.arrayIs( dstContainer[ key ] ) ) + dstContainer[ key ] = _.arrayPrependArrays( dstContainer[ key ], [ srcContainer[ key ] ] ); + else + dstContainer[ key ] = _.arrayPrependArrays( [], [ dstContainer[ key ], srcContainer[ key ] ] ); + } + +} + +prependingAnything.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function appendingOnlyArrays() +{ + let routine = appendingOnlyArrays; + + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function appendingOnlyArrays( dstContainer, srcContainer, key ) + { + if( _.arrayIs( dstContainer[ key ] ) && _.arrayIs( srcContainer[ key ] ) ) + _.arrayAppendArray( dstContainer[ key ], srcContainer[ key ] ); + else + dstContainer[ key ] = srcContainer[ key ]; + } + +} + +appendingOnlyArrays.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function appendingOnce() +{ + let routine = appendingOnce; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function appendingOnce( dstContainer, srcContainer, key ) + { + if( _.arrayIs( dstContainer[ key ] ) && _.arrayIs( srcContainer[ key ] ) ) + _.arrayAppendArrayOnce( dstContainer[ key ], srcContainer[ key ] ); + else + dstContainer[ key ] = srcContainer[ key ]; + } + +} + +appendingOnce.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function removing() +{ + let routine = removing; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function removing( dstContainer, srcContainer, key ) + { + let dstElement = dstContainer[ key ]; + let srcElement = srcContainer[ key ]; + if( _.arrayIs( dstElement ) && _.arrayIs( srcElement ) ) + { + if( dstElement === srcElement ) + dstContainer[ key ] = []; + else + _.arrayRemoveArrayOnce( dstElement, srcElement ); + } + else if( dstElement === srcElement ) + { + delete dstContainer[ key ]; + } + } + +} + +removing.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function notPrimitiveAssigning() +{ + let routine = notPrimitiveAssigning; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function notPrimitiveAssigning( dstContainer, srcContainer, key ) + { + if( _.primitive.is( srcContainer[ key ] ) ) + return; + + _.entity.assign2FieldFromContainer( dstContainer, srcContainer, key ); + } + +} + +notPrimitiveAssigning.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function assigningRecursive() +{ + let routine = assigningRecursive; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function assigningRecursive( dstContainer, srcContainer, key ) + { + _.entity.assign2FieldFromContainer( dstContainer, srcContainer, key, _.entity.assign2FieldFromContainer ); + } + +} + +assigningRecursive.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function drop( dropContainer ) +{ + + debugger; + + _.assert( _.object.isBasic( dropContainer ) ); + + let routine = drop; + + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function drop( dstContainer, srcContainer, key ) + { + if( dropContainer[ key ] !== undefined ) + return false + + /*dstContainer[ key ] = srcContainer[ key ];*/ + return true; + } + +} + +drop.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function notIdentical() +{ + let routine = notIdentical; + routine.identity = { propertyCondition : true, propertyTransformer : true }; ; + return routine; + function notIdentical( dstContainer, srcContainer, key ) + { + if( dstContainer[ key ] === srcContainer[ key ] ) + return false; + return true; + } +} + +notIdentical.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// -- +// src +// -- + +function srcDefined() +{ + let routine = srcDefined; + routine.identity = { propertyCondition : true, propertyTransformer : true }; ; + return routine; + + function srcDefined( dstContainer, srcContainer, key ) + { + if( srcContainer[ key ] === undefined ) + return false; + return true; + } +} + +srcDefined.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstNotHasOrSrcNotNull() +{ + let routine = dstNotHasOrSrcNotNull; + routine.identity = { propertyCondition : true, propertyTransformer : true }; ; + return routine; + function dstNotHasOrSrcNotNull( dstContainer, srcContainer, key ) + { + if( key in dstContainer && dstContainer[ key ] !== undefined ) + return false; + if( srcContainer[ key ] === null ) + return false; + return true; + } +} + +dstNotHasOrSrcNotNull.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// -- +// dst +// -- + +function dstNotConstant() +{ + let routine = dstNotConstant; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstNotConstant( dstContainer, srcContainer, key ) + { + let d = Object.getOwnPropertyDescriptor( dstContainer, key ); + if( !d ) + return true; + if( !d.writable ) + return false; + return true; + } + +} + +dstNotConstant.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstAndSrcOwn() +{ + let routine = dstAndSrcOwn; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstAndSrcOwn( dstContainer, srcContainer, key ) + { + if( !Object.hasOwnProperty.call( srcContainer, key ) ) + return false; + if( !Object.hasOwnProperty.call( dstContainer, key ) ) + return false; + + return true; + } + +} + +dstAndSrcOwn.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstUndefinedSrcNotUndefined() +{ + let routine = dstUndefinedSrcNotUndefined; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstUndefinedSrcNotUndefined( dstContainer, srcContainer, key ) + { + if( dstContainer[ key ] !== undefined ) + return false; + if( srcContainer[ key ] === undefined ) + return false; + return true; + } + +} + +dstUndefinedSrcNotUndefined.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// -- +// dstNotHas +// -- + +function dstNotHas() +{ + let routine = dstNotHas; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstNotHas( dstContainer, srcContainer, key ) + { + + if( key in dstContainer ) + return false; + + return true; + } + +} + +dstNotHas.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstNotHasOrHasNull() +{ + let routine = dstNotHasOrHasNull; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstNotHasOrHasNull( dstContainer, srcContainer, key ) + { + if( key in dstContainer && dstContainer[ key ] !== null ) + return false; + return true; + } + +} + +dstNotHasOrHasNull.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstNotHasOrHasNil() +{ + let routine = dstNotHasOrHasNil; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstNotHasOrHasNil( dstContainer, srcContainer, key ) + { + + if( key in dstContainer && dstContainer[ key ] !== _.nothing ) + return false; + + return true; + } + +} + +dstNotHasOrHasNil.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstNotHasAssigning() +{ + let routine = dstNotHasAssigning; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function dstNotHasAssigning( dstContainer, srcContainer, key ) + { + if( dstContainer[ key ] !== undefined ) + return; + + _.entity.assign2FieldFromContainer( dstContainer, srcContainer, key ); + } + +} + +dstNotHasAssigning.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function dstNotHasAppending() +{ + let routine = dstNotHasAppending; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function dstNotHasAppending( dstContainer, srcContainer, key ) + { + if( key in dstContainer ) + { + debugger; + if( _.arrayIs( dstContainer[ key ] ) && _.arrayIs( srcContainer[ key ] ) ) + _.arrayAppendArray( dstContainer, srcContainer, key ); + return; + } + dstContainer[ key ] = srcContainer[ key ]; + } + +} + +dstNotHasAppending.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function dstNotHasSrcPrimitive() +{ + let routine = dstNotHasSrcPrimitive; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstNotHasSrcPrimitive( dstContainer, srcContainer, key ) + { + debugger; + if( key in dstContainer ) + return false; + + if( !_.primitive.is( srcContainer[ key ] ) ) + return false; + + return true; + } + +} + +dstNotHasSrcPrimitive.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstNotHasSrcOwn() +{ + let routine = dstNotHasSrcOwn; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstNotHasSrcOwn( dstContainer, srcContainer, key ) + { + if( !Object.hasOwnProperty.call( srcContainer, key ) ) + return false; + if( key in dstContainer ) + return false; + + /*dstContainer[ key ] = srcContainer[ key ];*/ + return true; + } + +} + +dstNotHasSrcOwn.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstNotHasSrcOwnAssigning() +{ + let routine = dstNotHasSrcOwnAssigning; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function dstNotHasSrcOwnAssigning( dstContainer, srcContainer, key ) + { + if( !Object.hasOwnProperty.call( srcContainer, key ) ) + return; + if( key in dstContainer ) + return; + + _.entity.assign2FieldFromContainer( dstContainer, srcContainer, key ); + } + +} + +dstNotHasSrcOwnAssigning.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function dstNotHasSrcOwnRoutines() +{ + let routine = dstNotHasSrcOwnRoutines; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstNotHasSrcOwnRoutines( dstContainer, srcContainer, key ) + { + if( !Object.hasOwnProperty.call( srcContainer, key ) ) + return false; + if( !_.routine.is( srcContainer[ key ] ) ) + return false; + if( key in dstContainer ) + return false; + + /*dstContainer[ key ] = srcContainer[ key ];*/ + + return true; + } + +} + +dstNotHasSrcOwnRoutines.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstNotHasAssigningRecursive() +{ + let routine = dstNotHasAssigningRecursive; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function dstNotHasAssigningRecursive( dstContainer, srcContainer, key ) + { + if( key in dstContainer ) + return; + + _.entity.assign2FieldFromContainer( dstContainer, srcContainer, key, _.entity.assign2FieldFromContainer ); + } + +} + +dstNotHasAssigningRecursive.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// -- +// dstOwn +// -- + +function dstOwn() +{ + let routine = dstOwn; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstOwn( dstContainer, srcContainer, key ) + { + if( !Object.hasOwnProperty.call( dstContainer, key ) ) + return false; + return true; + } + +} + +dstOwn.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstNotOwn() +{ + let routine = dstNotOwn; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstNotOwn( dstContainer, srcContainer, key ) + { + if( Object.hasOwnProperty.call( dstContainer, key ) ) + return false; + return true; + } + +} + +dstNotOwn.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstNotOwnNotSame() +{ + let routine = dstNotOwnNotSame; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstNotOwnNotSame( dstContainer, srcContainer, key ) + { + if( key === 'groupTextualReport' ) + debugger; + if( Object.hasOwnProperty.call( dstContainer, key ) ) + return false; + if( dstContainer[ key ] === srcContainer[ key ] ) + return false; + return true; + } + +} + +dstNotOwnNotSame.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstNotOwnSrcOwn() +{ + let routine = dstNotOwnSrcOwn; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstNotOwnSrcOwn( dstContainer, srcContainer, key ) + { + if( !Object.hasOwnProperty.call( srcContainer, key ) ) + return false; + + if( Object.hasOwnProperty.call( dstContainer, key ) ) + return false; + + return true; + } + +} + +dstNotOwnSrcOwn.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstNotOwnSrcOwnAssigning() +{ + let routine = dstNotOwnSrcOwnAssigning; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function dstNotOwnSrcOwnAssigning( dstContainer, srcContainer, key ) + { + if( !Object.hasOwnProperty.call( srcContainer, key ) ) + return; + + if( Object.hasOwnProperty.call( dstContainer, key ) ) + return; + + _.entity.assign2FieldFromContainer( dstContainer, srcContainer, key ); + } + +} + +dstNotOwnSrcOwnAssigning.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function dstNotOwnOrUndefinedAssigning() +{ + let routine = dstNotOwnOrUndefinedAssigning; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function dstNotOwnOrUndefinedAssigning( dstContainer, srcContainer, key ) + { + + if( Object.hasOwnProperty.call( dstContainer, key ) ) + { + + if( dstContainer[ key ] !== undefined ) + return; + + } + + _.entity.assign2FieldFromContainer( dstContainer, srcContainer, key ); + } + +} + +dstNotOwnOrUndefinedAssigning.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function dstNotOwnAssigning() +{ + let routine = dstNotOwnAssigning; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function dstNotOwnAssigning( dstContainer, srcContainer, key ) + { + + if( Object.hasOwnProperty.call( dstContainer, key ) ) + return; + + let srcElement = srcContainer[ key ]; + if( _.mapIs( srcElement ) || _.arrayIs( srcElement ) ) + _.entity.assign2FieldFromContainer( dstContainer, srcContainer, key ); + else + dstContainer[ key ] = srcContainer[ key ]; + + } + +} + +dstNotOwnAssigning.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function dstNotOwnAppending() +{ + let routine = dstNotOwnAppending; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function dstNotOwnAppending( dstContainer, srcContainer, key ) + { + debugger; + if( dstContainer[ key ] !== undefined ) + { + debugger; + if( _.arrayIs( dstContainer[ key ] ) && _.arrayIs( srcContainer[ key ] ) ) + _.arrayAppendArray( dstContainer, srcContainer, key ); + } + if( Object.hasOwnProperty.call( dstContainer, key ) ) + return; + dstContainer[ key ] = srcContainer[ key ]; + } + +} + +dstNotOwnAppending.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// -- +// dstHas +// -- + +function dstHasMaybeUndefined() +{ + let routine = dstHasMaybeUndefined; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstHasMaybeUndefined( dstContainer, srcContainer, key ) + { + if( key in dstContainer ) + return true; + return false; + } + +} + +dstHasMaybeUndefined.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstHasButUndefined() +{ + let routine = dstHasButUndefined; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstHasButUndefined( dstContainer, srcContainer, key ) + { + if( dstContainer[ key ] === undefined ) + return false; + return true; + } + +} + +dstHasButUndefined.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstHasSrcOwn() +{ + let routine = dstHasSrcOwn; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstHasSrcOwn( dstContainer, srcContainer, key ) + { + if( !( key in dstContainer ) ) + return false; + if( !Object.hasOwnProperty.call( srcContainer, key ) ) + return false; + return true; + } + +} + +dstHasSrcOwn.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function dstHasSrcNotOwn() +{ + let routine = dstHasSrcNotOwn; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function dstHasSrcNotOwn( dstContainer, srcContainer, key ) + { + if( !( key in dstContainer ) ) + return false; + if( Object.hasOwnProperty.call( srcContainer, key ) ) + return false; + return true; + } + +} + +dstHasSrcNotOwn.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// -- +// srcOwn +// -- + +function srcOwn() +{ + let routine = srcOwn; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function srcOwn( dstContainer, srcContainer, key ) + { + if( !Object.hasOwnProperty.call( srcContainer, key ) ) + return false; + + /*dstContainer[ key ] = srcContainer[ key ];*/ + return true; + } + +} + +srcOwn.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function srcOwnRoutines() +{ + let routine = srcOwnRoutines; + routine.identity = { propertyCondition : true, propertyTransformer : true }; ; + return routine; + + function srcOwnRoutines( dstContainer, srcContainer, key ) + { + if( !Object.hasOwnProperty.call( srcContainer, key ) ) + return false; + if( !_.routine.is( srcContainer[ key ] ) ) + return false; + + /*dstContainer[ key ] = srcContainer[ key ];*/ + return true; + } + +} + +srcOwnRoutines.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function srcOwnAssigning() +{ + let routine = assigning; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function assigning( dstContainer, srcContainer, key ) + { + if( !Object.hasOwnProperty.call( srcContainer, key ) ) + return; + + _.entity.assign2FieldFromContainer( dstContainer, srcContainer, key ); + } + +} + +srcOwnAssigning.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function srcOwnPrimitive() +{ + let routine = srcOwnPrimitive; + routine.identity = { propertyCondition : true, propertyTransformer : true }; + return routine; + + function srcOwnPrimitive( dstContainer, srcContainer, key ) + { + if( !Object.hasOwnProperty.call( srcContainer, key ) ) + return false; + if( !_.primitive.is( srcContainer[ key ] ) ) + return false; + + /*dstContainer[ key ] = srcContainer[ key ];*/ + return true; + } + +} + +srcOwnPrimitive.identity = { propertyCondition : true, propertyTransformer : true, functor : true }; + +// + +function srcOwnNotPrimitiveAssigning() +{ + let routine = srcOwnNotPrimitiveAssigning; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function srcOwnNotPrimitiveAssigning( dstContainer, srcContainer, key ) + { + if( !Object.hasOwnProperty.call( srcContainer, key ) ) + return; + if( _.primitive.is( srcContainer[ key ] ) ) + return; + + _.entity.assign2FieldFromContainer( dstContainer, srcContainer, key ); + } + +} + +srcOwnNotPrimitiveAssigning.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function srcOwnNotPrimitiveAssigningRecursive() +{ + let routine = srcOwnNotPrimitiveAssigningRecursive; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function srcOwnNotPrimitiveAssigningRecursive( dstContainer, srcContainer, key ) + { + if( !Object.hasOwnProperty.call( srcContainer, key ) ) + return; + if( _.primitive.is( srcContainer[ key ] ) ) + return; + + _.entity.assign2FieldFromContainer( dstContainer, srcContainer, key, _.entity.assign2FieldFromContainer ); + } + +} + +srcOwnNotPrimitiveAssigningRecursive.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function srcOwnAssigningRecursive() +{ + let routine = srcOwnAssigningRecursive; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function srcOwnAssigningRecursive( dstContainer, srcContainer, key ) + { + if( !Object.hasOwnProperty.call( srcContainer, key ) ) + return; + + _.entity.assign2FieldFromContainer( dstContainer, srcContainer, key, _.entity.assign2FieldFromContainer ); + } + +} + +srcOwnAssigningRecursive.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// -- +// make +// -- + +let _Transformers = +{ + + // + + bypass, + assigning, + primitive, + hiding, + appendingAnything, + prependingAnything, + appendingOnlyArrays, + appendingOnce, + removing, + notPrimitiveAssigning, + assigningRecursive, + drop, + notIdentical, + + // src + + srcDefined, + dstNotHasOrSrcNotNull, + + // dst + + dstNotConstant, + dstAndSrcOwn, + dstUndefinedSrcNotUndefined, + + // dstNotHas + + dstNotHas, + dstNotHasOrHasNull, + dstNotHasOrHasNil, + + dstNotHasAssigning, + dstNotHasAppending, + dstNotHasSrcPrimitive, + + dstNotHasSrcOwn, + dstNotHasSrcOwnAssigning, + dstNotHasSrcOwnRoutines, + dstNotHasAssigningRecursive, + + // dstOwn + + dstOwn, + dstNotOwn, + dstNotOwnNotSame, + dstNotOwnSrcOwn, + dstNotOwnSrcOwnAssigning, + dstNotOwnOrUndefinedAssigning, + dstNotOwnAssigning, + dstNotOwnAppending, + + // dstHas + + dstHasMaybeUndefined, + dstHasButUndefined, + dstHasSrcOwn, + dstHasSrcNotOwn, + + // srcOwn + + srcOwn, + srcOwnRoutines, + srcOwnAssigning, + srcOwnPrimitive, + srcOwnNotPrimitiveAssigning, + srcOwnNotPrimitiveAssigningRecursive, + srcOwnAssigningRecursive, + +} + +// -- +// extend +// -- + +_.props.transformersRegister( _Transformers ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l6/PropertyTransformers.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l6' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, PropertyTransformers_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file PropertyTransformers_s */ })(); + +/* */ /* begin of file ArgumentsArray_s */ ( function ArgumentsArray_s() { function ArgumentsArray_s_naked() { ( function _l7_ArgumentsArray_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.argumentsArray = _.argumentsArray || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +var Extension = +{ + +} + +// + +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/ArgumentsArray.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ArgumentsArray_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ArgumentsArray_s */ })(); + +/* */ /* begin of file Array_s */ ( function Array_s() { function Array_s_naked() { ( function _l7_Array_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// declaration +// -- + +let ToolsExtension = +{ + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Array.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Array_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Array_s */ })(); + +/* */ /* begin of file ArraySet_s */ ( function ArraySet_s() { function ArraySet_s_naked() { ( function _l7_ArraySet_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.arraySet = _.arraySet || Object.create( null ); + +// -- +// array set +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +// + +let Extension = +{ + +} + +Object.assign( Self, Extension ); +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/ArraySet.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ArraySet_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ArraySet_s */ })(); + +/* */ /* begin of file Auxiliary_s */ ( function Auxiliary_s() { function Auxiliary_s_naked() { ( function _l7_Auxiliary_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// dichotomy +// -- + +// -- +// extension +// -- + +var AuxiliaryExtension = +{ + +} + +Object.assign( _.aux, AuxiliaryExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Auxiliary.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Auxiliary_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Auxiliary_s */ })(); + +/* */ /* begin of file BigInt_s */ ( function BigInt_s() { function BigInt_s_naked() { ( function _l7_BigInt_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.bigInt = _.bigInt || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +// + +let Extension = +{ + +} + +Object.assign( Self, Extension ); +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/BigInt.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, BigInt_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file BigInt_s */ })(); + +/* */ /* begin of file Bool_s */ ( function Bool_s() { function Bool_s_naked() { ( function _l7_Bool_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.bool = _.bool || Object.create( null ); + +// -- +// bool +// -- + +/** + * @summary Converts argument( src ) to boolean. + * @function boolFrom + * @param {*} src - entity to convert + * @namespace Tools + * @throws Exception if cannot convert. + */ + +function from( src ) +{ + let result = _.bool.fromMaybe( src ); + _.assert( _.boolIs( result ), `Cant convert ${_.entity.strType( src )} to boolean` ); + return result; +} + +// + +/** + * @summary Converts argument( src ) to boolean or return src. + * @function boolFrom + * @param {*} src - entity to convert + * @namespace Tools + */ + +function fromMaybe( src ) +{ + if( _.bool.is( src ) ) + { + return src; + } + else if( _.number.is( src ) ) + { + return !!src; + } + else if( _.strIs( src ) ) + { + src = src.toLowerCase(); + if( src === '0' ) + return false; + if( src === 'false' ) + return false; + if( src === '1' ) + return true; + if( src === 'true' ) + return true; + return src; + } + else + { + return src; + } +} + +// + +/** + * @summary Converts argument( src ) to boolean. + * @function boolFrom + * @param {*} src - entity to convert + * @namespace Tools + */ + +function coerceFrom( src ) +{ + if( _.strIs( src ) ) + { + src = src.toLowerCase(); + if( src === '0' ) + return false; + if( src === 'false' ) + return false; + if( src === 'null' ) + return false; + if( src === 'undefined' ) + return false; + if( src === '' ) + return false; + return true; + } + return Boolean( src ); +} + +// -- +// implementation +// -- + +let ToolsExtension = +{ + + boolFrom : from, + boolFromMaybe : fromMaybe, + boolCoerceFrom : coerceFrom, + +} + +Object.assign( _, ToolsExtension ); + +// + +let BoolExtension = +{ + + from, + fromMaybe, + coerceFrom, + +} + +Object.assign( _.bool, BoolExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Bool.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Bool_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Bool_s */ })(); + +/* */ /* begin of file Buffer_s */ ( function Buffer_s() { function Buffer_s_naked() { ( function _l7_Buffer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// buffer +// -- + +function _argumentsOnlyBuffer( /* dst, src, range, ins */ ) +{ + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + + if( dst === null ) + dst = true; + else if( dst === src ) + dst = false; + else if( arguments.length === 4 ) + _.assert( _.longIs( dst ) || _.bufferAnyIs( dst ), '{-dst-} should be Long or buffer' ); + else + { + if( arguments.length > 1 && !_.intervalIs( src ) && !_.number.is( src ) ) + _.assert( _.longIs( dst ) || _.bufferAnyIs( dst ) ); + else + { + ins = range; + range = src; + src = dst; + dst = false; + } + } + + _.assert( _.longIs( src ) || _.bufferAnyIs( src ) ); + + return [ dst, src, range, ins ]; +} + +function _returnDst( dst, src ) +{ + let dstLength; + if( !_.bool.is( dst ) ) + dstLength = dst.length === undefined ? dst.byteLength : dst.length; + + if( dstLength !== undefined ) + { + let srcLength = src.length === undefined ? src.byteLength : src.length; + + if( _.arrayLikeResizable( dst ) ) + dst.length = srcLength; + else if( _.argumentsArray.is( dst ) ) + dst = new Array( srcLength ); + else if( dstLength !== srcLength ) + dst = _.bufferViewIs( dst ) ? new BufferView( new BufferRaw( srcLength ) ) : new dst.constructor( srcLength ); + + let dstTyped = dst; + if( _.bufferRawIs( dstTyped ) ) + dstTyped = new U8x( dstTyped ); + else if( _.bufferViewIs( dstTyped ) ) + dstTyped = new U8x( dstTyped.buffer ); + + if( _.bufferRawIs( src ) ) + src = new U8x( src ); + else if( _.bufferViewIs( src ) ) + src = new U8x( src.buffer ); + + for( let i = 0; i < srcLength; i++ ) + dstTyped[ i ] = src[ i ]; + + return dst; + } + return dst === true ? _.bufferMake( src ) : src; +} + +// + +/** + * The bufferRelen() routine returns a new or the same typed array {-srcMap-} with a new or the same length (len). + * + * It creates the variable (result) checks, if (len) is more than (src.length), + * if true, it creates and assigns to (result) a new typed array with the new length (len) by call the function(longMakeUndefined(src, len)) + * and copies each element from the {-srcMap-} into the (result) array while ensuring only valid data types, if data types are invalid they are replaced with zero. + * Otherwise, if (len) is less than (src.length) it returns a new typed array from 0 to the (len) indexes, but not including (len). + * Otherwise, it returns an initial typed array. + * + * @see {@link wTools.longMakeUndefined} - See for more information. + * + * @param { typedArray } src - The source typed array. + * @param { Number } len - The length of a typed array. + * + * @example + * let ints = new I8x( [ 3, 7, 13 ] ); + * _.bufferRelen( ints, 4 ); + * // returns [ 3, 7, 13, 0 ] + * + * @example + * let ints2 = new I16x( [ 3, 7, 13, 33, 77 ] ); + * _.bufferRelen( ints2, 3 ); + * // returns [ 3, 7, 13 ] + * + * @example + * let ints3 = new I32x( [ 3, 7, 13, 33, 77 ] ); + * _.bufferRelen( ints3, 6 ); + * // returns [ 3, 0, 13, 0, 77, 0 ] + * + * @returns { typedArray } - Returns a new or the same typed array {-srcMap-} with a new or the same length (len). + * @function bufferRelen + * @namespace Tools + */ + +function bufferRelen( src, len ) +{ + let result = src; + + _.assert( _.bufferTypedIs( src ) ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.number.is( len ) ); + + if( len > src.length ) + { + result = _.long.makeUndefined( src, len ); + result.set( src ); + } + else if( len < src.length ) + { + result = src.subarray( 0, len ); + } + + return result; +} + +// + +/** + * Routine bufferBut_() copies elements from source buffer {-src-} to destination buffer {-dst-}. + * Routine copies all elements excluding elements in range {-cinterval-}, its elements replaces by elements + * from insertion buffer {-ins-}. + * + * If first and second provided arguments is containers, then fisrs argument is destination + * container {-dst-} and second argument is source container {-src-}. All data in {-dst-} cleares. If {-dst-} container + * is not resizable and resulted length of destination container is not equal to original {-dst-} length, then routine + * makes new container of {-dst-} type. + * + * If first argument and second argument are the same container, routine tries to change container inplace. + * + * If {-dst-} is not provided then routine tries to change container inplace. + * + * @param { BufferAny|Long|Null } dst - The destination container. + * @param { BufferAny|Long } src - The container from which makes a shallow copy. + * @param { Range|Number } cinterval - The two-element array that defines the start index and the end index for removing elements. + * If {-cinterval-} is a Number, then it defines the index of removed element. + * If {-cinterval-} is undefined and {-dst-} is null, then routine returns copy of {-src-}, otherwise, routine returns original {-src-}. + * If range[ 0 ] < 0, then start index sets to 0. + * If range[ 1 ] > src.length, end index sets to ( src.length - 1 ). + * If range[ 1 ] < range[ 0 ], then routine removes not elements, the insertion of elements begins at start index. + * @param { BufferAny|Long } ins - The container with elements for insertion. Inserting begins at start index. + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferBut_( buffer ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log true + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferBut_( null, buffer ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log false + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferBut_( buffer, buffer ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log true + * + * @example + * let dst = [ 0, 0 ] + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferBut_( dst, buffer ); + * console.log( got ); + * // log [ 1, 2, 3, 4 ] + * console.log( got === dst ); + * // log true + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let ins = new I32x( [ 0, 0 ] ); + * let got = _.bufferBut_( buffer, [ 1, 2 ], ins ); + * console.log( got ); + * // log Uint8Array[ 1, 0, 0, 4 ] + * console.log( got === buffer ); + * // log true + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferBut_( null, buffer, 1, [ 0, 0 ] ); + * console.log( got ); + * // log Uint8Array[ 0, 0, 2, 3, 4 ] + * console.log( got === buffer ); + * // log false + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferBut_( buffer, buffer, [ 1, 2 ], [ 0, 0 ] ); + * console.log( got ); + * // log Uint8Array[ 1, 0, 0, 4 ] + * console.log( got === buffer ); + * // log true + * + * @example + * let dst = [ 0, 0 ] + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferBut_( dst, buffer, [ 1, 2 ], [ 0, 0 ] ); + * console.log( got ); + * // log [ 1, 0, 0, 4 ] + * console.log( got === dst ); + * // log true + * + * @returns { BufferAny|Long } - If {-dst-} is provided, routine returns container of {-dst-} type. + * Otherwise, routine returns container of {-src-} type. + * If {-dst-} and {-src-} are the same container, routine tries to return original container. + * @function bufferBut_ + * @throws { Error } If arguments.length is less then one or more then four. + * @throws { Error } If {-dst-} is not a buffer, not a Long, not null. + * @throws { Error } If {-src-} is not an any buffer, not a Long. + * @throws { Error } If {-cinterval-} is not a Range or not a Number. + * @namespace Tools + */ + +function bufferBut_( /* dst, src, cinterval, ins */ ) +{ + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + + if( arguments.length < 4 && dst !== null && dst !== src ) + { + dst = arguments[ 0 ]; + src = arguments[ 0 ]; + cinterval = arguments[ 1 ]; + ins = arguments[ 2 ]; + } + + let dstLength = 0; + if( dst !== null ) + dstLength = dst.length === undefined ? dst.byteLength : dst.length; + let srcLength = src.length === undefined ? src.byteLength : src.length; + + if( cinterval === undefined ) + { + cinterval = [ 0, -1 ]; + ins = undefined; + } + else if( _.number.is( cinterval ) ) + { + cinterval = [ cinterval, cinterval ]; + } + + _.assert( _.bufferAnyIs( dst ) || _.longIs( dst ) || dst === null, 'Expects {-dst-} of any buffer type, long or null' ); + _.assert( _.bufferAnyIs( src ) || _.longIs( src ), 'Expects {-src-} of any buffer type or long' ); + _.assert( _.intervalIs( cinterval ), 'Expects cinterval {-cinterval-}' ); + _.assert( _.longIs( ins ) || _.bufferNodeIs( ins ) || ins === undefined || ins === null, 'Expects iterable buffer {-ins-}' ); + + let first = cinterval[ 0 ] = cinterval[ 0 ] === undefined ? 0 : cinterval[ 0 ]; + let last = cinterval[ 1 ] = cinterval[ 1 ] === undefined ? srcLength - 1 : cinterval[ 1 ]; + + if( first < 0 ) + first = 0; + if( first > srcLength ) + first = srcLength; + if( last > srcLength - 1 ) + last = srcLength - 1; + + if( last + 1 < first ) + last = first - 1; + + let delta = last - first + 1; + let insLength = 0 + if( ins ) + insLength = ins.length === undefined ? ins.byteLength : ins.length; + let delta2 = delta - insLength; + let resultLength = srcLength - delta2; + + let result = dst; + if( dst === null ) + { + result = _.bufferMakeUndefined( src, resultLength ); + } + else if( dst === src ) + { + if( ( dstLength === resultLength ) && delta === 0 ) + { + return dst; + } + if( _.arrayLikeResizable( dst ) ) + { + ins ? dst.splice( first, delta, ... ins ) : dst.splice( first, delta ); + return dst; + } + else if( dstLength !== resultLength || _.argumentsArray.is( dst ) ) + { + result = _.bufferMakeUndefined( dst, resultLength ); + } + } + else if( dstLength !== resultLength ) + { + dst = _.bufferMakeUndefined( dst, resultLength ); + } + + let resultTyped = result; + if( _.bufferRawIs( result ) ) + resultTyped = new U8x( result ); + else if( _.bufferViewIs( result ) ) + resultTyped = new U8x( result.buffer ); + let srcTyped = src; + if( _.bufferRawIs( src ) ) + srcTyped = new U8x( src ); + else if( _.bufferViewIs( src ) ) + srcTyped = new U8x( src.buffer ); + + for( let i = 0 ; i < first ; i++ ) + resultTyped[ i ] = srcTyped[ i ]; + + for( let i = last + 1 ; i < srcLength ; i++ ) + resultTyped[ i - delta2 ] = srcTyped[ i ]; + + if( ins ) + { + for( let i = 0 ; i < insLength ; i++ ) + resultTyped[ first + i ] = ins[ i ]; + } + + return result; +} + +// + +/** + * Routine bufferOnly_() returns a shallow copy of a portion of provided container {-dstArray-} + * into a new container selected by range {-range-}. + * + * If first and second provided arguments is containers, then fisrs argument is destination + * container {-dst-} and second argument is source container {-dstArray-}. All data in {-dst-} + * will be cleared. If {-dst-} container is not resizable and resulted container length + * is not equal to original {-dst-} length, then routine makes new container of {-dst-} type. + * + * If first argument and second argument is the same container, routine will try change container inplace. + * + * If {-dst-} is not provided routine makes new container of {-dstArray-} type. + * + * @param { BufferAny|Long|Null } dst - The destination container. + * @param { BufferAny|Long } dstArray - The container from which makes a shallow copy. + * @param { Range|Number } range - The two-element array that defines the start index and the end index for selecting elements. + * If {-range-} is number, then it defines the start index, and the end index sets to dstArray.length. + * If {-range-} is undefined, routine returns copy of {-dstArray-}. + * If range[ 0 ] < 0, then start index sets to 0. + * If range[ 1 ] > dstArray.length, end index sets to dstArray.length. + * If range[ 1 ] <= range[ 0 ], then routine returns empty container. + * @param { * } srcArray - The object of any type for insertion. + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferOnly_( buffer ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log false + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferOnly_( null, buffer ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log false + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferOnly_( buffer, buffer ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log true + * + * @example + * let dst = [ 0, 0 ] + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferOnly_( dst, buffer ); + * console.log( got ); + * // log [ 1, 2, 3, 4 ] + * console.log( got === dst ); + * // log true + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let src = new I32x( [ 0, 0, 0 ] ); + * let got = _.bufferOnly_( buffer, [ 1, 3 ], src ); + * console.log( got ); + * // log Uint8Array[ 2, 3 ] + * console.log( got === buffer ); + * // log false + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferOnly_( null, buffer, 1, [ 0, 0, 0 ] ); + * console.log( got ); + * // log Uint8Array[ 2, 3, 4 ] + * console.log( got === buffer ); + * // log false + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferOnly_( buffer, buffer, [ 1, 3 ], [ 0, 0, 0 ] ); + * console.log( got ); + * // log Uint8Array[ 2, 3 ] + * console.log( got === buffer ); + * // log false + * + * @example + * let dst = [ 0, 0 ]; + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferOnly_( dst, buffer, [ 1, 3 ], [ 0, 0, 0 ] ); + * console.log( got ); + * // log [ 2, 3 ] + * console.log( got === dst ); + * // log true + * + * @returns { BufferAny|Long } If {-dst-} is provided, routine returns container of {-dst-} type. + * Otherwise, routine returns container of {-dstArray-} type. + * If {-dst-} and {-dstArray-} is the same container, routine tries to return original container. + * @function bufferOnly_ + * @throws { Error } If arguments.length is less then one or more then four. + * @throws { Error } If {-dst-} is not an any buffer, not a Long, not null. + * @throws { Error } If {-dstArray-} is not an any buffer, not a Long. + * @throws { Error } If ( range ) is not a Range or not a Number. + * @namespace Tools + */ + +function bufferOnly_( dst, src, cinterval ) +{ + _.assert( 1 <= arguments.length && arguments.length <= 3, 'Expects not {-ins-} argument' ); + + if( arguments.length < 3 && dst !== null && dst !== src ) + { + dst = arguments[ 0 ]; + src = arguments[ 0 ]; + cinterval = arguments[ 1 ]; + } + + let dstLength = 0; + if( dst !== null ) + dstLength = dst.length === undefined ? dst.byteLength : dst.length; + let srcLength = src.length === undefined ? src.byteLength : src.length; + + if( cinterval === undefined ) + cinterval = [ 0, srcLength - 1 ]; + if( _.number.is( cinterval ) ) + cinterval = [ 0, cinterval ]; + + _.assert( _.bufferAnyIs( dst ) || _.longIs( dst ) || dst === null, 'Expects {-dst-} of any buffer type, long or null' ); + _.assert( _.bufferAnyIs( src ) || _.longIs( src ), 'Expects {-src-} of any buffer type or long' ); + _.assert( _.intervalIs( cinterval ), 'Expects cinterval {-cinterval-}' ); + + let first = cinterval[ 0 ] = cinterval[ 0 ] === undefined ? 0 : cinterval[ 0 ]; + let last = cinterval[ 1 ] = cinterval[ 1 ] === undefined ? srcLength - 1 : cinterval[ 1 ]; + + if( first < 0 ) + first = 0; + if( last > srcLength - 1 ) + last = srcLength - 1; + + if( last + 1 < first ) + last = first - 1; + + let first2 = Math.max( first, 0 ); + let last2 = Math.min( srcLength - 1, last ); + + let resultLength = last - first + 1; + + let result = dst; + if( dst === null ) + { + result = _.bufferMakeUndefined( src, resultLength ); + } + else if( dst === src ) + { + if( dstLength === resultLength ) + { + return dst; + } + if( _.arrayLikeResizable( dst ) ) + { + _.assert( Object.isExtensible( dst ), 'Array is not extensible, cannot change array' ); + if( resultLength === 0 ) + return _.longEmpty( dst ); + + dst.splice( last2 + 1, dst.length - last + 1 ); + dst.splice( 0, first2 ); + return dst; + } + else if( dstLength !== resultLength || _.argumentsArray.is( dst ) ) + { + result = _.bufferMakeUndefined( dst, resultLength ); + } + } + else if( dstLength !== resultLength ) + { + if( _.arrayLikeResizable( result ) ) + result.splice( resultLength ); + else + result = _.bufferMakeUndefined( dst, resultLength ); + } + + let resultTyped = result; + if( _.bufferRawIs( result ) ) + resultTyped = new U8x( result ); + else if( _.bufferViewIs( result ) ) + resultTyped = new U8x( result.buffer ); + let srcTyped = src; + if( _.bufferRawIs( src ) ) + srcTyped = new U8x( src ); + else if( _.bufferViewIs( src ) ) + srcTyped = new U8x( src.buffer ); + + for( let r = first2 ; r < last2 + 1 ; r++ ) + resultTyped[ r - first2 ] = srcTyped[ r ]; + + return result; +} + +// + +/** + * Routine bufferGrow_() grows provided container {-dst-} by copying elements of source buffer to it. + * Routine uses cinterval {-cinterval-} positions of the source container and value {-ins-} to fill destination buffer. + * Routine can only grows size of source container. + * + * If first and second provided arguments is containers, then fisrs argument is destination + * container {-dst-} and second argument is source container {-dstArray-}. All data in {-dst-} + * will be cleared. If {-dst-} container is not resizable and resulted container length + * is not equal to original {-src-} length, then routine makes new container with {-dst-} type. + * + * If first argument and second argument is the same container, routine will try change container inplace. + * + * If {-dst-} is not provided routine makes new container with {-src-} type. + * + * @param { BufferAny|Long|Null } dst - The destination container. + * @param { BufferAny|Long } src - The container from which makes a shallow copy. + * @param { Range|Number } cinterval - The two-element array that defines the start index and the end index for copying elements from {-src-} and adding {-ins-}. + * If {-range-} is number, then it defines the end index, and the start index is 0. + * If range[ 0 ] < 0, then start index sets to 0, end index incrementes by absolute value of range[ 0 ]. + * If range[ 0 ] > 0, then start index sets to 0. + * If range[ 1 ] < range[ 0 ], then routine returns a copy of original container. + * @param { * } ins - The object of any type for insertion. + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferGrow_( buffer ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log true + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferGrow_( null, buffer ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log false + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferGrow_( buffer, buffer, [ 0, 3 ] ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log true + * + * @example + * let dst = [ 0, 0 ] + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferGrow_( dst, buffer, [ 0, 3 ] ); + * console.log( got ); + * // log [ 1, 2, 3, 4 ] + * console.log( got === dst ); + * // log true + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferGrow_( buffer, [ 1, 5 ], 0 ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4, 0, 0 ] + * console.log( got === buffer ); + * // log true + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferGrow_( null, buffer, 2, 1 ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log false + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferGrow_( buffer, buffer, [ 0, 3 ], 2 ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log true + * + * @example + * let dst = [ 0, 0 ]; + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferGrow_( dst, buffer, [ 1, 5 ], 1 ); + * console.log( got ); + * // log [ 1, 2, 3, 4, 1, 1 ] + * console.log( got === dst ); + * // log true + * + * @returns { BufferAny|Long } - If {-dst-} is provided, routine returns container of {-dst-} type. + * Otherwise, routine returns container of {-src-} type. + * If {-dst-} and {-src-} is the same container, routine tries to return original container. + * @function bufferGrow_ + * @throws { Error } If arguments.length is less then one or more then four. + * @throws { Error } If {-dst-} is not an any buffer, not a Long, not null. + * @throws { Error } If {-src-} is not an any buffer, not a Long. + * @throws { Error } If ( range ) is not a Range or not a Number. + * @namespace Tools + */ + +function bufferGrow_( /* dst, src, cinterval, ins */ ) +{ + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + + if( arguments.length < 4 && dst !== null && dst !== src ) + { + dst = arguments[ 0 ]; + src = arguments[ 0 ]; + cinterval = arguments[ 1 ]; + ins = arguments[ 2 ]; + } + + let dstLength = 0; + if( dst !== null ) + dstLength = dst.length === undefined ? dst.byteLength : dst.length; + let srcLength = src.length === undefined ? src.byteLength : src.length; + + if( cinterval === undefined ) + cinterval = [ 0, srcLength - 1 ]; + if( _.number.is( cinterval ) ) + cinterval = [ 0, cinterval - 1 ]; + + _.assert( _.bufferAnyIs( dst ) || _.longIs( dst ) || dst === null, 'Expects {-dst-} of any buffer type, long or null' ); + _.assert( _.bufferAnyIs( src ) || _.longIs( src ), 'Expects {-src-} of any buffer type or long' ); + _.assert( _.intervalIs( cinterval ), 'Expects cinterval {-cinterval-}' ); + + let first = cinterval[ 0 ] = cinterval[ 0 ] === undefined ? 0 : cinterval[ 0 ]; + let last = cinterval[ 1 ] = cinterval[ 1 ] === undefined ? srcLength - 1 : cinterval[ 1 ]; + + if( first > 0 ) + first = 0; + if( last < srcLength - 1 ) + last = srcLength - 1; + + if( first < 0 ) + { + last -= first; + first -= first; + } + + if( last + 1 < first ) + last = first - 1; + + let first2 = Math.max( -cinterval[ 0 ], 0 ); + let last2 = Math.min( srcLength - 1 + first2, last + first2 ); + + let resultLength = last - first + 1; + + let result = dst; + if( dst === null ) + { + result = _.bufferMakeUndefined( src, resultLength ); + } + else if( dst === src ) + { + if( dstLength === resultLength ) + { + return dst; + } + if( _.arrayLikeResizable( dst ) ) + { + _.assert( Object.isExtensible( dst ), 'Array is not extensible, cannot change array' ); + dst.splice( first, 0, ... _.dup( ins, first2 ) ); + dst.splice( last2 + 1, 0, ... _.dup( ins, resultLength <= last2 ? 0 : resultLength - last2 - 1 ) ); + return dst; + } + else if( dstLength !== resultLength || _.argumentsArray.is( dst ) ) + { + result = _.bufferMakeUndefined( dst, resultLength ); + } + } + else if( dstLength !== resultLength ) + { + if( _.arrayLikeResizable( result ) ) + result.splice( resultLength ); + else + result = _.bufferMakeUndefined( dst, resultLength ); + } + + let resultTyped = result; + if( _.bufferRawIs( result ) ) + resultTyped = new U8x( result ); + else if( _.bufferViewIs( result ) ) + resultTyped = new U8x( result.buffer ); + let srcTyped = src; + if( _.bufferRawIs( src ) ) + srcTyped = new U8x( src ); + else if( _.bufferViewIs( src ) ) + srcTyped = new U8x( src.buffer ); + + for( let r = first2 ; r < last2 + 1 ; r++ ) + resultTyped[ r ] = srcTyped[ r - first2 ]; + + if( ins !== undefined ) + { + for( let r = 0 ; r < first2 ; r++ ) + resultTyped[ r ] = ins; + + for( let r = last2 + 1 ; r < resultLength ; r++ ) + resultTyped[ r ] = ins; + } + + return result; +} + +// + +/** + * Routine bufferRelength_() changes length of provided container {-dstArray-} by copying it elements to newly created container of the same + * type using range {-range-} positions of the original containers and value to fill free space after copy {-srcArray-}. + * Routine can grows and reduces size of container. + * + * If first and second provided arguments is containers, then fisrs argument is destination + * container {-dst-} and second argument is source container {-dstArray-}. All data in {-dst-} + * will be cleared. If {-dst-} container is not resizable and resulted container length + * is not equal to original {-dst-} length, then routine makes new container of {-dst-} type. + * + * If first argument and second argument is the same container, routine will try change container inplace. + * + * If {-dst-} is not provided routine makes new container of {-dstArray-} type. + * + * @param { BufferAny|Long|Null } dst - The destination container. + * @param { BufferAny|Long } dstArray - The container from which makes a shallow copy. + * @param { Range|Number } range - The two-element array that defines the start index and the end index for copying elements from {-dstArray-} and adding {-srcArray-}. + * If {-range-} is number, then it defines the start index, and the end index sets to dstArray.length. + * If range[ 0 ] < 0, then start index sets to 0. + * If range[ 1 ] <= range[ 0 ], then routine returns empty container. + * @param { * } srcArray - The object of any type for insertion. + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferRelength_( buffer ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log false + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferRelength_( null, buffer ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log false + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferRelength_( buffer, buffer ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log true + * + * @example + * let dst = [ 0, 0 ] + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferRelength_( dst, buffer ); + * console.log( got ); + * // log [ 1, 2, 3, 4 ] + * console.log( got === dst ); + * // log true + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferRelength_( buffer, [ 1, 6 ], 0 ); + * console.log( got ); + * // log Uint8Array[ 2, 3, 4, 0, 0 ] + * console.log( got === buffer ); + * // log false + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferRelength_( null, buffer, 2, 1 ); + * console.log( got ); + * // log Uint8Array[ 3, 4 ] + * console.log( got === buffer ); + * // log false + * + * @example + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferRelength_( buffer, buffer, [ 0, 3 ], 2 ); + * console.log( got ); + * // log Uint8Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log true + * + * @example + * let dst = [ 0, 0 ]; + * let buffer = new U8x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferRelength_( dst, buffer, [ 1, 6 ], [ 0, 0, 0 ] ); + * console.log( got ); + * // log [ 2, 3, 4, [ 0, 0, 0 ], [ 0, 0, 0 ] ] + * console.log( got === dst ); + * // log true + * + * @returns { BufferAny|Long } If {-dst-} is provided, routine returns container of {-dst-} type. + * Otherwise, routine returns container of {-dstArray-} type. + * If {-dst-} and {-dstArray-} is the same container, routine tries to return original container. + * @function bufferRelength_ + * @throws { Error } If arguments.length is less then one or more then four. + * @throws { Error } If {-dst-} is not an any buffer, not a Long, not null. + * @throws { Error } If {-dstArray-} is not an any buffer, not a Long. + * @throws { Error } If ( range ) is not a Range or not a Number. + * @namespace Tools + */ + +function bufferRelength_( /* dst, src, cinterval, ins */ ) +{ + let dst = arguments[ 0 ]; + let src = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + + if( arguments.length < 4 && dst !== null && dst !== src ) + { + dst = arguments[ 0 ]; + src = arguments[ 0 ]; + cinterval = arguments[ 1 ]; + ins = arguments[ 2 ]; + } + + let dstLength = 0; + if( dst !== null ) + dstLength = dst.length === undefined ? dst.byteLength : dst.length; + let srcLength = src.length === undefined ? src.byteLength : src.length; + + if( cinterval === undefined ) + cinterval = [ 0, srcLength - 1 ]; + if( _.number.is( cinterval ) ) + cinterval = [ 0, cinterval-1 ]; + + _.assert( _.bufferAnyIs( dst ) || _.longIs( dst ) || dst === null, 'Expects {-dst-} of any buffer type, long or null' ); + _.assert( _.bufferAnyIs( src ) || _.longIs( src ), 'Expects {-src-} of any buffer type or long' ); + _.assert( _.intervalIs( cinterval ), 'Expects cinterval {-cinterval-}' ); + + let first = cinterval[ 0 ] = cinterval[ 0 ] === undefined ? 0 : cinterval[ 0 ]; + let last = cinterval[ 1 ] = cinterval[ 1 ] === undefined ? srcLength - 1 : cinterval[ 1 ]; + + if( last < first ) + last = first - 1; + + if( cinterval[ 1 ] < 0 && cinterval[ 0 ] < 0 ) + cinterval[ 0 ] -= cinterval[ 1 ] + 1; + + if( first < 0 ) + { + last -= first; + first -= first; + } + + let first2 = Math.max( Math.abs( cinterval[ 0 ] ), 0 ); + let last2 = Math.min( srcLength - 1, last ); + + let resultLength = last - first + 1; + + let result = dst; + if( dst === null ) + { + result = _.bufferMakeUndefined( src, resultLength ); + } + else if( dst === src ) + { + if( dstLength === resultLength && cinterval[ 0 ] === 0 ) + { + return dst; + } + if( _.arrayLikeResizable( dst ) ) + { + _.assert( Object.isExtensible( dst ), 'dst is not extensible, cannot change dst' ); + if( cinterval[ 0 ] < 0 ) + { + dst.splice( first, 0, ... _.dup( ins, first2 ) ); + dst.splice( last2 + 1, src.length - last2, ... _.dup( ins, last - last2 ) ); + } + else + { + dst.splice( 0, first ); + dst.splice( last2 + 1 - first2, src.length - last2, ... _.dup( ins, last - last2 ) ); + } + return dst; + } + else if( dstLength !== resultLength || _.argumentsArray.is( dst ) ) + { + result = _.bufferMakeUndefined( dst, resultLength ); + } + } + else if( dstLength !== resultLength ) + { + if( _.arrayLikeResizable( result ) ) + result.splice( resultLength ); + else + result = _.bufferMakeUndefined( dst, resultLength ); + } + + let resultTyped = result; + if( _.bufferRawIs( result ) ) + resultTyped = new U8x( result ); + else if( _.bufferViewIs( result ) ) + resultTyped = new U8x( result.buffer ); + let srcTyped = src; + if( _.bufferRawIs( src ) ) + srcTyped = new U8x( src ); + else if( _.bufferViewIs( src ) ) + srcTyped = new U8x( src.buffer ); + + if( resultLength === 0 ) + { + return result; + } + if( cinterval[ 0 ] < 0 ) + { + for( let r = first2 ; r < ( last2 + 1 + first2 ) && r < resultLength ; r++ ) + resultTyped[ r ] = srcTyped[ r - first2 ]; + if( ins !== undefined ) + { + for( let r = 0 ; r < first2 ; r++ ) + resultTyped[ r ] = ins; + for( let r = last2 + 1 + first2 ; r < resultLength ; r++ ) + resultTyped[ r ] = ins; + } + } + else + { + for( let r = first2 ; r < last2 + 1 ; r++ ) + resultTyped[ r - first2 ] = srcTyped[ r ]; + if( ins !== undefined ) + { + for( let r = last2 + 1 ; r < last + 1 ; r++ ) + resultTyped[ r - first2 ] = ins; + } + } + + return result; +} + +// + +function bufferResize_( dst, srcBuffer, size ) +{ + if( dst === null ) + dst = _.nothing; + + if( arguments.length === 2 ) + { + size = srcBuffer; + srcBuffer = dst; + } + + let range = _.intervalIs( size ) ? size : [ 0, size ]; + size = range[ 1 ] - range[ 0 ]; + + if( range[ 1 ] < range[ 0 ] ) + range[ 1 ] = range[ 0 ]; + + _.assert( _.bufferAnyIs( srcBuffer ) && srcBuffer.byteLength >= 0 ); + _.assert( _.intervalIs( range ) ); + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( dst === srcBuffer && range[ 0 ] === 0 && range[ 1 ] === srcBuffer.byteLength ) + return srcBuffer; + + let result; + let newOffset = srcBuffer.byteOffset ? srcBuffer.byteOffset + range[ 0 ] : range[ 0 ]; + + if( dst === _.nothing ) + { + _.assert( dst === _.nothing ); + + result = _.bufferMakeUndefined( srcBuffer, size / srcBuffer.BYTES_PER_ELEMENT || size ); + let resultTyped = _.bufferRawIs( result ) ? new U8x( result ) : new U8x( result.buffer ); + let srcBufferToU8x = _.bufferRawIs( srcBuffer ) ? new U8x( srcBuffer ) : new U8x( srcBuffer.buffer ); + + let first = Math.max( newOffset, 0 ); + let last = Math.min( srcBufferToU8x.byteLength, newOffset + size ); + newOffset = newOffset < 0 ? -newOffset : 0; + for( let r = first ; r < last ; r++ ) + resultTyped[ r - first + newOffset ] = srcBufferToU8x[ r ]; + } + else + { + _.assert( _.bufferAnyIs( dst ) ); + + if( dst === srcBuffer && !_.bufferRawIs( srcBuffer ) && newOffset >= 0 && newOffset + size <= srcBuffer.buffer.byteLength ) + { + if( _.bufferNodeIs( srcBuffer ) ) + result = BufferNode.from( srcBuffer.buffer, newOffset, size ); + else if( _.bufferViewIs( srcBuffer ) ) + result = new BufferView( srcBuffer.buffer, newOffset, size ); + else + result = new srcBuffer.constructor( srcBuffer.buffer, newOffset, size / srcBuffer.BYTES_PER_ELEMENT ); + } + else if( _.bufferRawIs( dst ) ) + { + if( size === dst.byteLength ) + result = dst; + else + result = _.bufferMakeUndefined( dst, size ); + } + else if( size <= dst.byteLength ) + { + result = dst; + } + else + { + result = _.bufferMakeUndefined( dst, size / dst.BYTES_PER_ELEMENT || size ); + } + + let dstTyped = _.bufferRawIs( result ) ? new U8x( result ) : new U8x( result.buffer ); + let srcBufferToU8x = _.bufferRawIs( srcBuffer ) ? new U8x( srcBuffer ) : new U8x( srcBuffer.buffer ); + + let first = Math.max( newOffset, 0 ); + let last = Math.min( srcBufferToU8x.byteLength, newOffset + size ); + for( let r = first ; r < last ; r++ ) + dstTyped[ r - first ] = srcBufferToU8x[ r ]; + dstTyped.fill( 0, last - first, dstTyped.length ); + } + + return result; +} + +// + +function bufferReusing4Arguments_head( routine, args ) +{ + _.assert( arguments.length === 2 ); + _.assert( args.length > 0, 'Expects arguments' ); + + /* qqq : for Dmytro : use switch here and in similar code */ + let o = Object.create( null ); + if( args.length === 1 ) + { + if( _.mapIs( args[ 0 ] ) ) + { + o = args[ 0 ]; + } + else + { + o.dst = null; + o.src = args[ 0 ]; + } + } + else if( args.length === 2 ) + { + o.dst = null; + o.src = args[ 0 ]; + o.cinterval = args[ 1 ]; + } + else if( args.length === 3 ) + { + o.dst = null; + o.src = args[ 0 ]; + o.cinterval = args[ 1 ]; + o.ins = args[ 2 ]; + } + else if( args.length === 4 ) + { + o.dst = args[ 0 ]; + o.src = args[ 1 ]; + o.cinterval = args[ 2 ]; + o.ins = args[ 3 ]; + } + else + { + _.assert( 0, 'Expects less then 4 arguments' ); + } + + /* */ + + _.routine.optionsWithoutUndefined( routine, o ); /* qqq : for Dmytro : use _.routine.options() */ + _.assert( _.bufferAnyIs( o.src ) || _.longIs( o.src ) ); + _.assert( _.intervalIs( o.cinterval ) || _.numberIs( o.cinterval ) || o.cinterval === null ); + _.assert( _.intIs( o.minSize ) && o.minSize >= 0 ); + + o.growFactor = o.growFactor === 0 ? 1 : o.growFactor; + o.shrinkFactor = o.shrinkFactor === 0 ? 1 : o.shrinkFactor; + + if( o.dst === _.self ) + o.dst = o.src; + + return o; +} + +// + +function bufferReusing3Arguments_head( routine, args ) +{ + _.assert( arguments.length === 2 ); + _.assert( 1 <= args.length && args.length <= 3 ); + + let o; + if( args.length === 3 ) + { + o = Object.create( null ); + o.dst = args[ 0 ]; + o.src = args[ 1 ]; + o.cinterval = args[ 2 ]; + o = _.bufferReusing4Arguments_head.call( this, routine, [ o ] ); + } + else + { + o = _.bufferReusing4Arguments_head.apply( this, arguments ); + } + + return o; +} + +// + +function _bufferElementSizeGet( src ) +{ + if( src.BYTES_PER_ELEMENT ) + return src.BYTES_PER_ELEMENT; + else if( src.byteLength === undefined ) + return 8; + else + return 1; +} + +// + +function _dstBufferSizeRecount( o ) +{ + if( !_.numberIs( o.dstSize ) ) + o.dstSize = ( o.cinterval[ 1 ] - o.cinterval[ 0 ] + 1 ) * o.dstElementSize; + + if( o.growFactor > 1 && o.reusing && o.dst !== null ) + { + let dstSize = o.dst.length ? o.dst.length * o.dstElementSize : o.dst.byteLength; + if( dstSize < o.dstSize ) + { + let growed = dstSize * o.growFactor; + o.dstSize = growed > o.dstSize ? growed : o.dstSize; + } + } + + o.dstSize = o.minSize > o.dstSize ? o.minSize : o.dstSize; + return o.dstSize; +} + +// + +function _bufferTypedViewMake( src ) +{ + let srcTyped = src; + if( _.bufferRawIs( src ) ) + srcTyped = new U8x( src ); + if( _.bufferViewIs( src ) ) + srcTyped = new U8x( src.buffer ); + + return srcTyped; +} + +// + +function _resultBufferReusedMaybe( o ) +{ + let buffer; + + let dstOffset = 0; + let dstSize = o.dst.length ? o.dst.length * o.dstElementSize : o.dst.byteLength; + + if( o.offsetting && !_.bufferNodeIs( o.dst ) && _.bufferAnyIs( o.dst ) ) + { + dstOffset = o.dst.byteOffset ? o.dst.byteOffset : dstOffset; + dstSize = o.dst.buffer ? o.dst.buffer.byteLength : dstSize; + } + + let shouldReuse = insideBufferBounds( dstOffset, dstSize, o.dstSize ); + let shouldShrink = shrinkFactorCheck( dstSize, o.dstSize ); + + if( shouldReuse && !shouldShrink ) + { + buffer = o.dst; + let leftOffset = dstOffset + o.cinterval[ 0 ]; + let bufferLength = buffer.buffer && !_.bufferViewIs( buffer ) ? buffer.length : buffer.byteLength; + + if( leftOffset !== dstOffset || o.dstSize !== bufferLength ) + { + if( !o.offsetting ) + leftOffset += buffer.byteOffset ? buffer.byteOffset : 0; + + if( _.bufferNodeIs( buffer ) ) + buffer = BufferNode.from( buffer.buffer, leftOffset, o.dstSize ); + else if( buffer.buffer ) + buffer = new buffer.constructor( buffer.buffer, leftOffset, o.dstSize ); + } + } + else + { + buffer = _resultBufferMake( o ); + } + + return buffer; + + /* */ + + function shrinkFactorCheck( dstSize, resultSize ) + { + if( o.shrinkFactor > 1 ) + return ( dstSize / resultSize ) >= o.shrinkFactor; + return false; + } + + /* */ + function insideBufferBounds( dstOffset, dstSize, resultSize ) + { + let leftOffset = dstOffset + o.cinterval[ 0 ]; + let insideLeftBound = leftOffset >= 0 && leftOffset < dstSize; + let rightBound = leftOffset + resultSize; + let insideRightBound = rightBound <= dstSize; + return insideLeftBound && insideRightBound; + } +} + +// + +function _resultBufferMake( o ) +{ + let buffer; + let dstResultedLength = o.dstSize / o.dstElementSize; + _.assert( _.intIs( dstResultedLength ) ); + + if( o.dst === null ) + { + buffer = _.bufferMakeUndefined( o.src, dstResultedLength ); + } + else if( o.dst.length === dstResultedLength ) + { + buffer = o.dst; + } + else if( o.dst.byteLength === o.dstSize ) + { + buffer = o.dst; + } + else if( _.arrayLikeResizable( o.dst ) ) + { + buffer = o.dst; + buffer.length = dstResultedLength; + } + else + { + buffer = _.bufferMakeUndefined( o.dst, dstResultedLength ); + } + + return buffer; +} + +// + +/** + * Routine bufferReusingBut() copies elements from source buffer {-src-} to destination buffer {-dst-}. + * Routine copies all elements excluding elements in interval {-cinterval-}, its elements replace by elements + * from insertion buffer {-ins-}. + * + * Data in buffer {-dst-} overwrites. If {-dst-} container is not resizable and resulted length of destination + * container is not equal to original {-dst-} length, then routine makes new container of {-dst-} type. + * + * If buffer {-dst-} and {-src-} are the same buffer, then routine tries to change container {-src-} inplace and + * reuse original raw buffer. + * + * @example + * let buffer = new F64x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferReusingBut( buffer, [ 1, 1 ], [ 5 ] ); + * console.log( got ); + * // log Float64Array[ 1, 5, 3, 4, 0, 0, 0, 0 ] + * console.log( got === buffer ); + * // log false + * + * @example + * let buffer = new F64x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferReusingBut + * ({ + * dst : buffer, + * src : buffer, + * cinterval : [ 1, 1 ], + * ins : [ 5 ], + * minSize : 2, + * }); + * console.log( got ); + * // log Float64Array[ 1, 5, 3, 4 ] + * console.log( got === buffer ); + * // log true + * + * First parameter set : + * @param { BufferAny|Long|Null } dst - The destination container. + * @param { BufferAny|Long } src - The container from which makes a shallow copy. + * @param { Interval|Number } cinterval - The closed interval that defines the start index and the end index for removing elements. + * If {-cinterval-} is a Number, then it defines the index of removed element. + * If cinterval[ 0 ] < 0, then start index sets to 0. + * If cinterval[ 1 ] > src.length, end index sets to ( src.length - 1 ). + * If cinterval[ 1 ] < cinterval[ 0 ], then routine removes not elements, the insertion of elements begins at start index. + * @param { BufferAny|Long|Undefined } ins - The container with elements for insertion. Inserting begins at start index. + * + * Second parameter set : + * @param { Aux } o - Options map. + * @param { BufferAny|Long|Null } o.dst - The destination container. + * @param { BufferAny|Long } o.src - The container from which makes a shallow copy. + * @param { Interval|Number } o.cinterval - The closed interval that defines the start index and the end index for removing elements. + * The behavior same to first parameter set. + * @param { BufferAny|Long|Undefined } o.ins - The container with elements for insertion. Inserting begins at start index. + * @param { BoolLike } o.reusing - Allows routine to reuse original raw buffer. Default is true. + * @param { BoolLike } o.offsetting - Allows routine to change offset in destination buffer {-o.dst-}. Default is true. + * @param { Number } o.minSize - Minimal size of resulted buffer. If resulted buffer size is less than {-o.minSize-}, routine makes + * new buffer. Default is 64. + * @param { Number } o.growFactor - If routine needs to make new container that is bigger than {-o.minSize-}, then routine multiplies + * {-o.growFactor-} on resulted buffer size. If {-o.growFactor-} <= 1, routine does not grow size of resulted buffer. Default is 2. + * @param { Number } o.shrinkFactor - If resulted buffer in {-o.shrinkFactor-} times less than its raw buffer, than routine makes + * new buffer. If {-o.shrinkFactor-} <= 1, then routine not change original raw buffer. Default is 0. + * + * @returns { BufferAny|Long } - If {-dst-} is provided, routine returns container of {-dst-} type. + * Otherwise, routine returns container of {-src-} type. + * If {-dst-} and {-src-} are the same container, routine tries to return original container. + * Routine tries to save original raw buffer. + * @function bufferReusingBut + * @throws { Error } If arguments.length is less then one or more then four. + * @throws { Error } If {-dst-} has not valid type. + * @throws { Error } If {-src-} has not valid type. + * @throws { Error } If {-cinterval-} has not valid type. + * @throws { Error } If {-ins-} has not valid type. + * @throws { Error } If options map {-o-} has not valid type. + * @throws { Error } If options map {-o-} has not known options. + * @throws { Error } If {-o.minSize-} has not valid type or is not an Integer. + * @throws { Error } If {-o.growFactor-} has not valid type or is not an Integer. + * @throws { Error } If {-o.shrinkFactor-} has not valid type or is not an Integer. + * @namespace Tools + */ + +function bufferReusingBut_body( o ) +{ + _.assert( _.intIs( o.growFactor ) && o.growFactor >= 0 ); + _.assert( _.intIs( o.shrinkFactor ) && o.shrinkFactor >= 0 ); + + /* */ + + let bufferLength = 0; + if( o.dst ) + bufferLength = o.dst && o.dst.length !== undefined ? o.dst.length : o.dst.byteLength; + else + bufferLength = o.src.length === undefined ? o.src.byteLength : o.src.length; + + let _cinterval; + o.cinterval = cintervalClamp(); + + if( o.ins === null || o.ins === undefined ) + o.ins = []; + + _.assert( _.longIs( o.ins ) || _.bufferAnyIs( o.ins ) ); + + /* */ + + let newBufferCreate = o.dst === null; + + _.assert( newBufferCreate || _.bufferAnyIs( o.dst ) || _.longIs( o.dst ) ); + + let dstElementSize; + if( newBufferCreate ) + o.dstElementSize = _._bufferElementSizeGet( o.src ); + else + o.dstElementSize = _._bufferElementSizeGet( o.dst ); + + o.dstSize = bufferSizeCount( _cinterval, o.dstElementSize ); + o.dstSize = _._dstBufferSizeRecount( o ); + + let dstBuffer + if( o.reusing && !newBufferCreate ) + dstBuffer = _resultBufferReusedMaybe( o ); + else + dstBuffer = _resultBufferMake( o ); + + let dstTyped = _bufferTypedViewMake( dstBuffer ); + let srcTyped = _bufferTypedViewMake( o.src ); + let result = dstBufferFill( dstTyped, srcTyped, o.cinterval, o.ins ); + + return dstBuffer; + + /* */ + + function cintervalClamp() + { + if( o.cinterval === null ) + o.cinterval = [ 0, -1 ]; + else if( _.number.is( o.cinterval ) ) + o.cinterval = [ o.cinterval, o.cinterval ]; + + if( o.cinterval[ 0 ] < 0 ) + o.cinterval[ 0 ] = 0; + if( o.cinterval[ 1 ] < o.cinterval[ 0 ] - 1 ) + o.cinterval[ 1 ] = o.cinterval[ 0 ] - 1; + + _cinterval = o.cinterval; + return [ 0, o.cinterval[ 1 ] ]; + } + + function bufferSizeCount( cinterval, elementSize ) + { + let length = bufferLength - ( cinterval[ 1 ] - cinterval[ 0 ] + 1 ) + o.ins.length; + return length * elementSize; + } + + /* */ + + function dstBufferFill( /* dstTyped, srcTyped, cinterval, ins */ ) + { + let dstTyped = arguments[ 0 ]; + let srcTyped = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + /* */ + + cinterval = _cinterval; + + let left = Math.max( 0, cinterval[ 0 ] ); + let right = left + ins.length + let start = cinterval[ 1 ] + 1; + + if( srcTyped.length ) + { + if( dstTyped.buffer === srcTyped.buffer ) + { + let val = srcTyped[ srcTyped.length - 1 ]; + /* qqq for Dmytro : not optimal */ + for( let i = srcTyped.length - 1 ; i >= start ; i-- ) + { + let temp = srcTyped[ i - 1 ]; + dstTyped[ right + i - start ] = val; + val = temp; + } + } + else + { + for( let i = srcTyped.length - 1 ; i >= start ; i-- ) + dstTyped[ right + i - start ] = srcTyped[ i ]; + } + + for( let i = 0 ; i < left ; i++ ) + dstTyped[ i ] = srcTyped[ i ]; + } + + for( let i = left ; i < right ; i++ ) + dstTyped[ i ] = ins[ i - left ]; + + return dstTyped; + } +} + +bufferReusingBut_body.defaults = +{ + dst : null, + src : null, + cinterval : null, + ins : null, + offsetting : 1, + reusing : 1, + growFactor : 2, + shrinkFactor : 0, + minSize : 64, +}; + +// + +let bufferReusingBut = _.routine.unite( bufferReusing4Arguments_head, bufferReusingBut_body ); + +// + +/** + * Routine bufferReusingOnly() gets the part of source buffer {-src-} and copies it to destination buffer {-dst-}. + * + * Data in buffer {-dst-} overwrites. If {-dst-} container is not resizable and resulted length of destination + * container is not equal to original {-dst-} length, then routine makes new container of {-dst-} type. + * + * If buffer {-dst-} and {-src-} are the same buffer, then routine tries to change container {-src-} inplace and + * reuse original raw buffer. + * + * @example + * let buffer = new F64x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferReusingOnly( buffer, [ 1, 1 ] ); + * console.log( got ); + * // log Float64Array[ 2 ] + * console.log( got === buffer ); + * // log false + * console.log( got.buffer === buffer.buffer ); + * // log false + * + * @example + * let buffer = new F64x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferReusingOnly + * ({ + * dst : buffer, + * src : buffer, + * cinterval : [ 1, 1 ], + * minSize : 1, + * }); + * console.log( got ); + * // log Float64Array[ 2 ] + * console.log( got === buffer ); + * // log false + * console.log( got.buffer === buffer.buffer ); + * // log true + * + * First parameter set : + * @param { BufferAny|Long|Null } dst - The destination container. + * @param { BufferAny|Long } src - The container from which makes a shallow copy. + * @param { Interval|Number } cinterval - The closed interval that defines the start index and the end index for removing elements. + * If {-cinterval-} is a Number, then it defines the index of removed element. + * If cinterval[ 0 ] < 0, then start index sets to 0. + * If cinterval[ 1 ] > src.length, end index sets to ( src.length - 1 ). + * If cinterval[ 1 ] < cinterval[ 0 ], then routine makes buffer of minimal size and fills by data. + * + * Second parameter set : + * @param { Aux } o - Options map. + * @param { BufferAny|Long|Null } o.dst - The destination container. + * @param { BufferAny|Long } o.src - The container from which makes a shallow copy. + * @param { Interval|Number } o.cinterval - The closed interval that defines the start index and the end index for removing elements. + * The behavior same to first parameter set. + * @param { BoolLike } o.reusing - Allows routine to reuse original raw buffer. Default is true. + * @param { BoolLike } o.offsetting - Allows routine to change offset in destination buffer {-o.dst-}. Default is true. + * @param { Number } o.minSize - Minimal size of resulted buffer. If resulted buffer size is less than {-o.minSize-}, routine makes + * new buffer. Default is 64. + * @param { Number } o.shrinkFactor - If resulted buffer in {-o.shrinkFactor-} times less than its raw buffer, than routine makes + * new buffer. If {-o.shrinkFactor-} <= 1, then routine not change original raw buffer. Default is 0. + * + * @returns { BufferAny|Long } - If {-dst-} is provided, routine returns container of {-dst-} type. + * Otherwise, routine returns container of {-src-} type. + * If {-dst-} and {-src-} are the same container, routine tries to return original container. + * Routine tries to save original raw buffer. + * @function bufferReusingOnly + * @throws { Error } If arguments.length is less then one or more then four. + * @throws { Error } If {-dst-} has not valid type. + * @throws { Error } If {-src-} has not valid type. + * @throws { Error } If {-cinterval-} has not valid type. + * @throws { Error } If options map {-o-} has not valid type. + * @throws { Error } If options map {-o-} has not known options. + * @throws { Error } If {-o.minSize-} has not valid type or is not an Integer. + * @throws { Error } If {-o.shrinkFactor-} has not valid type or is not an Integer. + * @namespace Tools + */ + +// function bufferReusingOnly( /* dst, src, cinterval */ ) +// { +// _.assert( 1 <= arguments.length && arguments.length <= 3 ); +// +// let o; +// if( arguments.length === 3 ) +// { +// o = Object.create( null ); +// o.dst = arguments[ 0 ]; +// o.src = arguments[ 1 ]; +// o.cinterval = arguments[ 2 ]; +// } +// else +// { +// o = _._bufferReusing_head.apply( this, arguments ); +// } +// _.assert( o.ins === undefined, 'Expects no argument {-ins-}' ); +// +// o.cinterval = cintervalClamp(); +// +// _.routine.options( bufferReusingOnly, o ); +// o.growFactor = 1; +// o.bufferFill = dstBufferFill; +// +// return _._bufferReusing( o ); +// +// /* */ +// +// function cintervalClamp() +// { +// let bufferLength = 0; +// if( o.dst ) +// bufferLength = o.dst && o.dst.length !== undefined ? o.dst.length : o.dst.byteLength; +// else +// bufferLength = o.src.length === undefined ? o.src.byteLength : o.src.length; +// +// if( o.cinterval === undefined ) +// o.cinterval = [ 0, bufferLength - 1 ]; +// else if( _.numberIs( o.cinterval ) ) +// o.cinterval = [ 0, o.cinterval ]; +// +// if( o.cinterval[ 0 ] < 0 ) +// o.cinterval[ 0 ] = 0; +// if( o.cinterval[ 1 ] < o.cinterval[ 0 ] - 1 ) +// o.cinterval[ 1 ] = o.cinterval[ 0 ] - 1; +// if( o.cinterval[ 1 ] > bufferLength - 1 ) +// o.cinterval[ 1 ] = bufferLength - 1; +// +// return o.cinterval; +// } +// +// /* */ +// +// function dstBufferFill( /* dstTyped, srcTyped, cinterval */ ) +// { +// let dstTyped = arguments[ 0 ]; +// let srcTyped = arguments[ 1 ]; +// let cinterval = arguments[ 2 ]; +// +// /* */ +// +// let left = Math.max( 0, cinterval[ 0 ] ); +// let right = Math.min( cinterval[ 1 ], srcTyped.length - 1 ); +// let i; +// for( i = left ; i < right + 1 ; i++ ) +// dstTyped[ i - left ] = srcTyped[ i ]; +// +// if( _.arrayLikeResizable( dstTyped ) && i - left < dstTyped.length ) +// for( ; i - left < dstTyped.length; i++ ) +// dstTyped[ i - left ] = undefined; +// } +// } +// +// bufferReusingOnly.defaults = +// { +// dst : null, +// src : null, +// cinterval : null, +// offsetting : 1, +// reusing : 1, +// shrinkFactor : 0, +// minSize : 64, +// }; + +function bufferReusingOnly_body( o ) +{ + _.assert( _.intIs( o.shrinkFactor ) && o.shrinkFactor >= 0 ); + + o.cinterval = cintervalClamp(); + o.growFactor = 1; + + /* */ + + let newBufferCreate = o.dst === null; + + _.assert( newBufferCreate || _.bufferAnyIs( o.dst ) || _.longIs( o.dst ) ); + + let dstElementSize; + if( newBufferCreate ) + o.dstElementSize = _._bufferElementSizeGet( o.src ); + else + o.dstElementSize = _._bufferElementSizeGet( o.dst ); + + o.dstSize = _._dstBufferSizeRecount( o ); + + let dstBuffer + if( o.reusing && !newBufferCreate ) + dstBuffer = _resultBufferReusedMaybe( o ); + else + dstBuffer = _resultBufferMake( o ); + + let dstTyped = _bufferTypedViewMake( dstBuffer ); + let srcTyped = _bufferTypedViewMake( o.src ); + let result = dstBufferFill( dstTyped, srcTyped, o.cinterval, o.ins ); + + return dstBuffer; + + /* */ + + function cintervalClamp() + { + let bufferLength = 0; + if( o.dst ) + bufferLength = o.dst && o.dst.length !== undefined ? o.dst.length : o.dst.byteLength; + else + bufferLength = o.src.length === undefined ? o.src.byteLength : o.src.length; + + if( o.cinterval === null ) + o.cinterval = [ 0, bufferLength - 1 ]; + else if( _.number.is( o.cinterval ) ) + o.cinterval = [ 0, o.cinterval ]; + + if( o.cinterval[ 0 ] < 0 ) + o.cinterval[ 0 ] = 0; + if( o.cinterval[ 1 ] < o.cinterval[ 0 ] - 1 ) + o.cinterval[ 1 ] = o.cinterval[ 0 ] - 1; + if( o.cinterval[ 1 ] > bufferLength - 1 ) + o.cinterval[ 1 ] = bufferLength - 1; + + return o.cinterval; + } + + /* */ + + function dstBufferFill( /* dstTyped, srcTyped, cinterval */ ) + { + let dstTyped = arguments[ 0 ]; + let srcTyped = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + + /* */ + + let left = Math.max( 0, cinterval[ 0 ] ); + let right = Math.min( cinterval[ 1 ], srcTyped.length - 1 ); + let i; + for( i = left ; i < right + 1 ; i++ ) + dstTyped[ i - left ] = srcTyped[ i ]; + + if( _.arrayLikeResizable( dstTyped ) && i - left < dstTyped.length ) + for( ; i - left < dstTyped.length; i++ ) + dstTyped[ i - left ] = undefined; + } +} + +bufferReusingOnly_body.defaults = +{ + dst : null, + src : null, + cinterval : null, + offsetting : 1, + reusing : 1, + shrinkFactor : 0, + minSize : 64, +}; + +// + +let bufferReusingOnly = _.routine.unite( bufferReusing3Arguments_head, bufferReusingOnly_body ); + +// + +/** + * Routine bufferReusingGrow() copies elements from source buffer {-src-} to grow destination buffer {-dst-}. + * All original source buffer will contains in destination buffer. + * + * Data in buffer {-dst-} overwrites. If {-dst-} container is not resizable and resulted length of destination + * container is not equal to original {-dst-} length, then routine makes new container of {-dst-} type. + * + * If buffer {-dst-} and {-src-} are the same buffer, then routine tries to change container {-src-} inplace and + * reuse original raw buffer. + * + * @example + * let buffer = new F64x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferReusingGrow( buffer, [ -1, 3 ], 7 ); + * console.log( got ); + * // log Float64Array[ 7, 1, 2, 3, 4, 7, 7, 7 ] + * console.log( got === buffer ); + * // log false + * console.log( got.buffer === buffer.buffer ); + * // log false + * + * @example + * let buffer = new F64x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferReusingGrow + * ({ + * dst : buffer, + * src : buffer, + * cinterval : [ 0, 3 ], + * ins : 7, + * minSize : 2, + * }); + * console.log( got ); + * // log Float64Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log true + * console.log( got.buffer === buffer.buffer ); + * // log true + * + * First parameter set : + * @param { BufferAny|Long|Null } dst - The destination container. + * @param { BufferAny|Long } src - The container from which makes a shallow copy. + * @param { Interval|Number } cinterval - The closed interval that defines the start index and the end index for removing elements. + * If {-cinterval-} is a Number, then it defines the index of removed element. + * If cinterval[ 0 ] < 0, then insertion element prepends to buffer. + * If cinterval[ 0 ] > 0, then cinterval[ 0 ] sets to 0. + * If cinterval[ 1 ] < src.length, then cinterval[ 1 ] sets to ( src.length - 1 ). + * If cinterval[ 1 ] > src.length, then insertion element appends to buffer. + * If cinterval[ 1 ] < cinterval[ 0 ], then routine change not source buffer. + * @param { * } ins - Insertion element with compatible type to destination buffer. + * + * Second parameter set : + * @param { Aux } o - Options map. + * @param { BufferAny|Long|Null } o.dst - The destination container. + * @param { BufferAny|Long } o.src - The container from which makes a shallow copy. + * @param { Interval|Number } o.cinterval - The closed interval that defines the start index and the end index for removing elements. + * The behavior same to first parameter set. + * @param { * } o.ins - Insertion element with compatible type to destination buffer. + * @param { BoolLike } o.reusing - Allows routine to reuse original raw buffer. Default is true. + * @param { BoolLike } o.offsetting - Allows routine to change offset in destination buffer {-o.dst-}. Default is true. + * @param { Number } o.minSize - Minimal size of resulted buffer. If resulted buffer size is less than {-o.minSize-}, routine makes + * new buffer. Default is 64. + * @param { Number } o.growFactor - If routine needs to make new container that is bigger than {-o.minSize-}, then routine multiplies + * {-o.growFactor-} on resulted buffer size. If {-o.growFactor-} <= 1, routine does not grow size of resulted buffer. Default is 2. + * + * @returns { BufferAny|Long } - If {-dst-} is provided, routine returns container of {-dst-} type. + * Otherwise, routine returns container of {-src-} type. + * If {-dst-} and {-src-} are the same container, routine tries to return original container. + * Routine tries to save original raw buffer. + * @function bufferReusingGrow + * @throws { Error } If arguments.length is less then one or more then four. + * @throws { Error } If {-dst-} has not valid type. + * @throws { Error } If {-src-} has not valid type. + * @throws { Error } If {-cinterval-} has not valid type. + * @throws { Error } If {-ins-} has not valid type. + * @throws { Error } If options map {-o-} has not valid type. + * @throws { Error } If options map {-o-} has not known options. + * @throws { Error } If {-o.minSize-} has not valid type or is not an Integer. + * @throws { Error } If {-o.growFactor-} has not valid type or is not an Integer. + * @namespace Tools + */ + +// function bufferReusingGrow( /* dst, src, cinterval, ins */ ) +// { +// let o = _._bufferReusing_head.apply( this, arguments ); +// +// let srcLength = o.src.byteLength; +// if( o.src.length !== undefined ) +// srcLength = o.src.length; +// o.cinterval = cintervalClamp(); +// +// _.routine.options( bufferReusingGrow, o ); +// +// o.bufferFill = dstBufferFill; +// +// return _._bufferReusing( o ); +// +// /* */ +// +// function cintervalClamp() +// { +// let bufferLength = 0; +// if( o.dst ) +// bufferLength = o.dst && o.dst.length !== undefined ? o.dst.length : o.dst.byteLength; +// else +// bufferLength = o.src.length === undefined ? o.src.byteLength : o.src.length; +// +// if( o.cinterval === undefined ) +// o.cinterval = [ 0, bufferLength - 1 ]; +// else if( _.numberIs( o.cinterval ) ) +// o.cinterval = [ 0, o.cinterval - 1 ]; +// +// if( o.cinterval[ 0 ] > 0 ) +// o.cinterval[ 0 ] = 0; +// if( o.cinterval[ 1 ] < o.cinterval[ 0 ] - 1 ) +// o.cinterval[ 1 ] = o.cinterval[ 0 ] - 1; +// if( o.cinterval[ 1 ] < bufferLength - 1 ) +// o.cinterval[ 1 ] = bufferLength - 1; +// +// return o.cinterval; +// } +// +// /* */ +// +// function dstBufferFill( /* dstTyped, srcTyped, cinterval, ins */ ) +// { +// let dstTyped = arguments[ 0 ]; +// let srcTyped = arguments[ 1 ]; +// let cinterval = arguments[ 2 ]; +// let ins = arguments[ 3 ]; +// +// /* */ +// +// let offset = Math.max( 0, -cinterval[ 0 ] ); +// let rightBound = Math.min( dstTyped.length, srcLength ); +// let length = dstTyped.length; +// +// if( dstTyped !== srcTyped ) +// { +// for( let i = offset ; i < rightBound + offset ; i++ ) +// dstTyped[ i ] = srcTyped[ i - offset ]; +// } +// +// for( let i = 0 ; i < offset ; i++ ) +// dstTyped[ i ] = o.ins; +// +// for( let i = offset + rightBound ; i < length ; i++ ) +// dstTyped[ i ] = o.ins; +// +// return dstTyped; +// +// } +// } +// +// bufferReusingGrow.defaults = +// { +// dst : null, +// src : null, +// cinterval : null, +// ins : null, +// offsetting : 1, +// reusing : 1, +// growFactor : 2, +// minSize : 64, +// }; + +function bufferReusingGrow_body( o ) +{ + _.assert( _.intIs( o.growFactor ) && o.growFactor >= 0 ); + + let srcLength = o.src.byteLength; + if( o.src.length !== undefined ) + srcLength = o.src.length; + o.cinterval = cintervalClamp(); + + /* */ + + let newBufferCreate = o.dst === null; + + _.assert( newBufferCreate || _.bufferAnyIs( o.dst ) || _.longIs( o.dst ) ); + + let dstElementSize; + if( newBufferCreate ) + o.dstElementSize = _._bufferElementSizeGet( o.src ); + else + o.dstElementSize = _._bufferElementSizeGet( o.dst ); + + o.dstSize = _._dstBufferSizeRecount( o ); + + let dstBuffer + if( o.reusing && !newBufferCreate ) + dstBuffer = _resultBufferReusedMaybe( o ); + else + dstBuffer = _resultBufferMake( o ); + + let dstTyped = _bufferTypedViewMake( dstBuffer ); + let srcTyped = _bufferTypedViewMake( o.src ); + let result = dstBufferFill( dstTyped, srcTyped, o.cinterval, o.ins ); + + return dstBuffer; + + /* */ + + function cintervalClamp() + { + let bufferLength = 0; + if( o.dst ) + bufferLength = o.dst && o.dst.length !== undefined ? o.dst.length : o.dst.byteLength; + else + bufferLength = o.src.length === undefined ? o.src.byteLength : o.src.length; + + if( o.cinterval === null ) + o.cinterval = [ 0, bufferLength - 1 ]; + else if( _.number.is( o.cinterval ) ) + o.cinterval = [ 0, o.cinterval - 1 ]; + + if( o.cinterval[ 0 ] > 0 ) + o.cinterval[ 0 ] = 0; + if( o.cinterval[ 1 ] < o.cinterval[ 0 ] - 1 ) + o.cinterval[ 1 ] = o.cinterval[ 0 ] - 1; + if( o.cinterval[ 1 ] < bufferLength - 1 ) + o.cinterval[ 1 ] = bufferLength - 1; + + return o.cinterval; + } + + /* */ + + function dstBufferFill( /* dstTyped, srcTyped, cinterval, ins */ ) + { + let dstTyped = arguments[ 0 ]; + let srcTyped = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + /* */ + + let offset = Math.max( 0, -cinterval[ 0 ] ); + let rightBound = Math.min( dstTyped.length, srcLength ); + let length = dstTyped.length; + + if( dstTyped !== srcTyped ) + { + for( let i = offset ; i < rightBound + offset ; i++ ) + dstTyped[ i ] = srcTyped[ i - offset ]; + } + + for( let i = 0 ; i < offset ; i++ ) + dstTyped[ i ] = o.ins; + + for( let i = offset + rightBound ; i < length ; i++ ) + dstTyped[ i ] = o.ins; + + return dstTyped; + + } +} + +bufferReusingGrow_body.defaults = +{ + dst : null, + src : null, + cinterval : null, + ins : null, + offsetting : 1, + reusing : 1, + growFactor : 2, + minSize : 64, +}; + +// + +let bufferReusingGrow = _.routine.unite( bufferReusing4Arguments_head, bufferReusingGrow_body ); + +// + +/** + * Routine bufferReusingRelength() copies elements from source buffer {-src-} to destination buffer {-dst-}. + * Routine applies any offsets from Interval {-cinterval-}. + * + * Data in buffer {-dst-} overwrites. If {-dst-} container is not resizable and resulted length of destination + * container is not equal to original {-dst-} length, then routine makes new container of {-dst-} type. + * + * If buffer {-dst-} and {-src-} are the same buffer, then routine tries to change container {-src-} inplace and + * reuse original raw buffer. + * + * @example + * let buffer = new F64x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferReusingRelength( buffer, [ -1, 3 ], 7 ); + * console.log( got ); + * // log Float64Array[ 7, 1, 2, 3, 4, 7, 7, 7 ] + * console.log( got === buffer ); + * // log false + * console.log( got.buffer === buffer.buffer ); + * // log false + * + * @example + * let buffer = new F64x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferReusingRelength + * ({ + * dst : buffer, + * src : buffer, + * cinterval : [ 0, 3 ], + * ins : 7, + * minSize : 2, + * }); + * console.log( got ); + * // log Float64Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log true + * console.log( got.buffer === buffer.buffer ); + * // log true + * + * First parameter set : + * @param { BufferAny|Long|Null } dst - The destination container. + * @param { BufferAny|Long } src - The container from which makes a shallow copy. + * @param { Interval|Number } cinterval - The closed interval that defines the start index and the end index for removing elements. + * If {-cinterval-} is a Number, then it defines the index of removed element. + * If cinterval[ 0 ] < 0, then insertion element prepends to buffer. + * If cinterval[ 0 ] > 0, then routine skips elements until index cinterval[ 0 ]. + * If cinterval[ 1 ] < src.length, routine shrinks buffer on right side. + * If cinterval[ 1 ] > src.length, then insertion element appends to buffer. + * If cinterval[ 1 ] < cinterval[ 0 ], then routine makes buffer with minimal size. + * @param { * } ins - Insertion element with compatible type to destination buffer. + * + * Second parameter set : + * @param { Aux } o - Options map. + * @param { BufferAny|Long|Null } o.dst - The destination container. + * @param { BufferAny|Long } o.src - The container from which makes a shallow copy. + * @param { Interval|Number } o.cinterval - The closed interval that defines the start index and the end index for removing elements. + * The behavior same to first parameter set. + * @param { * } o.ins - Insertion element with compatible type to destination buffer. + * @param { BoolLike } o.reusing - Allows routine to reuse original raw buffer. Default is true. + * @param { BoolLike } o.offsetting - Allows routine to change offset in destination buffer {-o.dst-}. Default is true. + * @param { Number } o.minSize - Minimal size of resulted buffer. If resulted buffer size is less than {-o.minSize-}, routine makes + * new buffer. Default is 64. + * @param { Number } o.growFactor - If routine needs to make new container that is bigger than {-o.minSize-}, then routine multiplies + * {-o.growFactor-} on resulted buffer size. If {-o.growFactor-} <= 1, routine does not grow size of resulted buffer. Default is 2. + * @param { Number } o.shrinkFactor - If resulted buffer in {-o.shrinkFactor-} times less than its raw buffer, than routine makes + * new buffer. If {-o.shrinkFactor-} <= 1, then routine not change original raw buffer. Default is 0. + * + * @returns { BufferAny|Long } - If {-dst-} is provided, routine returns container of {-dst-} type. + * Otherwise, routine returns container of {-src-} type. + * If {-dst-} and {-src-} are the same container, routine tries to return original container. + * Routine tries to save original raw buffer. + * @function bufferReusingRelength + * @throws { Error } If arguments.length is less then one or more then four. + * @throws { Error } If {-dst-} has not valid type. + * @throws { Error } If {-src-} has not valid type. + * @throws { Error } If {-cinterval-} has not valid type. + * @throws { Error } If {-ins-} has not valid type. + * @throws { Error } If options map {-o-} has not valid type. + * @throws { Error } If options map {-o-} has not known options. + * @throws { Error } If {-o.minSize-} has not valid type or is not an Integer. + * @throws { Error } If {-o.growFactor-} has not valid type or is not an Integer. + * @throws { Error } If {-o.shrinkFactor-} has not valid type or is not an Integer. + * @namespace Tools + */ + +// function bufferReusingRelength( /* dst, src, cinterval, ins */ ) +// { +// let o = _._bufferReusing_head.apply( this, arguments ); +// +// let left, right; +// let srcLength = o.src.byteLength; +// if( o.src.length !== undefined ) +// srcLength = o.src.length; +// o.cinterval = cintervalClamp(); +// +// _.routine.options( bufferReusingRelength, o ); +// +// o.bufferFill = dstBufferFill; +// +// return _._bufferReusing( o ); +// +// /* */ +// +// function cintervalClamp() +// { +// +// let bufferLength = 0; +// if( o.dst ) +// bufferLength = o.dst && o.dst.length !== undefined ? o.dst.length : o.dst.byteLength; +// else +// bufferLength = o.src.length === undefined ? o.src.byteLength : o.src.length; +// +// if( o.cinterval === undefined ) +// o.cinterval = [ 0, bufferLength - 1 ]; +// else if( _.numberIs( o.cinterval ) ) +// o.cinterval = [ 0, o.cinterval - 1 ]; +// +// left = o.cinterval[ 0 ]; +// right = o.cinterval[ 1 ]; +// +// if( o.cinterval[ 1 ] < o.cinterval[ 0 ] - 1 ) +// o.cinterval[ 1 ] = o.cinterval[ 0 ] - 1; +// +// return o.cinterval; +// } +// +// /* */ +// +// function dstBufferFill( /* dstTyped, srcTyped, cinterval, ins */ ) +// { +// let dstTyped = arguments[ 0 ]; +// let srcTyped = arguments[ 1 ]; +// let cinterval = arguments[ 2 ]; +// let ins = arguments[ 3 ]; +// +// /* */ +// +// let offset = left < 0 ? Math.max( 0, -left ) : 0; +// left = left < 0 ? 0 : left; +// let rightBound = Math.min( srcTyped.length, right - left + 1 ); +// rightBound = Math.min( rightBound, srcLength ); +// let length = dstTyped.length; +// +// let i; +// for( i = offset ; i < rightBound + offset && i - offset + left < srcTyped.length ; i++ ) +// dstTyped[ i ] = srcTyped[ i - offset + left ]; +// +// if( i > srcLength + offset - left ) +// i = srcLength + offset - left; +// +// for( ; i < length ; i++ ) +// dstTyped[ i ] = o.ins; +// +// for( let i = 0 ; i < offset ; i++ ) +// dstTyped[ i ] = o.ins; +// +// return dstTyped; +// +// } +// } +// +// bufferReusingRelength.defaults = +// { +// dst : null, +// src : null, +// cinterval : null, +// ins : null, +// offsetting : 1, +// reusing : 1, +// growFactor : 2, +// shrinkFactor : 0, +// minSize : 64, +// }; + +function bufferReusingRelength_body( o ) +{ + _.assert( _.intIs( o.growFactor ) && o.growFactor >= 0 ); + _.assert( _.intIs( o.shrinkFactor ) && o.shrinkFactor >= 0 ); + + let left, right; + let srcLength = o.src.byteLength; + if( o.src.length !== undefined ) + srcLength = o.src.length; + o.cinterval = cintervalClamp(); + + let newBufferCreate = o.dst === null; + + _.assert( newBufferCreate || _.bufferAnyIs( o.dst ) || _.longIs( o.dst ) ); + + let dstElementSize; + if( newBufferCreate ) + o.dstElementSize = _._bufferElementSizeGet( o.src ); + else + o.dstElementSize = _._bufferElementSizeGet( o.dst ); + + o.dstSize = _._dstBufferSizeRecount( o ); + + let dstBuffer + if( o.reusing && !newBufferCreate ) + dstBuffer = _resultBufferReusedMaybe( o ); + else + dstBuffer = _resultBufferMake( o ); + + let dstTyped = _bufferTypedViewMake( dstBuffer ); + let srcTyped = _bufferTypedViewMake( o.src ); + let result = dstBufferFill( dstTyped, srcTyped, o.cinterval, o.ins ); + + return dstBuffer; + + /* */ + + function cintervalClamp() + { + + let bufferLength = 0; + if( o.dst ) + bufferLength = o.dst && o.dst.length !== undefined ? o.dst.length : o.dst.byteLength; + else + bufferLength = o.src.length === undefined ? o.src.byteLength : o.src.length; + + if( o.cinterval === null ) + o.cinterval = [ 0, bufferLength - 1 ]; + else if( _.number.is( o.cinterval ) ) + o.cinterval = [ 0, o.cinterval - 1 ]; + + left = o.cinterval[ 0 ]; + right = o.cinterval[ 1 ]; + + if( o.cinterval[ 1 ] < o.cinterval[ 0 ] - 1 ) + o.cinterval[ 1 ] = o.cinterval[ 0 ] - 1; + + return o.cinterval; + } + + /* */ + + function dstBufferFill( /* dstTyped, srcTyped, cinterval, ins */ ) + { + let dstTyped = arguments[ 0 ]; + let srcTyped = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + /* */ + + let offset = left < 0 ? Math.max( 0, -left ) : 0; + left = left < 0 ? 0 : left; + let rightBound = Math.min( srcTyped.length, right - left + 1 ); + rightBound = Math.min( rightBound, srcLength ); + let length = dstTyped.length; + + let i; + for( i = offset ; i < rightBound + offset && i - offset + left < srcTyped.length ; i++ ) + dstTyped[ i ] = srcTyped[ i - offset + left ]; + + if( i > srcLength + offset - left ) + i = srcLength + offset - left; + + for( ; i < length ; i++ ) + dstTyped[ i ] = o.ins; + + for( let i = 0 ; i < offset ; i++ ) + dstTyped[ i ] = o.ins; + + return dstTyped; + + } +} + +bufferReusingRelength_body.defaults = +{ + dst : null, + src : null, + cinterval : null, + ins : null, + offsetting : 1, + reusing : 1, + growFactor : 2, + shrinkFactor : 0, + minSize : 64, +}; + +// + +let bufferReusingRelength = _.routine.unite( bufferReusing4Arguments_head, bufferReusingRelength_body ); + +// + +/** + * Routine bufferReusingResize() resizes raw buffer of source buffer {-src-} in interval {-cinterval-}. + * + * If destination buffer {-dst-} is provided, then routine copies data to the buffer byte per byte. Data in + * buffer {-dst-} overwrites. If {-dst-} container is not resizable and resulted length of destination container + * is not equal to original {-dst-} length, then routine makes new container of {-dst-} type. + * + * If buffer {-dst-} and {-src-} are the same buffer, then routine tries to change container {-src-} inplace and + * reuse original raw buffer. + * + * @example + * let buffer = new F64x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferReusingResize( buffer, buffer, [ 8, 32 ] ); + * console.log( got ); + * // log Float64Array[ 2, 3, 4 ] + * console.log( got === buffer ); + * // log false + * console.log( got.buffer === buffer.buffer ); + * // log true + * + * @example + * let buffer = new F64x( [ 1, 2, 3, 4 ] ); + * let got = _.bufferReusingResize + * ({ + * dst : buffer, + * src : buffer, + * cinterval : [ 0, 32 ], + * ins : 7, + * minSize : 2, + * }); + * console.log( got ); + * // log Float64Array[ 1, 2, 3, 4 ] + * console.log( got === buffer ); + * // log true + * console.log( got.buffer === buffer.buffer ); + * // log true + * + * First parameter set : + * @param { BufferAny|Long|Null } dst - The destination container. + * @param { BufferAny|Long } src - The container from which makes a shallow copy. + * @param { Interval|Number } cinterval - The closed interval that defines the start index and the end index for removing elements. + * If {-cinterval-} is a Number, then it defines the index of removed element. + * If cinterval[ 0 ] < 0, then routine resizes buffer left. + * If cinterval[ 0 ] > 0, then routine skips bytes until index cinterval[ 0 ]. + * If cinterval[ 1 ] < src size, routine shrinks buffer on right side. + * If cinterval[ 1 ] > src size, then routine resizes buffer right. + * If cinterval[ 1 ] < cinterval[ 0 ], then routine makes buffer with minimal size. + * + * Second parameter set : + * @param { Aux } o - Options map. + * @param { BufferAny|Long|Null } o.dst - The destination container. + * @param { BufferAny|Long } o.src - The container from which makes a shallow copy. + * @param { Interval|Number } o.cinterval - The closed interval that defines the start index and the end index for removing elements. + * The behavior same to first parameter set. + * @param { BoolLike } o.reusing - Allows routine to reuse original raw buffer. Default is true. + * @param { BoolLike } o.offsetting - Allows routine to change offset in destination buffer {-o.dst-}. Default is true. + * @param { Number } o.minSize - Minimal size of resulted buffer. If resulted buffer size is less than {-o.minSize-}, routine makes + * new buffer. Default is 64. + * @param { Number } o.growFactor - If routine needs to make new container that is bigger than {-o.minSize-}, then routine multiplies + * {-o.growFactor-} on resulted buffer size. If {-o.growFactor-} <= 1, routine does not grow size of resulted buffer. Default is 2. + * @param { Number } o.shrinkFactor - If resulted buffer in {-o.shrinkFactor-} times less than its raw buffer, than routine makes + * new buffer. If {-o.shrinkFactor-} <= 1, then routine not change original raw buffer. Default is 0. + * + * @returns { BufferAny|Long } - If {-dst-} is provided, routine returns container of {-dst-} type. + * Otherwise, routine returns container of {-src-} type. + * If {-dst-} and {-src-} are the same container, routine tries to return original container. + * Routine tries to save original raw buffer. + * @function bufferReusingResize + * @throws { Error } If arguments.length is less then one or more then four. + * @throws { Error } If {-dst-} has not valid type. + * @throws { Error } If {-src-} has not valid type. + * @throws { Error } If {-cinterval-} has not valid type. + * @throws { Error } If options map {-o-} has not valid type. + * @throws { Error } If options map {-o-} has not known options. + * @throws { Error } If {-o.minSize-} has not valid type or is not an Integer. + * @throws { Error } If {-o.growFactor-} has not valid type or is not an Integer. + * @throws { Error } If {-o.shrinkFactor-} has not valid type or is not an Integer. + * @namespace Tools + */ + +// function bufferReusingResize( /* dst, src, cinterval */ ) +// { +// _.assert( 1 <= arguments.length && arguments.length <= 3 ); +// +// let o; +// if( arguments.length === 3 ) +// { +// o = Object.create( null ); +// o.dst = arguments[ 0 ]; +// o.src = arguments[ 1 ]; +// o.cinterval = arguments[ 2 ]; +// } +// else +// { +// o = _._bufferReusing_head.apply( this, arguments ); +// } +// +// _.assert( _.bufferAnyIs( o.src ), 'Expects buffer {-src-}' ); +// +// let left, right; +// o.cinterval = cintervalClamp(); +// +// _.routine.options( bufferReusingResize, o ); +// +// o.bufferSizeCount = bufferSizeCount; +// o.bufferFill = dstBufferFill; +// +// return _._bufferReusing( o ); +// +// /* */ +// +// function cintervalClamp() +// { +// let bufferLength = 0; +// if( o.dst ) +// bufferLength = o.dst && o.dst.length !== undefined ? o.dst.length : o.dst.byteLength; +// else +// bufferLength = o.src.length === undefined ? o.src.byteLength : o.src.length; +// +// if( o.cinterval === undefined ) +// o.cinterval = [ 0, bufferLength - 1 ]; +// else if( _.numberIs( o.cinterval ) ) +// o.cinterval = [ 0, o.cinterval - 1 ]; +// +// left = o.cinterval[ 0 ]; +// right = o.cinterval[ 1 ]; +// +// if( o.cinterval[ 1 ] < o.cinterval[ 0 ] - 1 ) +// o.cinterval[ 1 ] = o.cinterval[ 0 ] - 1; +// +// return o.cinterval; +// } +// +// /* */ +// +// function bufferSizeCount( cinterval, elementSize ) +// { +// return cinterval[ 1 ] - cinterval[ 0 ] + 1; +// } +// +// /* */ +// +// function dstBufferFill( /* dstTyped, srcTyped, cinterval, ins */ ) +// { +// let dstTyped = arguments[ 0 ]; +// let srcTyped = arguments[ 1 ]; +// let cinterval = arguments[ 2 ]; +// let ins = arguments[ 3 ]; +// +// /* */ +// +// if( srcTyped === dstTyped ) +// return dstTyped; +// +// if( _.bufferAnyIs( dstTyped ) ) +// dstTyped = _.bufferBytesFrom( dstTyped.buffer ? dstTyped.buffer : dstTyped ); +// +// let srcBytesView = srcTyped; +// if( _.bufferAnyIs( srcTyped ) ) +// srcBytesView = _.bufferBytesFrom( srcTyped.buffer ? srcTyped.buffer : srcTyped ); +// +// let offset = srcTyped.byteOffset ? srcTyped.byteOffset : 0; +// offset += left; +// +// let length = right - left + 1; +// if( dstTyped.buffer === srcTyped.buffer ) +// { +// dstTyped = new dstTyped.constructor( dstTyped.buffer, offset, length ); +// } +// else +// { +// for( let i = 0; i < dstTyped.length && i < length ; i++ ) +// dstTyped[ i ] = srcBytesView[ offset + i ] ? srcBytesView[ offset + i ] : 0; +// } +// +// return dstTyped; +// +// } +// } +// +// bufferReusingResize.defaults = +// { +// dst : null, +// src : null, +// cinterval : null, +// offsetting : 1, +// reusing : 1, +// growFactor : 2, +// shrinkFactor : 0, +// minSize : 64, +// }; + + +function bufferReusingResize_body( o ) +{ + _.assert( _.intIs( o.shrinkFactor ) && o.shrinkFactor >= 0 ); + _.assert( _.intIs( o.growFactor ) && o.growFactor >= 0 ); + _.assert( _.bufferAnyIs( o.src ), 'Expects buffer {-src-}' ); + + let left, right; + o.cinterval = cintervalClamp(); + + let newBufferCreate = o.dst === null; + + _.assert( newBufferCreate || _.bufferAnyIs( o.dst ) || _.longIs( o.dst ) ); + + let dstElementSize; + if( newBufferCreate ) + o.dstElementSize = _._bufferElementSizeGet( o.src ); + else + o.dstElementSize = _._bufferElementSizeGet( o.dst ); + + o.dstSize = bufferSizeCount( o.cinterval ); + o.dstSize = _._dstBufferSizeRecount( o ); + + let dstBuffer + if( o.reusing && !newBufferCreate ) + dstBuffer = _resultBufferReusedMaybe( o ); + else + dstBuffer = _resultBufferMake( o ); + + let dstTyped = _bufferTypedViewMake( dstBuffer ); + let srcTyped = _bufferTypedViewMake( o.src ); + let result = dstBufferFill( dstTyped, srcTyped, o.cinterval, o.ins ); + + return dstBuffer; + + /* */ + + function cintervalClamp() + { + let bufferLength = 0; + if( o.dst ) + bufferLength = o.dst && o.dst.length !== undefined ? o.dst.length : o.dst.byteLength; + else + bufferLength = o.src.length === undefined ? o.src.byteLength : o.src.length; + + if( o.cinterval === null ) + o.cinterval = [ 0, bufferLength - 1 ]; + else if( _.number.is( o.cinterval ) ) + o.cinterval = [ 0, o.cinterval - 1 ]; + + left = o.cinterval[ 0 ]; + right = o.cinterval[ 1 ]; + + if( o.cinterval[ 1 ] < o.cinterval[ 0 ] - 1 ) + o.cinterval[ 1 ] = o.cinterval[ 0 ] - 1; + + return o.cinterval; + } + + /* */ + + function bufferSizeCount( cinterval ) + { + return cinterval[ 1 ] - cinterval[ 0 ] + 1; + } + + /* */ + + function dstBufferFill( /* dstTyped, srcTyped, cinterval, ins */ ) + { + let dstTyped = arguments[ 0 ]; + let srcTyped = arguments[ 1 ]; + let cinterval = arguments[ 2 ]; + let ins = arguments[ 3 ]; + + /* */ + + if( srcTyped === dstTyped ) + return dstTyped; + + if( _.bufferAnyIs( dstTyped ) ) + dstTyped = _.bufferBytesFrom( dstTyped.buffer ? dstTyped.buffer : dstTyped ); + + let srcBytesView = srcTyped; + if( _.bufferAnyIs( srcTyped ) ) + srcBytesView = _.bufferBytesFrom( srcTyped.buffer ? srcTyped.buffer : srcTyped ); + + let offset = srcTyped.byteOffset ? srcTyped.byteOffset : 0; + offset += left; + + let length = right - left + 1; + if( dstTyped.buffer === srcTyped.buffer ) + { + dstTyped = new dstTyped.constructor( dstTyped.buffer, offset, length ); + } + else + { + for( let i = 0; i < dstTyped.length && i < length ; i++ ) + dstTyped[ i ] = srcBytesView[ offset + i ] ? srcBytesView[ offset + i ] : 0; + } + + return dstTyped; + + } +} + +bufferReusingResize_body.defaults = +{ + dst : null, + src : null, + cinterval : null, + offsetting : 1, + reusing : 1, + growFactor : 2, + shrinkFactor : 0, + minSize : 64, +}; + +// + +let bufferReusingResize = _.routine.unite( bufferReusing3Arguments_head, bufferReusingResize_body ); + +// + +/** + * The routine bufferBytesGet() converts source buffer {-src-} and returns a new instance of buffer U8x ( array of 8-bit unsigned integers ). + * + * @param { BufferRaw|BufferNode|BufferTyped|BufferView|String } src - Instance of any buffer or string. + * + * @example + * let src = new BufferRaw( 5 ); + * _.bufferBytesGet(src); + * // returns [ 0, 0, 0, 0, 0, ] + * + * @example + * let src = BufferNode.alloc( 5, 'a' ); + * _.bufferBytesGet(src); + * // returns [ 97, 97, 97, 97, 97 ] + * + * @example + * let src = new I32x( [ 5, 6, 7 ] ); + * _.bufferBytesGet(src); + * // returns [ 5, 0, 6, 0, 7, 0 ] + * + * @example + * let src = 'string'; + * _.bufferBytesGet(src); + * // returns [ 115, 116, 114, 105, 110, 103 ] + * + * @returns { TypedArray } Returns a new instance of U8x constructor. + * @function bufferBytesGet + * @throws { Error } If arguments.length is less or more than 1. + * @throws { Error } If {-src-} is not a instance of any buffer or string. + * @memberof wTools + */ + +function bufferBytesGet( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( src instanceof BufferRaw || src instanceof BufferRawShared ) + { + return new U8x( src ); + } + else if( typeof BufferNode !== 'undefined' && src instanceof BufferNode ) + { + return new U8x( src.buffer, src.byteOffset, src.byteLength ); + } + else if( _.bufferTypedIs( src ) ) + { + return new U8x( src.buffer, src.byteOffset, src.byteLength ); + } + else if( _.bufferViewIs( src ) ) + { + return new U8x( src.buffer, src.byteOffset, src.byteLength ); + } + else if( _.strIs( src ) ) + { + if( _global_.BufferNode ) + return new U8x( _.bufferRawFrom( BufferNode.from( src, 'utf8' ) ) ); + else + return new U8x( _.encode.utf8ToBuffer( src ) ); /* Dmytro : maybe it should have some improvement, base module should not use higher level modules */ + } + else _.assert( 0, 'wrong argument' ); + +} + +// + +/** + * The bufferRetype() routine converts and returns a new instance of (bufferType) constructor. + * + * @param { typedArray } src - The typed array. + * @param { typedArray } bufferType - The type of typed array. + * + * @example + * let view1 = new I8x( [ 1, 2, 3, 4, 5, 6 ] ); + * _.bufferRetype(view1, I16x); + * // returns [ 513, 1027, 1541 ] + * + * @example + * let view2 = new I16x( [ 513, 1027, 1541 ] ); + * _.bufferRetype(view2, I8x); + * // returns [ 1, 2, 3, 4, 5, 6 ] + * + * @returns { typedArray } Returns a new instance of (bufferType) constructor. + * @function bufferRetype + * @throws { Error } Will throw an Error if {-srcMap-} is not a typed array object. + * @throws { Error } Will throw an Error if (bufferType) is not a type of the typed array. + * @namespace Tools + */ + +function bufferRetype( src, bufferType ) +{ + + _.assert( arguments.length === 2, 'Expects source buffer {-src-} and constructor of buffer {-bufferTyped-}' ); + _.assert( _.bufferTypedIs( src ) ); + _.assert( _.constructorIsBuffer( bufferType ) ); + + let o = src.byteOffset; + let l = Math.floor( src.byteLength / bufferType.BYTES_PER_ELEMENT ); + let result = new bufferType( src.buffer, o, l ); + + return result; +} + +// + +function bufferJoin() +{ + + if( arguments.length < 2 ) + { + _.assert( _.bufferAnyIs( arguments[ 0 ] ) || !arguments[ 0 ] ); + return arguments[ 0 ] || null; + } + + let srcs = []; + let size = 0; + let firstSrc; + for( let s = 0 ; s < arguments.length ; s++ ) + { + let src = arguments[ s ]; + + if( src === null ) + continue; + + if( !firstSrc ) + firstSrc = src; + + if( _.bufferRawIs( src ) ) + { + srcs.push( new U8x( src ) ); + } + else if( src instanceof U8x ) + { + srcs.push( src ); + } + else + { + srcs.push( new U8x( src.buffer, src.byteOffset, src.byteLength ) ); + } + + _.assert( src.byteLength >= 0, 'Expects buffers, but got', _.entity.strType( src ) ); + + size += src.byteLength; + } + + if( srcs.length === 0 ) + return null; + + /* */ + + let resultBuffer = new BufferRaw( size ); + let result = _.bufferRawIs( firstSrc ) ? resultBuffer : new firstSrc.constructor( resultBuffer ); + let resultBytes = result.constructor === U8x ? result : new U8x( resultBuffer ); + + /* */ + + let offset = 0; + for( let s = 0 ; s < srcs.length ; s++ ) + { + let src = srcs[ s ]; + if( resultBytes.set ) + { + resultBytes.set( src, offset ); + } + else + { + for( let i = 0 ; i < src.length ; i++ ) + resultBytes[ offset+i ] = src[ i ]; + } + offset += src.byteLength; + } + + return result; +} + +// + +function bufferMove( dst, src ) +{ + + if( arguments.length === 2 ) + { + + _.assert( _.longIs( dst ) ); + _.assert( _.longIs( src ) ); + + if( dst.length !== src.length ) + throw _.err( '_.bufferMove :', '"dst" and "src" must have same length' ); + + if( dst.set && ( src instanceof U64x || src instanceof I64x ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + dst[ s ] = Number( src[ s ] ); + } + else if( dst.set && ( dst instanceof U64x || dst instanceof I64x ) ) + { + dst.set( _.bigInt.s.from( src ) ); + } + else if( dst.set ) + { + dst.set( src ); + } + else + { + for( let s = 0 ; s < src.length ; s++ ) + dst[ s ] = src[ s ]; + } + + } + else if( arguments.length === 1 ) + { + + let options = arguments[ 0 ]; + _.map.assertHasOnly( options, bufferMove.defaults ); + + src = options.src; + dst = options.dst; + + if( _.bufferRawIs( dst ) ) + { + dst = new U8x( dst ); + if( _.bufferTypedIs( src ) && !( src instanceof U8x ) ) + src = new U8x( src.buffer, src.byteOffset, src.byteLength ); + } + + _.assert( _.longIs( dst ) ); + _.assert( _.longIs( src ) ); + + options.dstOffset = options.dstOffset || 0; + + if( dst.set && ( src instanceof U64x || src instanceof I64x ) ) + { + for( let s = 0, d = options.dstOffset ; s < src.length ; s++, d++ ) + dst[ d ] = Number( src[ s ] ); + } + else if( dst.set && ( dst instanceof U64x || dst instanceof I64x ) ) + { + dst.set( _.bigInt.s.from( src ), options.dstOffset ); + } + else if( dst.set ) + { + dst.set( src, options.dstOffset ); + } + else + { + for( let s = 0, d = options.dstOffset ; s < src.length ; s++, d++ ) + dst[ d ] = src[ s ]; + } + + } + else _.assert( 0, 'unexpected' ); + + return dst; +} + +bufferMove.defaults = +{ + dst : null, + src : null, + dstOffset : null, +} + +// + +function bufferToStr( src ) +{ + let result = ''; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.bufferAnyIs( src ) ); + + if( typeof BufferNode !== 'undefined' ) + src = _.bufferNodeFrom( src ); + else if( src instanceof BufferRaw ) + src = new U8x( src, 0, src.byteLength ); + + if( _.bufferNodeIs( src ) ) + return src.toString( 'utf8' ); + + try + { + result = String.fromCharCode.apply( null, src ); + } + catch( e ) + { + for( let i = 0 ; i < src.byteLength ; i++ ) + { + result += String.fromCharCode( src[ i ] ); + } + } + + return result; +} + +// + +function bufferToDom( xmlBuffer ) +{ + let result; + + if( typeof DOMParser !== 'undefined' && DOMParser.prototype.parseFromBuffer ) + { + + let parser = new DOMParser(); + result = parser.parseFromBuffer( xmlBuffer, xmlBuffer.byteLength, 'text/xml' ); + throw _.err( 'not tested' ); + + } + else + { + + let xmlStr = _.bufferToStr( xmlBuffer ); + result = this.strToDom( xmlStr ); + + } + + return result; +} + +// + +function bufferLeft( src, ins ) +{ + + if( !_.bufferRawIs( src ) ) + src = _.bufferBytesGet( src ); + + if( !_.bufferRawIs( ins ) ) + ins = _.bufferBytesGet( ins ); + + _.assert( _.routine.is( src.indexOf ) ); + _.assert( _.routine.is( ins.indexOf ) ); + + let index = src.indexOf( ins[ 0 ] ); + while( index !== -1 ) + { + let i = 0; + for( ; i < ins.length ; i++ ) + if( src[ index + i ] !== ins[ i ] ) + break; + + if( i === ins.length ) + return index; + + index += 1; + index = src.indexOf( ins[ 0 ], index ); + + } + + return index; +} + +// + +function bufferRight( src, ins ) +{ + + if( !_.bufferRawIs( src ) ) + src = _.bufferBytesGet( src ); + + if( !_.bufferRawIs( ins ) ) + ins = _.bufferBytesGet( ins ); + + _.assert( _.routine.is( src.indexOf ) ); + _.assert( _.routine.is( ins.indexOf ) ); + + let index = src.lastIndexOf( ins[ 0 ] ); + while( index !== -1 ) + { + + let i = 0; + for( ; i < ins.length; i++ ) + if( src[ index + i ] !== ins[ i ] ) + break; + + if( i === ins.length ) + return index; + + index -= 1; + index = src.lastIndexOf( ins[ 0 ], index ); + + } + + return index; +} + +// + +function bufferSplit( src, del ) +{ + + if( !_.bufferRawIs( src ) ) + src = _.bufferBytesGet( src ); + + if( !_.bufferRawIs( del ) ) + del = _.bufferBytesGet( del ); + + _.assert( _.routine.is( src.indexOf ) ); + _.assert( _.routine.is( del.indexOf ) ); + + let result = []; + let begin = 0; + let index = src.indexOf( del[ 0 ] ); + while( index !== -1 ) + { + + for( let i = 0 ; i < del.length ; i++ ) + if( src[ index+i ] !== del[ i ] ) + break; + + if( i === del.length ) + { + result.push( src.slice( begin, index ) ); + index += i; + begin = index; + } + else + { + index += 1; + } + + index = src.indexOf( del[ 0 ], index ); + + } + + if( begin === 0 ) + result.push( src ); + else + result.push( src.slice( begin, src.length ) ); + + return result; +} + +// + +function bufferCutOffLeft( src, del ) +{ + + if( !_.bufferRawIs( src ) ) + src = _.bufferBytesGet( src ); + + if( !_.bufferRawIs( del ) ) + del = _.bufferBytesGet( del ); + + _.assert( _.routine.is( src.indexOf ) ); + _.assert( _.routine.is( del.indexOf ) ); + + let result = []; + let index = src.indexOf( del[ 0 ] ); + while( index !== -1 ) + { + + for( let i = 0 ; i < del.length ; i++ ) + if( src[ index+i ] !== del[ i ] ) + break; + + if( i === del.length ) + { + result.push( src.slice( 0, index ) ); + result.push( src.slice( index, index+i ) ); + result.push( src.slice( index+i, src.length ) ); + return result; + } + else + { + index += 1; + } + + index = src.indexOf( del[ 0 ], index ); + + } + + result.push( null ); + result.push( null ); + result.push( src ); + + return result; +} + +// + +function bufferIsolate_head( routine, args ) +{ + let o; + + if( args.length > 1 ) + { + if( args.length === 3 ) + o = { src : args[ 0 ], delimeter : args[ 1 ], times : args[ 2 ] }; + else if( args.length === 2 ) + o = { src : args[ 0 ], delimeter : args[ 1 ] }; + else + o = { src : args[ 0 ] }; + } + else + { + o = args[ 0 ]; + _.assert( args.length === 1, 'Expects single argument' ); + } + + _.routine.options( routine, o ); + _.assert( 1 <= args.length && args.length <= 3 ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.bufferAnyIs( o.src ) || _.strIs( o.src ) ); + _.assert( _.bufferAnyIs( o.delimeter ) || _.strIs( o.delimeter ) ); + _.assert( _.number.is( o.times ) ); + + return o; +} + +// + +function bufferIsolate_body( o ) +{ + _.routine.assertOptions( bufferIsolate_body, arguments ); + + let src = o.src; + if( _.strIs( o.src ) ) + src = o.src = _.bufferBytesGet( o.src ); + if( !_.bufferTypedIs( o.src ) ) + src = _.bufferBytesGet( o.src ); + + let delimeter = o.delimeter; + if( _.strIs( o.delimeter ) || !_.bufferTypedIs( o.delimeter ) ) + delimeter = _.bufferBytesGet( o.delimeter ); + + delimeter = _.bufferRetype( delimeter, src.constructor ); + + _.assert( _.routine.is( src.indexOf ) ); + _.assert( _.routine.is( delimeter.indexOf ) ); + + let result = []; + let times = o.times; + let index = o.left ? 0 : src.length; + let more = o.left ? bufferLeft : bufferRight; + + /* */ + + while( times > 0 ) + { + index = more( index ); + + if( index === -1 ) + break; + + times -= 1; + + if( times === 0 ) + { + if( o.src.constructor === src.constructor ) + { + let del = delimeter; + result.push( o.src.subarray( 0, index ) ); + result.push( new o.src.constructor( del.buffer, del.byteOffset, del.byteLength / ( o.src.BYTES_PER_ELEMENT || 1 ) ) ); + result.push( o.src.subarray( index + delimeter.length ) ); + } + else + { + if( o.src.constructor === BufferRaw ) + { + result.push( o.src.slice( 0, index ) ); + result.push( delimeter.buffer.slice( delimeter.byteOffset, delimeter.byteOffset + delimeter.byteLength ) ); + result.push( o.src.slice( index + delimeter.length, src.byteLength ) ); + } + else + { + let del = delimeter; + result.push( new o.src.constructor( o.src.buffer, o.src.byteOffset, index ) ); + result.push( new o.src.constructor( del.buffer, del.byteOffset, del.byteLength / ( o.src.BYTES_PER_ELEMENT || 1 ) ) ); + let secondOffset = src.byteOffset + index * ( o.src.BYTES_PER_ELEMENT || 1 ) + delimeter.length; + result.push( new o.src.constructor( o.src.buffer, secondOffset, o.src.byteOffset + src.byteLength - secondOffset ) ); + } + } + return result; + } + + /* */ + + if( o.left ) + { + index = index + 1; + if( index >= src.length ) + break; + } + else + { + index = index - 1; + if( index <= 0 ) + break; + } + + } + + /* */ + + if( !result.length ) + { + if( o.times === 0 ) + return everything( !o.left ); + else if( times === o.times ) + return everything( o.left ^ o.none ); + else + return everything( o.left ); + } + + return result; + + /* */ + + function everything( side ) + { + let empty = new U8x( 0 ).buffer; + return ( side ) ? [ o.src, undefined, new o.src.constructor( empty ) ] : [ new o.src.constructor( empty ), undefined, o.src ]; + } + + /* */ + + function bufferLeft( index ) + { + index = src.indexOf( delimeter[ 0 ], index ); + while( index !== -1 ) + { + let i = 0; + for( ; i < delimeter.length; i++ ) + if( src[ index + i ] !== delimeter[ i ] ) + break; + + if( i === delimeter.length ) + return index; + + index += 1; + index = src.indexOf( delimeter[ 0 ], index ); + } + return index; + } + + /* */ + + function bufferRight( index ) + { + index = src.lastIndexOf( delimeter[ 0 ], index ); + while( index !== -1 ) + { + let i = 0; + for( ; i < delimeter.length; i++ ) + if( src[ index + i ] !== delimeter[ i ] ) + break; + + if( i === delimeter.length ) + return index; + + index -= 1; + index = src.lastIndexOf( delimeter[ 0 ], index ); + } + return index; + } +} + +bufferIsolate_body.defaults = +{ + src : null, + delimeter : ' ', + left : 1, + times : 1, + none : 1, +}; + +// + +let bufferIsolate = _.routine.unite( bufferIsolate_head, bufferIsolate_body ); + +// + +function bufferIsolateLeftOrNone_body( o ) +{ + o.left = 1; + o.none = 1; + let result = _.bufferIsolate.body( o ); + return result; +} + +bufferIsolateLeftOrNone_body.defaults = +{ + src : null, + delimeter : ' ', + times : 1, +}; + +let bufferIsolateLeftOrNone = _.routine.unite( bufferIsolate_head, bufferIsolateLeftOrNone_body ); + +// + +function bufferIsolateLeftOrAll_body( o ) +{ + o.left = 1; + o.none = 0; + let result = _.bufferIsolate.body( o ); + return result; +} + +bufferIsolateLeftOrAll_body.defaults = +{ + src : null, + delimeter : ' ', + times : 1, +}; + +let bufferIsolateLeftOrAll = _.routine.unite( bufferIsolate_head, bufferIsolateLeftOrAll_body ); + +// + +function bufferIsolateRightOrNone_body( o ) +{ + o.left = 0; + o.none = 1; + let result = _.bufferIsolate.body( o ); + return result; +} + +bufferIsolateRightOrNone_body.defaults = +{ + src : null, + delimeter : ' ', + times : 1, +}; + +let bufferIsolateRightOrNone = _.routine.unite( bufferIsolate_head, bufferIsolateRightOrNone_body ); + +// + +function bufferIsolateRightOrAll_body( o ) +{ + o.left = 0; + o.none = 0; + let result = _.bufferIsolate.body( o ); + return result; +} + +bufferIsolateRightOrAll_body.defaults = +{ + src : null, + delimeter : ' ', + times : 1, +}; + +let bufferIsolateRightOrAll = _.routine.unite( bufferIsolate_head, bufferIsolateRightOrAll_body ); + +// -- +// declaration +// -- + +let BufferExtension = +{ +} + +Object.assign( _.buffer, BufferExtension ); + +// + +let ToolsExtension = +{ + + bufferRelen, /* xxx : investigate */ + + bufferBut_, + bufferOnly_, + bufferGrow_, + bufferRelength_, + bufferResize_, + + // + + // _bufferReusing_head, + // _bufferReusing, + bufferReusing4Arguments_head, + bufferReusing3Arguments_head, + _bufferElementSizeGet, + _dstBufferSizeRecount, + _bufferTypedViewMake, + _resultBufferReusedMaybe, + _resultBufferMake, + bufferReusingBut, + bufferReusingOnly, + bufferReusingGrow, + bufferReusingRelength, + bufferReusingResize, + + // + + bufferBytesGet, + bufferRetype, + + bufferJoin, /* qqq for Dmytro : look, analyze and cover _.longJoin */ + + bufferMove, + bufferToStr, + bufferToDom, /* qqq for Dmytro : move out to DomTools */ + + bufferLeft, + bufferRight, + bufferSplit, + bufferCutOffLeft, + + bufferIsolate, + bufferIsolateLeftOrNone, + bufferIsolateLeftOrAll, + bufferIsolateRightOrNone, + bufferIsolateRightOrAll, + + // buffersSerialize, /* deprecated */ + // buffersDeserialize, /* deprecated */ + + // to replace + + /* + | routine | makes new dst container | saves dst container | + | ----------------- | ---------------------------------------------- | ---------------------------------------------------------- | + | bufferBut_ | _.bufferBut_( src, range ) | _.bufferBut_( src ) | + | | if src is not resizable and change length | _.bufferBut_( dst, dst ) | + | | _.bufferBut_( null, src, range ) | _.bufferBut_( dst, dst, range ) if dst is resizable | + | | _.bufferBut_( dst, src, range ) | or dst not change length | + | | if dst not resizable and change length | _.bufferBut_( dst, src, range ) if dst is resizable | + | | | or dst not change length | + | ----------------- | ---------------------------------------------- | ---------------------------------------------------------- | + | bufferOnly__ | _.bufferOnly__( src, range ) | _.bufferOnly__( src ) | + | | if src is not resizable and change length | _.bufferOnly__( dst, dst ) | + | | _.bufferOnly__( null, src, range ) | _.bufferOnly__( dst, dst, range ) if dst is resizable | + | | _.bufferOnly__( dst, src, range ) | or dst not change length | + | | if dst not resizable and change length | _.bufferOnly__( dst, src, range ) if dst is resizable | + | | | or dst not change length | + | ----------------- | ---------------------------------------------- | ---------------------------------------------------------- | + | bufferGrow_ | _.bufferGrow_( src, range ) | _.bufferGrow_( src ) | + | | if src is not resizable and change length | _.bufferGrow_( dst, dst ) | + | | _.bufferGrow_( null, src, range ) | _.bufferGrow_( dst, dst, range ) if dst is resizable | + | | _.bufferGrow_( dst, src, range ) | or dst not change length | + | | if dst not resizable and change length | _.bufferGrow_( dst, src, range ) if dst is resizable | + | | | or dst not change length | + | ----------------- | ---------------------------------------------- | ---------------------------------------------------------- | + | bufferRelength_ | _.bufferRelength_( src, range ) | _.bufferRelength_( src ) | + | | if src is not resizable and change length | _.bufferRelength_( dst, dst ) | + | | _.bufferRelength_( null, src, range ) | _.bufferRelength_( dst, dst, range ) if dst is resizable | + | | _.bufferRelength_( dst, src, range ) | or dst not change length | + | | if dst not resizable and change length | _.bufferRelength_( dst, src, range ) if dst is resizable | + | | | or dst not change length | + | ----------------- | ---------------------------------------------- | ---------------------------------------------------------- | + | bufferResize_ | _.bufferResize_( null, src, size ) | _.bufferResize_( src, size ) | + | bufferResize_ | every time | if src is not BufferRaw or buffer not changes length | + | | _.bufferResize_( src, size ) | _.bufferResize_( dst, dst, size ) if buffer not changes | + | | if src is BufferRaw or buffer changes length | _.bufferResize_( dst, src, size ) | + | | _.bufferResize_( dst, src, range ) | if dst.byteLength >= size | + | | if dst.byteLength < size | | + | ----------------- | ---------------------------------------------- | ---------------------------------------------------------- | + */ + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Buffer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Buffer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Buffer_s */ })(); + +/* */ /* begin of file Constructible_s */ ( function Constructible_s() { function Constructible_s_naked() { ( function _l7_Constructible_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.constructible = _.constructible || Object.create( null ); + +// -- +// dichotomy +// -- + +// -- +// extension +// -- + +let Extension = +{ +} + +// + +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Constructible.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Constructible_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Constructible_s */ })(); + +/* */ /* begin of file Container_s */ ( function Container_s() { function Container_s_naked() { ( function _l7_Container_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +function extendReplacing( dst, src ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( dst === null || dst === undefined ) + { + + if( _.aux.is( src ) ) + dst = _.props.extend( null, src ); + else if( _.longLike( src ) ) + dst = _.arrayExtendAppending( null, src ); + else if( _.hashMap.like( src ) ) + dst = _.hashMap.extend( null, src ); + else if( _.set.like( src ) ) + dst = _.arraySet.union_( null, src ); + else + dst = src; + + } + else if( _.aux.is( src ) ) + { + + if( _.aux.is( dst ) ) + dst = _.props.extend( dst, src ); + else if( _.hashMap.like( dst ) ) + dst = _.hashMap.extend( dst, src ); + else + dst = _.container.extendReplacing( null, src ); + + } + else if( _.longLike( src ) ) + { + + if( _.longIs( dst ) ) + { + for( let i = src.length - 1 ; i >= 0 ; i-- ) + dst[ i ] = src[ i ]; + } + else + { + dst = _.container.extendReplacing( null, src ); + } + + } + else if( _.hashMap.like( src ) ) + { + + if( _.hashMap.like( dst ) || _.aux.is( dst ) ) + dst = _.hashMap.extend( dst, src ); + else + dst = _.container.extendReplacing( null, src ); + + } + else if( _.set.like( src ) ) + { + + if( _.set.like( dst ) || _.longLike( dst ) ) + dst = _.arraySet.union_( dst, src ); + else + dst = _.container.extendReplacing( null, src ); + + } + else + { + + dst = src; + + } + + return dst; +} + +// + +function extendAppending( dst, src ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( dst === null || dst === undefined ) + { + + if( _.aux.is( src ) ) + dst = _.props.extend( null, src ); + else if( _.longLike( src ) ) + dst = _.arrayExtendAppending( null, src ); + else if( _.hashMap.like( src ) ) + dst = _.hashMap.extend( null, src ); + else if( _.set.like( src ) ) + dst = _.arraySet.union_( null, src ); + else + dst = src; + + } + else if( _.aux.is( dst ) ) + { + + if( _.aux.is( src ) ) + dst = _.props.extend( dst, src ); + else if( _.hashMap.like( src ) ) + dst = _.hashMap.extend( dst, src ); + else + dst = _.arrayExtendAppending( dst, src ); + + } + else if( _.longLike( dst ) ) + { + + dst = _.arrayExtendAppending( dst, src ); + + } + else if( _.hashMap.like( dst ) ) + { + + if( _.hashMap.like( src ) || _.aux.is( src ) ) + dst = _.hashMap.extend( dst, src ); + else + dst = _.arrayExtendAppending( dst, src ); + + } + else if( _.set.like( dst ) ) + { + + if( _.set.like( src ) || _.longLike( src ) ) + dst = _.arraySet.union_( dst, src ); + else + dst = _.arrayExtendAppending( dst, src ); + + } + else + { + + dst = src; + + } + + return dst; +} + +// -- +// declaration +// -- + +let ContainerExtension = +{ + + extendReplacing, /* zzz : dubious */ + extendAppending, /* zzz : dubious */ + +} + +_.props.supplement( _.container, ContainerExtension ); + +// + +let ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Container.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Container_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Container_s */ })(); + +/* */ /* begin of file Countable_s */ ( function Countable_s() { function Countable_s_naked() { ( function _l7_Countable_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.countable = _.countable || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +var Extension = +{ + +} + +// + +Object.assign( _.countable, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Countable.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Countable_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Countable_s */ })(); + +/* */ /* begin of file Ct_s */ ( function Ct_s() { function Ct_s_naked() { ( function _l7_Ct_s_() +{ + +'use strict'; + +/* = Glossary:: + +CT -- colorful text. + +*/ + +// + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.ct = _.ct || Object.create( null ); + +// -- +// implementation +// -- + +function _formatAffixesBackground( color ) +{ + let result = Object.create( null ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( color ) ); + + result.head = `❮background : ${color}❯`; + result.post = `❮background : default❯`; + + return result; +} + +// + +function formatBackground( srcStr, color ) +{ + + if( _.number.is( color ) ) + color = _.color.colorNameNearest( color ); + + _.assert( arguments.length === 2, 'Expects 2 arguments' ); + _.assert( _.strIs( srcStr ), 'Expects string {-srcStr-}' ); + _.assert( _.strIs( color ), 'Expects string {-color-}' ); + + return `❮background : ${color}❯${srcStr}❮background : default❯`; +} + +// + +function _formatAffixesForeground( color ) +{ + let result = Object.create( null ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( color ) ); + + result.head = `❮foreground : ${color}❯`; + result.post = `❮foreground : default❯`; + + return result; +} + +// + +function formatForeground( srcStr, color ) +{ + + if( _.number.is( color ) ) + color = _.color.colorNameNearest( color ); + + _.assert( arguments.length === 2, 'Expects 2 arguments' ); + _.assert( _.strIs( srcStr ), 'Expects string {-srcStr-}' ); + _.assert( _.strIs( color ), 'Expects string {-color-}' ); + + return `❮foreground : ${color}❯${srcStr}❮foreground : default❯`; +} + +// + +function _strEscape( srcStr ) +{ + let result = srcStr; + if( _.number.is( result ) ) + result = result + ''; + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( result ), 'Expects string got', _.entity.strType( result ) ); + return '❮inputRaw:1❯' + srcStr + '❮inputRaw:0❯' +} + +let escape = _.routineVectorize_functor( _strEscape ); + +// + +function _strUnescape( srcStr ) +{ + let result = srcStr; + if( _.number.is( result ) ) + result = result + ''; + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( result ), 'Expects string got', _.entity.strType( result ) ); + return '❮inputRaw:0❯' + srcStr + '❮inputRaw:1❯' +} + +let unescape = _.routineVectorize_functor( _strUnescape ); + +// + +function styleObjectFor( style ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( style ), 'Expects string got', _.entity.strType( style ) ); + + let result = _.ct.Style[ style ]; + + _.assert( _.mapIs( result ), `No such style : ${style}` ); + + return result; +} + +// + +function _affixesJoin() +{ + + _.assert( _.mapIs( arguments[ 0 ] ) ); + + for( let a = 1 ; a < arguments.length ; a++ ) + { + arguments[ 0 ].head = arguments[ a ].head + arguments[ 0 ].head; + arguments[ 0 ].post = arguments[ 0 ].post + arguments[ a ].post; + } + + return arguments[ 0 ]; +} + +// + +function _formatAffixesForStyleObject( styleObject ) +{ + let result = Object.create( null ); + result.head = ''; + result.post = ''; + + _.map.assertHasOnly( styleObject, _formatAffixesForStyleObject.defaults ); + + if( styleObject.fg ) + _.ct._affixesJoin( result, _.ct._formatAffixesForeground( styleObject.fg ) ); + + if( styleObject.bg ) + _.ct._affixesJoin( result, _.ct._formatAffixesBackground( styleObject.bg ) ); + + return result; +} + +_formatAffixesForStyleObject.defaults = +{ + fg : null, + bg : null, +} + +// + +function _formatAffixes( styles ) +{ + let result = Object.create( null ); + result.head = ''; + result.post = ''; + + styles = _.array.as( styles ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.arrayIs( styles ), 'Expects string or array of strings {- styles -}' ); + + for( let s = 0 ; s < styles.length ; s++ ) + { + let style = styles[ s ]; + + if( _.object.isBasic( style ) ) + { + let affixes = _.ct._formatAffixesForStyleObject( style ); + _.ct._affixesJoin( result, affixes ); + continue; + } + + _.assert( _.strIs( style ), 'Expects string or array of strings { style }' ); + + let styleObject = _.ct.styleObjectFor( style ); + _.assert( !!styleObject, 'Unknown style', _.strQuote( style ) ); + + let affixes = _.ct._formatAffixesForStyleObject( styleObject ); + _.ct._affixesJoin( result, affixes ); + + } + + return result; +} + +// + +function _format( srcStr, style ) +{ + let result = srcStr; + + if( _.number.is( result ) ) + result = result + ''; + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( result ), 'Expects string got', _.entity.strType( result ) ); + + let r = _.ct._formatAffixes( style ); + + result = r.head + result + r.post; + + return result; +} + +let format = _.routineVectorize_functor( _format ); + +// + +function _strip( srcStr ) +{ + + _.assert( _.strIs( srcStr ) ); + + let splitted = _.strSplitInlinedStereo_ + ({ + src : srcStr, + preservingEmpty : 0, + stripping : 0, + preservingInlined : 0, + inliningDelimeters : 1, + }); + + return splitted.join( '' ); +} + +let strip = _.vectorize( _strip ); + +// + +function parse( o ) +{ + if( _.strIs( arguments[ 0 ] ) ) + o = { src : arguments[ 0 ] }; + _.routine.options_( parse, o ); + o.inliningDelimeters = 1; + o.preservingOrdinary = 1; + o.preservingInlined = 1; + return _.strSplitInlinedStereo_( o ); +} + +parse.defaults = +{ + src : null, + prefix : '❮', + postfix : '❯', + onInlined : ( e ) => [ e ], + onOrdinary : null, + stripping : 0, + quoting : 0, + preservingDelimeters : 0, + preservingEmpty : 0, +} + +// + +let StripAnsi; +function _stripAnsi( src ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.strIs( src ) ); + + if( StripAnsi === undefined ) + StripAnsi = require( 'strip-ansi' ); + /* xxx : move to module::wCt, routine _.ct.stripAnsi() with lazy including of strip-ansi */ + /* qqq : implement without dependency */ + /* qqq : implement routine _.ct.fromAnsi() */ + + return StripAnsi( src ); +} + +let stripAnsi = _.vectorize( _stripAnsi ); + +// -- +// relation +// -- + +let Style = +{ + + 'positive' : { fg : 'green' }, + 'negative' : { fg : 'red' }, + + 'path' : { fg : 'dark cyan' }, + 'code' : { fg : 'dark green' }, + 'entity' : { fg : 'bright blue' }, + + 'topic.up' : { fg : 'white', bg : 'dark blue' }, + 'topic.down' : { fg : 'dark black', bg : 'dark blue' }, + + 'head' : { fg : 'dark black', bg : 'white' }, + 'tail' : { fg : 'white', bg : 'dark black' }, + + 'highlighted' : { fg : 'white', bg : 'dark black' }, + 'selected' : { fg : 'dark yellow', bg : 'dark blue' }, + 'neutral' : { fg : 'smoke', bg : 'dim' }, + 'secondary' : { fg : 'silver' }, + 'tertiary' : { fg : 'gray' }, + + 'pipe.neutral' : { fg : 'dark magenta' }, + 'pipe.negative' : { fg : 'dark red' }, + + 'exclusiveOutput.neutral' : { fg : 'dark black', bg : 'dark yellow' }, + 'exclusiveOutput.negative' : { fg : 'dark red', bg : 'dark yellow' }, + + 'info.neutral' : { fg : 'white', bg : 'magenta' }, + 'info.negative' : { fg : 'dark red', bg : 'magenta' }, + +} + +// -- +// declare +// -- + +let Extension = +{ + + // implementation + + _formatAffixesBackground, + formatBackground, + bg : formatBackground, + + _formatAffixesForeground, + formatForeground, + fg : formatForeground, + + escape, + unescape, + + styleObjectFor, + _affixesJoin, + _formatAffixesForStyleObject, + _formatAffixes, + _format, + format, + formatFinal : format, + + strip, + parse, /* qqq : for junior : test? */ + + _stripAnsi, + stripAnsi, /* xxx : qqq : move out to module::wCtBasic */ + + // fields + + Style, + +} + +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Ct.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Ct_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Ct_s */ })(); + +/* */ /* begin of file Date_s */ ( function Date_s() { function Date_s_naked() { ( function _l7_Date_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.date = _.date || Object.create( null ); + +// -- +// dichotomy +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +// + +let Extension = +{ + +} + +// + +Object.assign( _, ToolsExtension ); +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Date.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Date_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Date_s */ })(); + +/* */ /* begin of file Diagnostic_s */ ( function Diagnostic_s() { function Diagnostic_s_naked() { ( function _l7_Diagnostic_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.diagnostic = _.diagnostic || Object.create( null ); + +// -- +// diagnostic +// -- + +function beep() +{ + console.log( '\x07' ); +} + +// + +/* + +_.diagnostic.watchFields +({ + target : _global_, + names : 'Uniforms', +}); + +_.diagnostic.watchFields +({ + target : state, + names : 'filterColor', +}); + +_.diagnostic.watchFields +({ + target : _global_, + names : 'Config', +}); + +_.diagnostic.watchFields +({ + target : _global_, + names : 'logger', +}); + +_.diagnostic.watchFields +({ + target : self, + names : 'catalogPath', +}); + +*/ + +function watchFields( o ) +{ + + if( arguments[ 1 ] !== undefined ) + o = { target : arguments[ 0 ], names : arguments[ 1 ] } + o = _.routine.options( watchFields, o ); + + if( o.names ) + o.names = o.names; + // o.names = _.nameFielded( o.names ); + else + o.names = o.target; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.object.like( o.target ) ); + _.assert( _.object.like( o.names ) ); + + for( let f in o.names ) ( function() + { + + let propName = f; + let fieldSymbol = Symbol.for( f ); + //o.target[ fieldSymbol ] = o.target[ f ]; + let val = o.target[ f ]; + + /* */ + + function read() + { + //let result = o.target[ fieldSymbol ]; + let result = val; + if( o.verbosity > 1 ) + console.log( 'reading ' + propName + ' ' + _.entity.exportString( result ) ); + else + console.log( 'reading ' + propName ); + if( o.debugging > 1 ) + debugger; + return result; + } + + /* */ + + function write( src ) + { + if( o.verbosity > 1 ) + console.log( 'writing ' + propName + ' ' + _.entity.exportString( o.target[ propName ] ) + ' -> ' + _.entity.exportString( src ) ); + else + console.log( 'writing ' + propName ); + if( o.debugging ) + debugger; + //o.target[ fieldSymbol ] = src; + val = src; + } + + /* */ + + if( o.debugging > 1 ) + debugger; + + if( o.verbosity > 1 ) + console.log( 'watching for', propName, 'in', o.target ); + let properties = + { + enumerable : true, + configurable : true, + get : read, + set : write, + }; + Object.defineProperty( o.target, propName, properties ); + + })(); + +} + +watchFields.defaults = +{ + target : null, + names : null, + verbosity : 2, + debugging : 1, +} + +// + +/* + +_.diagnostic.proxyFields +({ + target : _.props, +}); + +_.diagnostic.watchFields +({ + target : _, + names : 'field', +}); + +*/ + +function proxyFields( o ) +{ + + if( arguments[ 1 ] !== undefined ) + o = { target : arguments[ 0 ], names : arguments[ 1 ] } + o = _.routine.options( proxyFields, o ); + + // if( o.names ) + // o.names = _.nameFielded( o.names ); + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.object.like( o.target ) ); + _.assert( _.object.like( o.names ) || o.names === null ); + + let handler = + { + set : function( obj, k, e ) + { + if( o.names && !( k in o.names ) ) + return; + if( o.verbosity > 1 ) + console.log( 'writing ' + k + ' ' + _.entity.exportString( o.target[ k ] ) + ' -> ' + _.entity.exportString( e ) ); + else + console.log( 'writing ' + k ); + if( o.debug ) + debugger; + obj[ k ] = e; + return true; + } + } + + let result = new Proxy( o.target, handler ); + if( o.verbosity > 1 ) + console.log( 'watching for', o.target ); + + if( o.debug ) + debugger; + + return result; +} + +proxyFields.defaults = +{ + ... watchFields.defaults, +} + +// + +function eachLongType( o ) +{ + let result = Object.create( null ); + + if( _.routine.is( o ) ) + o = { onEach : o } + o = _.routine.options( eachLongType, o ); + + if( o.onEach === null ) + o.onEach = function onEach( make, descriptor ) + { + return make; + } + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.routine.is( o.onEach ) ) + + // debugger; + + for( let k in _.long.namespaces ) + { + let namespace = _.long.namespaces[ k ]; + let long = _.withLong[ namespace.TypeName ]; + debugger; + result[ long.TypeName ] = o.onEach( long.make, long ); + } + + // debugger; + + return result; +} + +eachLongType.defaults = +{ + onEach : null, +} + +// + +function eachElementComparator( o ) +{ + let result = []; + + if( arguments[ 1 ] !== undefined ) + o = { onMake : arguments[ 0 ], onEach : arguments[ 1 ] || null } + else if( _.routine.is( arguments[ 0 ] ) ) + o = { onEach : arguments[ 1 ] || null } + + o = _.routine.options( eachElementComparator, o ); + + if( o.onEach === null ) + o.onEach = function onEach( make, evaluate, description ) + { + return evaluate; + } + + if( o.onMake === null ) + o.onMake = function onMake( src ) + { + return src; + } + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.routine.is( o.onEach ) ); + _.assert( _.routine.is( o.onMake ) ); + + result.push( o.onEach( o.onMake, undefined, 'no evaluator' ) ); + result.push( o.onEach( make, evaluator, 'evaluator' ) ); + result.push( o.onEach( make, [ evaluator, evaluator ], 'tandem of evaluators' ) ); + result.push( o.onEach( make, equalizer, 'equalizer' ) ); + + return result; + + /* */ + + function evaluator( e ) + { + _.assert( e.length === 1 ); + return e[ 0 ]; + } + + /* */ + + function equalizer( e1, e2 ) + { + _.assert( e1.length === 1 ); + _.assert( e2.length === 1 ); + return e1[ 0 ] === e2[ 0 ]; + } + + /* */ + + function make( long ) + { + _.assert( _.longIs( long ) ); + let result = []; + for( let l = 0 ; l < long.length ; l++ ) + result[ l ] = [ long[ l ] ]; + return o.onMake( result ); + } + +} + +eachElementComparator.defaults = +{ + onMake : null, + onEach : null, +} + +// + +function diagnosticStructureGenerate_head( routine, args ) +{ + _.assert( args.length === 0 || args.length === 1, () => `Expects optional argument, but got ${args.length} arguments` ); + + let o; + if( args.length === 1 ) + o = args[ 0 ]; + else + o = Object.create( null ); + + o = _.routine.options( structureGenerate, o ); + + if( o.arrayLength === null ) + o.arrayLength = o.defaultLength; + if( o.mapLength === null ) + o.mapLength = o.defaultLength; + if( o.hashMapLength === null ) + o.hashMapLength = o.defaultLength; + if( o.setLength === null ) + o.setLength = o.defaultLength; + + if( o.stringSize === null ) + o.stringSize = o.defaultSize; + if( o.bufferSize === null ) + o.bufferSize = o.defaultSize; + if( o.regexpSize === null ) + o.regexpSize = o.defaultSize; + + if( o.primitiveComplexity === null ) + o.primitiveComplexity = from( o.defaultComplexity ); + + if( o.nullComplexity === null ) + o.nullComplexity = from( o.primitiveComplexity ); + if( o.undefinedComplexity === null ) + o.undefinedComplexity = from( o.primitiveComplexity ); + if( o.booleanComplexity === null ) + o.booleanComplexity = from( o.primitiveComplexity ); + if( o.stringComplexity === null ) + o.stringComplexity = from( o.primitiveComplexity ); + if( o.bigIntComplexity === null ) + o.bigIntComplexity = from( o.primitiveComplexity ); + + if( o.numberComplexity === null ) + o.numberComplexity = from( o.primitiveComplexity ); + if( o.numberInfinityComplexity === null ) + o.numberInfinityComplexity = from( o.numberComplexity ); + if( o.numberNanComplexity === null ) + o.numberNanComplexity = from( o.numberComplexity ); + if( o.numberSignedZeroComplexity === null ) + o.numberSignedZeroComplexity = from( o.numberComplexity ); + + if( o.objectComplexity === null ) + o.objectComplexity = from( o.defaultComplexity ); + if( o.dateComplexity === null ) + o.dateComplexity = from( o.objectComplexity ); + if( o.regexpComplexity === null ) + o.regexpComplexity = from( o.objectComplexity ); + + if( o.bufferComplexity === null ) + o.bufferComplexity = from( o.objectComplexity ); + if( o.bufferNodeComplexity === null ) + o.bufferNodeComplexity = from( o.bufferComplexity ); + if( o.bufferRawComplexity === null ) + o.bufferRawComplexity = from( o.bufferComplexity ); + if( o.bufferBytesComplexity === null ) + o.bufferBytesComplexity = from( o.bufferComplexity ); + + if( o.containerComplexity === null ) + o.containerComplexity = from( o.defaultComplexity ); + if( o.recursionComplexity === null ) + o.recursionComplexity = from( o.containerComplexity ); + if( o.arrayComplexity === null ) + o.arrayComplexity = from( o.containerComplexity ); + if( o.mapComplexity === null ) + o.mapComplexity = from( o.containerComplexity ); + if( o.setComplexity === null ) + o.setComplexity = from( o.containerComplexity ); + if( o.hashMapComplexity === null ) + o.hashMapComplexity = from( o.containerComplexity ); + + _.assert( _.number.is( o.depth ) ); + + function from( complexity, min ) + { + if( min === undefined ) + return complexity; + + if( complexity >= min ) + return complexity; + + return 0; + } + + return o; +} + +// + +function diagnosticStructureGenerate_body( o ) +{ + + /**/ + + o.result = structureMake( 0 ); + o.size = _.entity.sizeOf( o.result ); + + return o; + + /* */ + + function structureMake( level ) + { + let struct = Object.create( null ); + + if( !( level <= o.depth ) ) + { + return null; + } + + if( o.nullComplexity >= 2 ) + { + struct[ 'null' ] = null; + } + + if( o.undefinedComplexity >= 3 ) + { + struct[ 'undefined' ] = undefined; + } + + if( o.booleanComplexity ) + { + struct[ 'boolean.true' ] = true; + struct[ 'boolean.false' ] = false; + } + + if( o.stringComplexity ) + { + if( o.random ) + struct[ 'string.defined' ] = _.strRandom( o.stringSize ); + else + struct[ 'string.defined' ] = new RegExp( _.strDup( 'a', o.stringSize ) ); + struct[ 'string.empty' ] = ''; + } + + if( o.numberComplexity ) + { + struct[ 'number.zero' ] = 0; + struct[ 'number.small' ] = 13; + } + + if( o.numberComplexity >= 2 ) + { + struct[ 'number.big' ] = 1 << 30; + } + + if( o.numberInfinityComplexity >= 2 ) + { + struct[ 'number.infinity.positive' ] = +Infinity; + struct[ 'number.infinity.negative' ] = -Infinity; + } + + if( o.numberNanComplexity >= 2 ) + { + struct[ 'number.nan' ] = NaN; + } + + if( o.numberSignedZeroComplexity >= 3 ) + { + struct[ 'number.signed.zero.negative' ] = -0; + struct[ 'number.signed.zero.positive' ] = +0; + } + + if( o.bigIntComplexity >= 3 ) + if( typeof BigInt !== 'undefined' ) + { + struct[ 'bigInt.zero' ] = BigInt( 0 ); + struct[ 'bigInt.small' ] = BigInt( 1 ); + struct[ 'bigInt.big' ] = BigInt( 1 ) << BigInt( 100 ); + } + + if( o.regexpComplexity >= 2 ) + { + if( o.random ) + struct[ 'regexp.defined' ] = new RegExp( _.strRandom( o.regexpSize ) ); + else + struct[ 'regexp.defined' ] = new RegExp( _.strDup( 'a', o.regexpSize ) ); + struct[ 'regexp.simple1' ] = /ab|cd/; + struct[ 'regexp.simple2' ] = /a[bc]d/; + struct[ 'regexp.simple3' ] = /ab{1, }bc/; + struct[ 'regexp.simple4' ] = /\.js$/; + struct[ 'regexp.simple5' ] = /.reg/; + } + + if( o.regexpComplexity >= 3 ) + { + struct[ 'regexp.complex0' ] = /^(?:(?!ab|cd).)+$/gm; + struct[ 'regexp.complex1' ] = /\/\*[\s\S]*?\*\/|\/\/.*/g; + struct[ 'regexp.complex2' ] = /^[1-9]+[0-9]*$/gm; + struct[ 'regexp.complex3' ] = /aBc/i; + struct[ 'regexp.complex4' ] = /^\d+/gm; + struct[ 'regexp.complex5' ] = /^a.*c$/g; + struct[ 'regexp.complex6' ] = /[a-z]/m; + struct[ 'regexp.complex7' ] = /^[A-Za-z0-9]$/; + } + + if( o.dateComplexity >= 3 ) + { + struct[ 'date.now' ] = new Date(); + struct[ 'date.fixed' ] = new Date( 1987, 1, 4, 5, 13, 0 ); + } + + // let bufferSrc = _.longFillTimes( [], o.bufferSize || o.defaultSize, 0 ); + let bufferSrc = _.longRandom( [], [ 0, 1 ], [ 0, o.bufferSize ] ); + /* qqq : suspicious! */ + + if( o.bufferNodeComplexity >= 4 ) + if( typeof BufferNode !== 'undefined' ) + struct[ 'buffer.node' ] = BufferNode.from( bufferSrc ); + + if( o.bufferRawComplexity >= 3 ) + struct[ 'buffer.raw' ] = new U8x( bufferSrc ).buffer; + + if( o.bufferBytesComplexity >= 3 ) + struct[ 'buffer.bytes' ] = new U8x( bufferSrc ); + + if( o.arrayComplexity ) + struct[ 'array.simple' ] = _.longFill( [], 0, [ 0, o.arrayLength ] ) + + if( o.arrayComplexity >= 3 ) + { + struct[ 'array.complex' ] = []; + for( let a = 0 ; a < o.arrayLength ; a++ ) + struct[ 'array.complex' ][ a ] = structureMake( level+1 ); + } + + /* */ + + if( o.setComplexity >= 3 ) + { + struct[ 'set' ] = new Set; + for( let m = 0 ; m < o.setLength ; m++ ) + struct[ 'set' ].add( structureMake( level+1 ) ); + } + + /* */ + + if( o.hashMapComplexity >= 4 ) + { + struct[ 'hashMap' ] = new HashMap; + for( let m = 0 ; m < o.hashMapLength ; m++ ) + struct[ 'hashMap' ].set( 'element' + m, structureMake( level+1 ) ); + } + + /* */ + + if( o.mapComplexity ) + { + // let map = struct[ 'mapComplex' ] = { 0 : '1', 1 : { b : 2 }, 2 : [ 1, 2, 3 ] }; + // if( o.mapLength ) + // struct[ 'map.complex' ] = mapFor( map, [ 0, 3 ] ); + struct[ 'map' ] = Object.create( null ); + for( let m = 0 ; m < o.mapLength ; m++ ) + struct[ 'map' ][ 'element' + m ] = structureMake( level+1 ); + } + + // if( o.map || o.result ) + // if( o.mapComplexity ) + // { + // // let map = struct[ 'map' ] = { 0 : string, 1 : 1, 2 : true }; + // // if( o.mapLength ) + // debugger; + // let map = struct[ 'map' ] = { 0 : string, 1 : 1, true : true }; + // struct[ 'map.simple' ] = mapFor( map, [ 0, 1 << 25 ] ); + // } + + if( level < o.depth ) + { + struct[ 'level' + ( level + 1 ) ] = structureMake( level+1 ); + } + + if( o.recursionComplexity >= 2 ) + { + struct[ 'recursion.self' ] = struct; + } + + if( o.recursionComplexity >= 3 && struct[ 'level' + ( level + 1 ) ] ) + { + struct[ 'level' + ( level + 1 ) ][ 'recursion.super' ] = struct; + } + + return struct; + + /* */ + + function mapFor( src, range ) + { + let map = {}; + for( var i = 0; i < o.mapLength; i++ ) + { + let k = _.intRandom( range ); + map[ i ] = src[ k ]; + } + return map; + } + } + + /* */ + + // function from( complexity, min ) + // { + // if( min === undefined ) + // return complexity; + + // if( complexity >= min ) + // return complexity; + + // return 0; + // } + + /* + + if( o.booleanComplexity || o.primitiveComplexity ) + currentLevel[ 'booleanComplexity' ] = true; + + if( o.numberComplexity || o.primitiveComplexity ) + currentLevel[ 'numberComplexity' ] = 0; + + if( o.numberSignedZeroComplexity || o.primitiveComplexity > 2 ) + { + currentLevel[ '-0' ] = -0; + currentLevel[ '+0' ] = +0; + } + + if( o.string || o.primitiveComplexity ) + currentLevel[ 'string' ] = string; + + if( o.nullComplexity || o.primitiveComplexity > 1 ) + currentLevel[ 'null' ] = null; + + if( o.numberInfinityComplexity || o.primitiveComplexity > 1 ) + { + currentLevel[ '+numberInfinityComplexity' ] = +Infinity; + currentLevel[ '-numberInfinityComplexity' ] = -Infinity; + } + + if( o.numberNanComplexity || o.primitiveComplexity > 1 ) + currentLevel[ 'numberNanComplexity' ] = NaN; + + if( o.undefinedComplexity || o.primitiveComplexity > 2 ) + currentLevel[ 'undefined' ] = undefined; + + if( o.dateComplexity || o.primitiveComplexity > 2 ) + currentLevel[ 'dateComplexity' ] = new Date(); + + if( o.bigIntComplexity || o.primitiveComplexity > 2 ) + if( typeof BigInt !== 'undefined' ) + currentLevel[ 'bigInt' ] = BigInt( 1 ); + + */ + +} + +diagnosticStructureGenerate_body.defaults = +{ + + result : null, + + /* */ + + depth : 1, /* qqq : cover the option */ + random : 1, /* qqq : cover the option */ + stringSize : null, + bufferSize : null, + regexpSize : null, + defaultSize : 50, + + arrayLength : null, + mapLength : null, + hashMapLength : null, + setLength : null, + defaultLength : 4, + + /* */ + + defaultComplexity : 2, + + primitiveComplexity : null, + nullComplexity : null, + undefinedComplexity : null, + booleanComplexity : null, + stringComplexity : null, + bigIntComplexity : null, + numberComplexity : null, + numberInfinityComplexity : null, + numberNanComplexity : null, + numberSignedZeroComplexity : null, + + objectComplexity : null, + dateComplexity : null, + regexpComplexity : null, + bufferComplexity : null, + bufferNodeComplexity : null, + bufferRawComplexity : null, + bufferBytesComplexity : null, + + containerComplexity : null, + recursionComplexity : null, + arrayComplexity : null, + mapComplexity : null, + setComplexity : null, + hashMapComplexity : null, + +} + +// + +/** + * Routine diagnosticStructureGenerate generates structure with different data types in provided options map {-o-}. The final resulted structure almost defined by + * property {-o.defaultComplexity-} of options map {-o-} and other separate options. + * If routine calls without arguments, then routine returns new map with structure that generates from default parameters. + * + * @param { Map } o - The options map. Options map includes next options: + * + * @param { Number } o.defaultComplexity - The complexity of data types, options of which is not defined directly. Default value - 2. + * + * @param { Number } o.primitiveComplexity - The default complexity for primitives. If option is not defined, then it inherits {-o.defaultComplexity-}. + * @param { Number } o.nullComplexity - Option for enabling generating of null. To generate null, it should be 2 or more. + * @param { Number } o.undefinedComplexity - Option for enabling generating of undefined. To generate undefined, it should be 3 or more. + * @param { Number } o.booleanComplexity - Option for enabling generating of boolean values. To generate true and false, it should be 1 or more. + * @param { Number } o.stringComplexity - Option for enabling generating of string. To generate random string with {-o.stringSize-} length + * and empty string, it should be 1 or more. + * @param { Number } o.bigIntComplexity - Option for enabling generating of bigInt numbers. To generate bigInt zero, small and big value, it should be 3 or more. + * @param { Number } o.numberComplexity - Option for enabling generating of numbers. To generate zero and small value, it should be 1. If option is 2 or more, + * then routine generates big value. + * @param { Number } o.numberInfinityComplexity - Option for enabling generating of Infinity values. To generate positive and negative Infinity, + * it should be 2 or more. + * @param { Number } o.numberNanComplexity - Option for enabling generating of NaN. To generate NaN, it should be 2 or more. + * @param { Number } o.numberSignedZeroComplexity - Option for enabling generating of signed zero values. To generate positive and negative zero, + * it should be 3 or more. + * + * @param { Number } o.objectComplexity - The default complexity for Date, RegExp and buffers. If option is not defined, then it inherits {-o.defaultComplexity-}. + * @param { Number } o.dateComplexity - Option for enabling generating of Date instances. To generate Date instance with current date and with fixed date, + * it should be 3 or more. + * @param { Number } o.regexpComplexity - Option for enabling generating of regexps. To generate simple regexps, it should be 2. To generate complex + * regexps it should be 3 or more. + * @param { Number } o.bufferComplexity - The default complexity for buffers ( raw, typed, view, node ). If option is not defined, + * then it inherits {-o.objectComplexity-} + * @param { Number } o.bufferNodeComplexity - Option for enabling generating of BufferNode. To generate BufferNode, it should be 4 or more. + * @param { Number } o.bufferRawComplexity - Option for enabling generating of BufferRaw. To generate BufferRaw it should be 3 or more. + * @param { Number } o.bufferBytesComplexity - Option for enabling generating of typed U8x buffer. To generate BufferBytes, it should be 3 or more. + + * @param { Number } o.containerComplexity - The default complexity array, map, Set, HashMap and recursion. If option is not defined, then + * it inherits {-o.defaultComplexity-}. + * @param { Number } o.recursionComplexity - Option for enabling generating field with recursive link to current structure. To generate link, + * it should be 2 or more. + * @param { Number } o.arrayComplexity - Option for enabling generating of array. To generate flat array, it should be 2. If option set to 3 or more, + * then routine generated array with nested arrays. Depth of nesting defines by option {-o.depth-}. + * @param { Number } o.mapComplexity - Option for enabling generating of map. To generate map, it should be 1 or more. + * @param { Number } o.setComplexity - Option for enabling generating of Set. To generate Set, it should be 3 or more. + * @param { Number } o.hashMapComplexity - Option for enabling generating of HashMap. To generate HashMap, it should be 4 or more. + * + * @param { Number } o.depth - Defines maximal generated level of nesting for complex data structure. Default value - 1. + * @param { Number } defaultSize - The default size of generated string, buffer, regexp. Default value - 50. + * @param { Number } o.stringSize - The length of generated string. + * @param { Number } o.bufferSize - The length of generated buffer ( raw, typed, view, node ). + * @param { Number } o.regexpSize - The length of generated regexp. + * @param { Number } o.defaultLength - The default length for generated array, map, HashMap, Set. Default value - 4. + * @param { Number } o.arrayLength - The length of generated array. + * @param { Number } o.mapLength - The length of generated map. + * @param { Number } o.hashMapLength - The length of generated HashMap. + * @param { Number } o.setLength - The length of generated Set. + * + * @example + * _.diagnostic.structureGenerate() + * //returns + * // [Object: null prototype] + * // { + * // result: [Object: null prototype] + * // { + * // // generated structure + * // }, + * // depth: 1, + * // stringSize: 50, + * // bufferSize: 50, + * // regexpSize: 50, + * // defaultSize: 50, + * // arrayLength: 4, + * // mapLength: 4, + * // hashMapLength: 4, + * // setLength: 4, + * // defaultLength: 4, + * // defaultComplexity: 2, + * // primitiveComplexity: 2, + * // nullComplexity: 2, + * // undefinedComplexity: 2, + * // booleanComplexity: 2, + * // ... + * // // other options + * // } + * + * @returns { Map } - Returns map with diagnostic data types of defined complexity. + * @function diagnosticStructureGenerate + * @throws { Error } If arguments.length is more then one. + * @throws { Error } If options map {-o-} is not aixiliary. + * @throws { Error } If options map {-o-} has unknown options. + * @namespace Tools + */ + +let structureGenerate = _.routine.unite( diagnosticStructureGenerate_head, diagnosticStructureGenerate_body ); + +// // +// +// function objectMake( o ) +// { +// let result; +// +// _.assert( arguments.length === 1 ); +// countableConstructorPure.prototype = Object.create( null ); +// if( o.withConstructor ) +// countableConstructorPure.prototype.constructor = countableConstructorPure; +// +// /* xxx : replace countableMake */ +// +// if( o.new ) +// { +// if( o.pure ) +// result = new countableConstructorPure( o ); +// else +// result = new countableConstructorPolluted( o ); +// } +// else +// { +// result = _objectMake( null, o ); +// } +// +// if( o.withOwnConstructor ) +// result.constructor = function ownConstructor(){} +// +// return result; +// +// /* - */ +// +// function _iterate() +// { +// +// let iterator = Object.create( null ); +// iterator.next = next; +// iterator.index = 0; +// iterator.instance = this; +// return iterator; +// +// function next() +// { +// let result = Object.create( null ); +// result.done = this.index === this.instance.elements.length; +// if( result.done ) +// return result; +// result.value = this.instance.elements[ this.index ]; +// this.index += 1; +// return result; +// } +// +// } +// +// /* */ +// +// function countableConstructorPure( o ) +// { +// return _objectMake( this, o ); +// } +// +// /* */ +// +// function countableConstructorPolluted( o ) +// { +// let result = _objectMake( this, o ); +// if( !o.withConstructor ) +// delete Object.getPrototypeOf( result ).constructor; +// return result +// } +// +// /* */ +// +// function _objectMake( dst, o ) +// { +// if( dst === null ) +// if( o.pure ) +// dst = Object.create( null ); +// else +// dst = {}; +// _.props.extend( dst, o ); +// if( o.countable ) +// dst[ Symbol.iterator ] = _iterate; +// return dst; +// } +// +// /* */ +// +// } +// +// objectMake.defaults = +// { +// new : 0, +// pure : 0, +// countable : 0, +// withOwnConstructor : 0, +// withConstructor : 0, +// elements : null, +// } + +// -- +// extension +// -- + +let ToolsExtension = +{ + // diagnosticCode, + diagnosticBeep : beep, + + diagnosticWatchFields : watchFields, /* experimental */ + diagnosticProxyFields : proxyFields, /* experimental */ + diagnosticEachLongType : eachLongType, + diagnosticEachElementComparator : eachElementComparator, + + diagnosticStructureGenerate : structureGenerate, /* xxx : move */ + // diagnosticObjectMake, + +} + +Object.assign( _, ToolsExtension ); + +// + +let DiagnosticExtension = +{ + + // diagnosticCode, + beep, + + watchFields, /* experimental */ + proxyFields, /* experimental */ + eachLongType, + eachElementComparator, + + structureGenerate, + +} + +// + +Object.assign( _.diagnostic, DiagnosticExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Diagnostic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Diagnostic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Diagnostic_s */ })(); + +/* */ /* begin of file Entity_s */ ( function Entity_s() { function Entity_s_naked() { ( function _l7_Entity_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _global_.wTools; + +// -- +// entity getter +// -- + +/** + * Returns "size" of entity( src ). Representation of "size" depends on type of( src ): + * - For string returns value of it own length property; + * - For array-like entity returns value of it own byteLength property for( BufferRaw, TypedArray, etc ) + * or length property for other; + * - In other cases returns null. + * + * @param {*} src - Source entity. + * @returns {number} Returns "size" of entity. + * + * @example + * _.entity.sizeOfUncountable( 'string' ); + * // returns 6 + * + * @example + * _.entity.sizeOfUncountable( new BufferRaw( 8 ) ); + * // returns 8 + * + * @example + * _.entity.sizeOfUncountable( 123 ); + * // returns null + * + * @function sizeOfUncountable + * @namespace Tools +*/ + +/* qqq : cover argument sizeOfContainer */ +function sizeOfUncountable( src, sizeOfContainer ) +{ + if( arguments.length === 1 ) + sizeOfContainer = 8; + + _.assert( _.number.defined( sizeOfContainer ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( _.strIs( src ) ) + { + if( src.length ) + return _.bufferBytesFrom( src ).byteLength + sizeOfContainer; + return src.length + sizeOfContainer; + } + + if( _.primitive.is( src ) ) + return sizeOfContainer || 8; + + if( _.routine.is( src ) ) + return sizeOfContainer; + + if( _.number.is( src.byteLength ) ) + return src.byteLength + sizeOfContainer; + + if( _.regexpIs( src ) ) + return _.entity.sizeOfUncountable( src.source, 0 ) + src.flags.length + sizeOfContainer; + + // if( !_.iterableIs( src ) ) /* yyy */ /* Dmytro : simulate behavior of routine iterableIs, routine countableIs has different behavior */ + // return sizeOfContainer; + // if( !_.aux.is( src ) ) + // if( !_.class.methodIteratorOf( src ) ) + // return sizeOfContainer; + // if( _.countable.is( src ) ) + // return _.countable.lengthOf( src ) + sizeOfContainer; + + return NaN; +} + +// + +/** + * Returns "size" of entity( src ). Representation of "size" depends on type of( src ): + * - For string returns value of it own length property; + * - For array-like entity returns value of it own byteLength property for( BufferRaw, TypedArray, etc ) + * or length property for other; + * - In other cases returns null. + * + * @param {*} src - Source entity. + * @returns {number} Returns "size" of entity. + * + * @example + * _.entity.sizeOf( 'string' ); + * // returns 6 + * + * @example + * _.entity.sizeOf( [ 1, 2, 3 ] ); + * // returns 3 + * + * @example + * _.entity.sizeOf( new BufferRaw( 8 ) ); + * // returns 8 + * + * @example + * _.entity.sizeOf( 123 ); + * // returns null + * + * @function entitySize + * @namespace Tools +*/ + +/* qqq : review */ + +/* qqq : cover argument sizeOfContainer */ +function sizeOf( src, sizeOfContainer ) +{ + let result = 0; + + if( arguments.length === 1 ) + sizeOfContainer = 8; + + _.assert( _.number.defined( sizeOfContainer ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + // if( _.primitive.is( src ) || _.bufferAnyIs( src ) || !( _.mapIs( src ) || _.class.methodIteratorOf( src ) ) ) + if( _.primitive.is( src ) || _.bufferAnyIs( src ) || _.routineIs( src ) || _.regexpIs( src ) ) + return _.entity.sizeOfUncountable( src, sizeOfContainer ); + + /* + full implementation of routine _.entity.sizeOf() in the module::LookerExtra + */ + + return NaN; +} + +// -- +// entity extension +// -- + +let EntityExtension = +{ + + sizeOfUncountable, + sizeOf, + +} + +Object.assign( _.entity, EntityExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + // sizeOfUncountable, + // entitySize, + // sizeOf : entitySize, + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Entity.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Entity_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Entity_s */ })(); + +/* */ /* begin of file Err_s */ ( function Err_s() { function Err_s_naked() { ( function _l7_Err_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global.wTools; +const _err = _._err; + +// -- +// dichotomy +// -- + +function _isInstanceOrClass( _constructor, _this ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + debugger; + let result = + ( + _this === _constructor + || _this instanceof _constructor + || Object.isPrototypeOf.call( _constructor, _this ) + || Object.isPrototypeOf.call( _constructor, _this.prototype ) + ); + return result; +} + +// // +// +// function _ownNoConstructor( ins ) +// { +// _.assert( !_.primitive.is( ins ) ); +// _.assert( arguments.length === 1 ); +// let result = !Object.hasOwnProperty.call( ins, 'constructor' ); +// return result; +// } + +// + +function sureInstanceOrClass( _constructor, _this ) +{ + _.sure( arguments.length === 2, 'Expects exactly two arguments' ); + _.sure( _._isInstanceOrClass( _constructor, _this ) ); +} + +// + +function sureOwnNoConstructor( ins ) +{ + _.sure( !_.primitive.is( ins ) ); + let args = Array.prototype.slice.call( arguments ); + args[ 0 ] = !Object.hasOwnProperty.call( ins, 'constructor' ); + _.sure.apply( _, args ); +} + +// + +function assertInstanceOrClass( _constructor, _this ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _._isInstanceOrClass( _constructor, _this ) ); +} + +// + +function assertOwnNoConstructor( ins ) +{ + _.assert( !_.primitive.is( ins ) ); + let args = Array.prototype.slice.call( arguments ); + args[ 0 ] = !Object.hasOwnProperty.call( ins, 'constructor' ); + _.assert.apply( _, args ); + // _.assert( !_.primitive.is( ins ) ); + // let args = Array.prototype.slice.call( arguments ); + // args[ 0 ] = _.sureOwnNoConstructor( ins ); + // + // if( args.length === 1 ) + // args.push( () => 'Entity should not own constructor, but own ' + _.entity.exportStringDiagnosticShallow( ins ) ); + // + // _.assert.apply( _, args ); +} + +// -- +// errrors +// -- + +let ErrorAbort = _.error.error_functor( 'ErrorAbort' ); + +// -- +// declare +// -- + +/* zzz : move into independent module or namespace */ + +let ErrorExtension = +{ + ErrorAbort, +} + +let ToolsExtension = +{ + + // dichotomy + + _isInstanceOrClass, + // _ownNoConstructor, + + // sure + + sureInstanceOrClass, + sureOwnNoConstructor, + + // assert + + assertInstanceOrClass, + assertOwnNoConstructor, + +} + +Object.assign( _.error, ErrorExtension ); +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Err.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Err_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Err_s */ })(); + +/* */ /* begin of file Escape_s */ ( function Escape_s() { function Escape_s_naked() { ( function _l7_Escape_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.escape = _.escape || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +var Extension = +{ +} + +// + +_.props.supplement( _.escape, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Escape.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Escape_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Escape_s */ })(); + +/* */ /* begin of file Event_s */ ( function Event_s() { function Event_s_naked() { ( function _l7_Event_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// +// -- + +// -- +// declare +// -- + +let Extension = +{ +}; + +Object.assign( _.event, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Event.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Event_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Event_s */ })(); + +/* */ /* begin of file Functional_s */ ( function Functional_s() { function Functional_s_naked() { ( function _l7_Functional_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _global_.wTools; + +// -- +// +// -- + +function _entityFilterDeep( o ) +{ + + let result; + let onEach = _._filter_functor( o.onEach, o.conditionLevels ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.object.like( o.src ) || _.longIs( o.src ), 'entityFilter : expects objectLike or longIs src, but got', _.entity.strType( o.src ) ); + _.assert( _.routine.is( onEach ) ); + + /* */ + + if( _.longIs( o.src ) ) + { + if( _.argumentsArray.is( o.src ) ) /* Dmytro : seems as hack, this primitive realization use type check. The more type independent realization creates resulted container of full length and routine longBut_ */ /* qqq xxx : Dmytro : please, discuss it */ + result = []; + else + result = _.long.make( o.src, 0 ); + + // result = _.long.make( o.src, o.src.length ); /* Dmytro : second variant */ + let s, d; + for( s = 0, d = 0 ; s < o.src.length ; s++ ) + // for( let s = 0, d = 0 ; s < o.src.length ; s++, d++ ) + { + let r = onEach.call( o.src, o.src[ s ], s, o.src ); + + if( _.unrollIs( r ) ) + { + _.arrayAppendArray( result, r ); + // _.longBut_( result, d, r ); /* Dmytro : second variant */ + d += r.length; + } + else if( r !== undefined ) + { + result[ d ] = r; + d += 1; + } + + // if( r === undefined ) + // d--; + // else + // result[ d ] = r; + + } + if( d < o.src.length ) + result = _.longSlice( result, 0, d ); + // result = _.array.slice( result, 0, d ); + } + else + { + result = _.entity.makeUndefined( o.src ); + for( let s in o.src ) + { + let r = onEach.call( o.src, o.src[ s ], s, o.src ); + // r = onEach.call( o.src, o.src[ s ], s, o.src ); + if( r !== undefined ) + result[ s ] = r; + } + } + + /* */ + + return result; +} + +_entityFilterDeep.defaults = +{ + src : null, + onEach : null, + conditionLevels : 1, +} + +// + +function entityFilterDeep( src, onEach ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + return _entityFilterDeep + ({ + src, + onEach, + conditionLevels : 1024, + }); +} + +// + +/* +qqq : for Dmytro : poor coverage and implementation was wrong! +*/ + +function _entityIndex_functor( fop ) +{ + + fop = _.routine.options( _entityIndex_functor, fop ); + + let extendRoutine = fop.extendRoutine; + + return function entityIndex( src, onEach ) + { + let result = Object.create( null ); + + if( onEach === undefined ) + onEach = function( e, k ) + { + if( k === undefined && extendRoutine ) + return { [ e ] : undefined }; + return k; + } + else if( _.strIs( onEach ) ) + { + let selector = onEach; + _.assert( _.routine.is( _.select ) ); + _.assert( _.strBegins( selector, '*/' ), () => `Selector should begins with "*/", but "${selector}" does not` ); + selector = _.strRemoveBegin( selector, '*/' ); + onEach = function( e, k ) + { + return _.select( e, selector ); + } + /* Dmytro : Note. Selector selects properties of entities. For example: + var got = ( 'str', '\*\/length' ); + var exp = { 3 : 'str' }; + test.identical( got, exp ); + */ + } + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.routine.is( onEach ) ); + _.assert( src !== undefined, 'Expects {-src-}' ); + + /* */ + + if( _.aux.is( src ) ) + { + + for( let k in src ) + { + let val = src[ k ]; + let r = onEach( val, k, src ); + extend( r, val ); + } + + } + else if( _.longIs( src ) ) + { + + for( let k = 0 ; k < src.length ; k++ ) + { + let val = src[ k ]; + let r = onEach( val, k, src ); + extend( r, val ); + } + + } + else + { + + let val = src; + let r = onEach( val, undefined, undefined ); + extend( r, val ); + + } + + return result; + + /* */ + + function extend( ext, val ) + { + if( ext === undefined ) + return; + + if( _.unrollIs( ext ) ) + return ext.forEach( ( ext ) => extend( ext, val ) ); + + if( extendRoutine === null ) + { + // if( ext !== undefined ) // Dmytro : it's unnecessary condition, see 10 lines above + result[ ext ] = val; + } + else + { + if( !_.aux.is( ext ) ) + { + _.assert( _.primitive.is( ext ) ); + ext = { [ ext ] : val } + } + extendRoutine( result, ext ); + // // else if( ext !== undefined ) // Dmytro : it's unnecessary condition, see 16 lines above + // else + // result[ ext ] = val; + } + + } + + } + +} + +_entityIndex_functor.defaults = +{ + extendRoutine : null, +} + +// + +/** + * The routine entityIndex() returns a new pure map. The values of the map defined by elements of provided + * entity {-src-} and keys defined by result of callback execution on the correspond elements. + * If callback returns undefined, then element will not exist in resulted map. + * + * @param { * } src - Any entity to make map of indexes. + * @param { String|Function } onEach - The callback executed on elements of entity. + * If {-onEach-} is not defined, then routine uses callback that returns index of element. + * If {-onEach-} is a string, then routine searches elements with equal key. String value should has + * prefix "*\/" ( asterisk + slash ). + * By default, {-onEach-} applies three parameters: element, key, container. If entity is primitive, then + * routine applies only element value, other parameters is undefined. + * + * @example + * _.entityIndex( null ); + * // returns {} + * + * @example + * _.entityIndex( null, ( el ) => el ); + * // returns { 'null' : null } + * + * @example + * _.entityIndex( [ 1, 2, 3, 4 ] ); + * // returns { '0' : 1, '1' : 2, '2' : 3, '3' : 4 } + * + * @example + * _.entityIndex( [ 1, 2, 3, 4 ], ( el, key ) => el + key ); + * // returns { '1' : 1, '3' : 2, '5' : 3, '7' : 4 } + * + * @example + * _.entityIndex( { a : 1, b : 2, c : 3 } ); + * // returns { a : 1, b : 2, c : 3 } + * + * @example + * _.entityIndex( { a : 1, b : 2, c : 3 }, ( el, key, container ) => container.a > 0 ? key : el ); + * // returns { '1' : 1, '2' : 2, '3' : 3 } + * + * @example + * _.entityIndex( { a : { f1 : 1, f2 : 3 }, b : { f1 : 2, f2 : 4 } }, '*\/f1' ); + * // returns { '1' : { f1 : 1, f2 : 3 }, '2' : { f1 : 2, f2 : 4 } } + * + * @returns { PureMap } - Returns the pure map. Values of the map defined by elements of provided entity {-src-} + * and keys defined by results of callback execution on corresponding elements. + * @function entityIndex + * @throws { Error } If arguments.length is less then one or more then two. + * @throws { Error } If {-src-} has value undefined. + * @throws { Error } If {-onEach-} is not undefined, not a function, not a String. + * @throws { Error } If {-onEach-} is a String, but has not prefix '*\/' ( asterisk + slash ). + * @namespace Tools + */ + +let entityIndex = _entityIndex_functor({ extendRoutine : null }); + +// + +/** + * The routine entityIndexSupplementing() returns a new pure map. The pairs key-value of the map formed by results + * of callback execution on the entity elements. + * If callback returns undefined, then element will not exist in resulted map. + * If callback returns map with key existed in resulted map, then routine does not change existed value. + * + * @param { * } src - Any entity to make map of indexes. + * @param { String|Function } onEach - The callback executed on elements of entity. + * If {-onEach-} is not defined, then routine uses callback that returns index of element. + * If {-onEach-} is a string, then routine searches elements with equal key. String value should has + * prefix "*\/" ( asterisk + slash ). + * By default, {-onEach-} applies three parameters: element, key, container. If entity is primitive, then + * routine applies only element value, other parameters is undefined. + * + * @example + * _.entityIndexSupplementing( null ); + * // returns { 'null' : undefined } + * + * @example + * _.entityIndexSupplementing( null, ( el ) => el ); + * // returns { 'null' : null } + * + * @example + * _.entityIndexSupplementing( [ 1, 2, 3, 4 ] ); + * // returns { '0' : 1, '1' : 2, '2' : 3, '3' : 4 } + * + * @example + * _.entityIndexSupplementing( [ 1, 2, 3, 4 ], ( el, key ) => key > 2 ? key : 1 ); + * // returns { '1' : 3, '3' : 4 } + * + * @example + * _.entityIndexSupplementing( { a : 1, b : 1, c : 1 } ); + * // returns { a : 1, b : 1, c : 1 } + * + * @example + * _.entityIndexSupplementing( { a : 1, b : 2, c : 3 }, ( el, key, container ) => container.a > 0 ? key : el ); + * // returns { a : 1, b : 2, c : 3 } + * + * @example + * _.entityIndexSupplementing( { a : 1, b : 2, c : 3 }, ( el, key, container ) => { return { [ key ] : key, 'x' : el } } ); + * // returns { a : 'a', x : 1, b : 'b', c : 'c' } + * + * @example + * _.entityIndexSupplementing( { a : { f1 : 1, f2 : 3 }, b : { f1 : 1, f2 : 4 } }, '*\/f1' ); + * // returns { '1' : { f1 : 1, f2 : 4 } } + * + * @returns { PureMap } - Returns the pure map. Values of the map defined by elements of provided entity {-src-} + * and keys of defines by results of callback execution on corresponding elements. If the callback returns map + * with existed key, then routine does not replaces the previous value with the new one. + * @function entityIndexSupplementing + * @throws { Error } If arguments.length is less then one or more then two. + * @throws { Error } If {-src-} has value undefined. + * @throws { Error } If {-onEach-} is not undefined, not a function, not a String. + * @throws { Error } If {-onEach-} is a String, but has not prefix '*\/' ( asterisk + slash ). + * @namespace Tools + */ + +let entityIndexSupplementing = _entityIndex_functor({ extendRoutine : _.props.supplement.bind( _.props ) }); + +// + +/** + * The routine entityIndexExtending() returns a new pure map. The pairs key-value of the map formed by results + * of callback execution on the entity elements. + * If callback returns undefined, then element will not exist in resulted map. + * If callback returns map with key existed in resulted map, then routine replaces existed value to the new. + * + * @param { * } src - Any entity to make map of indexes. + * @param { String|Function } onEach - The callback executed on elements of entity. + * If {-onEach-} is not defined, then routine uses callback that returns index of element. + * If {-onEach-} is a string, then routine searches elements with equal key. String value should has + * prefix "*\/" ( asterisk + slash ). + * By default, {-onEach-} applies three parameters: element, key, container. If entity is primitive, then + * routine applies only element value, other parameters is undefined. + * + * @example + * _.entityIndexExtending( null ); + * // returns { 'null' : undefined } + * + * @example + * _.entityIndexExtending( null, ( el ) => el ); + * // returns { 'null' : null } + * + * @example + * _.entityIndexExtending( [ 1, 2, 3, 4 ] ); + * // returns { '0' : 1, '1' : 2, '2' : 3, '3' : 4 } + * + * @example + * _.entityIndexExtending( [ 1, 2, 3, 4 ], ( el, key ) => key > 2 ? key : 1 ); + * // returns { '1' : 3, '3' : 4 } + * + * @example + * _.entityIndexExtending( { a : 1, b : 1, c : 1 } ); + * // returns { a : 1, b : 1, c : 1 } + * + * @example + * _.entityIndexExtending( { a : 1, b : 2, c : 3 }, ( el, key, container ) => container.a > 0 ? key : el ); + * // returns { a : 1, b : 2, c : 3 } + * + * @example + * _.entityIndexExtending( { a : 1, b : 2, c : 3 }, ( el, key, container ) => { return { [ key ] : key, 'x' : el } } ); + * // returns { a : 'a', x : 3, b : 'b', c : 'c' } + * + * @example + * _.entityIndexExtending( { a : { f1 : 1, f2 : 3 }, b : { f1 : 1, f2 : 4 } }, '*\/f1' ); + * // returns { '1' : { f1 : 1, f2 : 4 } } + * + * @returns { PureMap } - Returns the pure map. Values of the map defined by elements of provided entity {-src-} + * and keys of defines by results of callback execution on corresponding elements. If the callback returns map + * with existed key, then routine replaces the previous value with the new one. + * @function entityIndexExtending + * @throws { Error } If arguments.length is less then one or more then two. + * @throws { Error } If {-src-} has value undefined. + * @throws { Error } If {-onEach-} is not undefined, not a function, not a String. + * @throws { Error } If {-onEach-} is a String, but has not prefix '*\/' ( asterisk + slash ). + * @namespace Tools + */ + +let entityIndexExtending = _entityIndex_functor({ extendRoutine : _.props.extend.bind( _.props ) }); + +// + +/** + * The routine entityIndexPrepending() returns a new pure map. The pairs key-value of the map formed by results + * of callback execution on the entity elements. + * If callback returns undefined, then element will not exist in resulted map. + * If callback returns map with key existed in resulted map, then routine prepends new values to the existed value. + * + * @param { * } src - Any entity to make map of indexes. + * @param { String|Function } onEach - The callback executed on elements of entity. + * If {-onEach-} is not defined, then routine uses callback that returns index of element. + * If {-onEach-} is a string, then routine searches elements with equal key. String value should has + * prefix "*\/" ( asterisk + slash ). + * By default, {-onEach-} applies three parameters: element, key, container. If entity is primitive, then + * routine applies only element value, other parameters is undefined. + * + * @example + * _.entityIndexPrepending( null ); + * // returns { 'null' : undefined } + * + * @example + * _.entityIndexPrepending( null, ( el ) => el ); + * // returns { 'null' : null } + * + * @example + * _.entityIndexPrepending( [ 1, 2, 3, 4 ] ); + * // returns { '0' : 1, '1' : 2, '2' : 3, '3' : 4 } + * + * @example + * _.entityIndexPrepending( [ 1, 2, 3, 4 ], ( el, key ) => key > 2 ? key : 1 ); + * // returns { '1' : 3, '3' : 4 } + * + * @example + * _.entityIndexPrepending( { a : 1, b : 1, c : 1 } ); + * // returns { a : 1, b : 1, c : 1 } + * + * @example + * _.entityIndexPrepending( { a : 1, b : 2, c : 3 }, ( el, key, container ) => container.a > 0 ? key : el ); + * // returns { a : 1, b : 2, c : 3 } + * + * @example + * _.entityIndexPrepending( { a : 1, b : 2, c : 3 }, ( el, key, container ) => { return { [ key ] : key, 'x' : el } } ); + * // returns { a : 'a', x : [ 3, 2, 1 ], b : 'b', c : 'c' } + * + * @example + * _.entityIndexPrepending( { a : { f1 : 1, f2 : 3 }, b : { f1 : 1, f2 : 4 } }, '*\/f1' ); + * // returns { '1' : { f1 : 1, f2 : 4 } } + * + * @returns { PureMap } - Returns the pure map. Values of the map defined by elements of provided entity {-src-} + * and keys of defines by results of callback execution on corresponding elements. If the callback returns map + * with existed key, then routine prepends new value to the previous. + * @function entityIndexPrepending + * @throws { Error } If arguments.length is less then one or more then two. + * @throws { Error } If {-src-} has value undefined. + * @throws { Error } If {-onEach-} is not undefined, not a function, not a String. + * @throws { Error } If {-onEach-} is a String, but has not prefix '*\/' ( asterisk + slash ). + * @namespace Tools + */ + +let entityIndexPrepending = _entityIndex_functor({ extendRoutine : _.mapExtendPrepending }); + +// + +/** + * The routine entityIndexAppending() returns a new pure map. The pairs key-value of the map formed by results + * of callback execution on the entity elements. + * If callback returns undefined, then element will not exist in resulted map. + * If callback returns map with key existed in resulted map, then routine appends new values to the existed value. + * + * @param { * } src - Any entity to make map of indexes. + * @param { String|Function } onEach - The callback executed on elements of entity. + * If {-onEach-} is not defined, then routine uses callback that returns index of element. + * If {-onEach-} is a string, then routine searches elements with equal key. String value should has + * prefix "*\/" ( asterisk + slash ). + * By default, {-onEach-} applies three parameters: element, key, container. If entity is primitive, then + * routine applies only element value, other parameters is undefined. + * + * @example + * _.entityIndexAppending( null ); + * // returns { 'null' : undefined } + * + * @example + * _.entityIndexAppending( null, ( el ) => el ); + * // returns { 'null' : null } + * + * @example + * _.entityIndexAppending( [ 1, 2, 3, 4 ] ); + * // returns { '0' : 1, '1' : 2, '2' : 3, '3' : 4 } + * + * @example + * _.entityIndexAppending( [ 1, 2, 3, 4 ], ( el, key ) => key > 2 ? key : 1 ); + * // returns { '1' : 3, '3' : 4 } + * + * @example + * _.entityIndexAppending( { a : 1, b : 1, c : 1 } ); + * // returns { a : 1, b : 1, c : 1 } + * + * @example + * _.entityIndexAppending( { a : 1, b : 2, c : 3 }, ( el, key, container ) => container.a > 0 ? key : el ); + * // returns { a : 1, b : 2, c : 3 } + * + * @example + * _.entityIndexAppending( { a : 1, b : 2, c : 3 }, ( el, key, container ) => { return { [ key ] : key, 'x' : el } } ); + * // returns { a : 'a', x : [ 1, 2, 3 ], b : 'b', c : 'c' } + * + * @example + * _.entityIndexAppending( { a : { f1 : 1, f2 : 3 }, b : { f1 : 1, f2 : 4 } }, '*\/f1' ); + * // returns { '1' : { f1 : 1, f2 : 4 } } + * + * @returns { PureMap } - Returns the pure map. Values of the map defined by elements of provided entity {-src-} + * and keys of defines by results of callback execution on corresponding elements. If the callback returns map + * with existed key, then routine appends new value to the previous. + * @function entityIndexAppending + * @throws { Error } If arguments.length is less then one or more then two. + * @throws { Error } If {-src-} has value undefined. + * @throws { Error } If {-onEach-} is not undefined, not a function, not a String. + * @throws { Error } If {-onEach-} is a String, but has not prefix '*\/' ( asterisk + slash ). + * @namespace Tools + */ + +let entityIndexAppending = _entityIndex_functor({ extendRoutine : _.mapExtendAppending }); + +// + +function _entityRemap_functor( fop ) +{ + + fop = _.routine.options( _entityRemap_functor, fop ); + + let extendRoutine = fop.extendRoutine; + + return function entityRemap( src, onEach ) + { + let result = Object.create( null ); + + if( onEach === undefined ) + onEach = function( e, k ) + { + if( e === undefined && extendRoutine ) + return { [ k ] : e }; + return e; + } + else if( _.strIs( onEach ) ) + { + let selector = onEach; + _.assert( _.routine.is( _.select ) ); + _.assert( _.strBegins( selector, '*/' ), () => `Selector should begins with "*/", but "${selector}" does not` ); + selector = _.strRemoveBegin( selector, '*/' ); + onEach = function( e, k ) + { + return _.select( e, selector ); + } + } + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.routine.is( onEach ) ); + _.assert( src !== undefined, 'Expects src' ); + + /* */ + + if( _.aux.is( src ) ) + { + + for( let k in src ) + { + let val = src[ k ]; + let r = onEach( val, k, src ); + extend( r, k ); + } + + } + else if( _.longIs( src ) ) + { + + for( let k = 0 ; k < src.length ; k++ ) + { + let val = src[ k ]; + let r = onEach( val, k, src ); + extend( r, k ); + } + + } + else + { + + let val = src; + let r = onEach( val, undefined, undefined ); + extend( r, undefined ); + + } + + return result; + + /* */ + + function extend( res, key ) + { + if( res === undefined ) + return; + + if( _.unrollIs( res ) ) + return res.forEach( ( res ) => extend( res, key ) ); + + if( extendRoutine === null ) + { + if( key !== undefined ) + result[ key ] = res; + } + else + { + if( _.aux.is( res ) ) + extendRoutine( result, res ); + else if( key !== undefined ) + result[ key ] = res; + } + + } + + } + +} + +_entityRemap_functor.defaults = +{ + extendRoutine : null, +} + +// + +/** + * The routine entityRemap() returns a new pure map. The keys of the map defined by keys of provided + * entity {-src-} and values defined by result of callback execution on the correspond elements. + * If callback returns undefined, then element will not exist in resulted map. + * + * @param { * } src - Any entity to make map of indexes. + * @param { String|Function } onEach - The callback executed on elements of entity. + * If {-onEach-} is not defined, then routine uses callback that returns map with pair key-value for Longs + * and maps or element for other types. + * If {-onEach-} is a string, then routine searches elements with equal key. String value should has + * prefix "*\/" ( asterisk + slash ). + * By default, {-onEach-} applies three parameters: element, key, container. If entity is primitive, then + * routine applies only element value, other parameters is undefined. + * + * @example + * _.entityRemap( null ); + * // returns {} + * + * @example + * _.entityRemap( null, ( el ) => el ); + * // returns {} + * + * @example + * _.entityRemap( [ 1, 2, 3, 4 ] ); + * // returns { '0' : 1, '1' : 2, '2' : 3, '3' : 4 } + * + * @example + * _.entityRemap( [ 1, 2, 3, 4 ], ( el, key ) => el + key ); + * // returns { '0' : 1, '1' : 3, '2' : 5, '3' : 7 } + * + * @example + * _.entityRemap( { a : 1, b : 2, c : 3 } ); + * // returns { a : 1, b : 2, c : 3 } + * + * @example + * _.entityRemap( { a : 1, b : 2, c : 3 }, ( el, key, container ) => container.a > 0 ? key : el ); + * // returns { a : 'a', b : 'b', c : 'c' } + * + * @example + * _.entityRemap( { a : { f1 : 1, f2 : 3 }, b : { f1 : 2, f2 : 4 } }, '*\/f1' ); + * // returns { a : 1, b : 2 } + * + * @returns { PureMap } - Returns the pure map. Keys of the map defined by keys of provided entity {-src-} + * and values defined by results of callback execution on corresponding elements. + * @function entityRemap + * @throws { Error } If arguments.length is less then one or more then two. + * @throws { Error } If {-src-} has value undefined. + * @throws { Error } If {-onEach-} is not undefined, not a function, not a String. + * @throws { Error } If {-onEach-} is a String, but has not prefix '*\/' ( asterisk + slash ). + * @namespace Tools + */ + +let entityRemap = _entityRemap_functor({ extendRoutine : null }); + +// + +/** + * The routine entityRemapSupplementing() returns a new pure map. The keys of the map defined by keys of provided + * entity {-src-} and values defined by result of callback execution on the correspond elements. + * If callback returns undefined, then element will not exist in resulted map. + * If callback returns map with key existed in resulted map, then routine does not change existed value. + * + * @param { * } src - Any entity to make map of indexes. + * @param { String|Function } onEach - The callback executed on elements of entity. + * If {-onEach-} is not defined, then routine uses callback that returns map with pair key-value for Longs + * and maps or element for other types. + * If {-onEach-} is a string, then routine searches elements with equal key. String value should has + * prefix "*\/" ( asterisk + slash ). + * By default, {-onEach-} applies three parameters: element, key, container. If entity is primitive, then + * routine applies only element value, other parameters is undefined. + * + * @example + * _.entityRemapSupplementing( null ); + * // returns {} + * + * @example + * _.entityRemapSupplementing( null, ( el ) => el ); + * // returns {} + * + * @example + * _.entityRemapSupplementing( [ 1, 2, 3, 4 ] ); + * // returns { '0' : 1, '1' : 2, '2' : 3, '3' : 4 } + * + * @example + * _.entityRemapSupplementing( [ 1, 2, 3, 4 ], ( el, key ) => el + key ); + * // returns { '0' : 1, '1' : 3, '2' : 5, '3' : 7 } + * + * @example + * _.entityRemapSupplementing( { a : 1, b : 2, c : 3 } ); + * // returns { a : 1, b : 2, c : 3 } + * + * @example + * _.entityRemapSupplementing( { a : 1, b : 2, c : 3 }, ( el, key, container ) => container.a > 0 ? key : el ); + * // returns { a : 'a', b : 'b', c : 'c' } + * + * @example + * _.entityRemapSupplementing( { a : 1, b : 2, c : 3 }, ( el, key, container ) => { return { [ key ] : el, x : el } } ); + * // returns { a : 1, x : 1, b : 2, c : 3 } + * + * @example + * _.entityRemapSupplementing( { a : { f1 : 1, f2 : 3 }, b : { f1 : 2, f2 : 4 } }, '*\/f1' ); + * // returns { a : 1, b : 2 } + * + * @returns { PureMap } - Returns the pure map. Keys of the map defined by keys of provided entity {-src-} + * and values defined by results of callback execution on corresponding elements. If the callback returns map + * with existed key, then routine does not replaces the previous value with the new one. + * @function entityRemapSupplementing + * @throws { Error } If arguments.length is less then one or more then two. + * @throws { Error } If {-src-} has value undefined. + * @throws { Error } If {-onEach-} is not undefined, not a function, not a String. + * @throws { Error } If {-onEach-} is a String, but has not prefix '*\/' ( asterisk + slash ). + * @namespace Tools + */ + + +let entityRemapSupplementing = _entityRemap_functor({ extendRoutine : _.props.supplement.bind( _.props ) }); + +// + +/** + * The routine entityRemapExtending() returns a new pure map. The keys of the map defined by keys of provided + * entity {-src-} and values defined by result of callback execution on the correspond elements. + * If callback returns undefined, then element will not exist in resulted map. + * If callback returns map with key existed in resulted map, then routine does change existed value to the new one. + * + * @param { * } src - Any entity to make map of indexes. + * @param { String|Function } onEach - The callback executed on elements of entity. + * If {-onEach-} is not defined, then routine uses callback that returns map with pair key-value for Longs + * and maps or element for other types. + * If {-onEach-} is a string, then routine searches elements with equal key. String value should has + * prefix "*\/" ( asterisk + slash ). + * By default, {-onEach-} applies three parameters: element, key, container. If entity is primitive, then + * routine applies only element value, other parameters is undefined. + * + * @example + * _.entityRemapExtending( null ); + * // returns {} + * + * @example + * _.entityRemapExtending( null, ( el ) => el ); + * // returns {} + * + * @example + * _.entityRemapExtending( [ 1, 2, 3, 4 ] ); + * // returns { '0' : 1, '1' : 2, '2' : 3, '3' : 4 } + * + * @example + * _.entityRemapExtending( [ 1, 2, 3, 4 ], ( el, key ) => el + key ); + * // returns { '0' : 1, '1' : 3, '2' : 5, '3' : 7 } + * + * @example + * _.entityRemapExtending( { a : 1, b : 2, c : 3 } ); + * // returns { a : 1, b : 2, c : 3 } + * + * @example + * _.entityRemapExtending( { a : 1, b : 2, c : 3 }, ( el, key, container ) => container.a > 0 ? key : el ); + * // returns { a : 'a', b : 'b', c : 'c' } + * + * @example + * _.entityRemapExtending( { a : 1, b : 2, c : 3 }, ( el, key, container ) => { return { [ key ] : el, x : el } } ); + * // returns { a : 1, x : 3, b : 2, c : 3 } + * + * @example + * _.entityRemapExtending( { a : { f1 : 1, f2 : 3 }, b : { f1 : 2, f2 : 4 } }, '*\/f1' ); + * // returns { a : 1, b : 2 } + * + * @returns { PureMap } - Returns the pure map. Keys of the map defined by keys of provided entity {-src-} + * and values defined by results of callback execution on corresponding elements. If the callback returns map + * with existed key, then routine replaces the previous value with the new one. + * @function entityRemapExtending + * @throws { Error } If arguments.length is less then one or more then two. + * @throws { Error } If {-src-} has value undefined. + * @throws { Error } If {-onEach-} is not undefined, not a function, not a String. + * @throws { Error } If {-onEach-} is a String, but has not prefix '*\/' ( asterisk + slash ). + * @namespace Tools + */ + +let entityRemapExtending = _entityRemap_functor({ extendRoutine : _.props.extend.bind( _.props ) }); + +// + +/** + * The routine entityRemapPrepending() returns a new pure map. The keys of the map defined by keys of provided + * entity {-src-} and values defined by result of callback execution on the correspond elements. + * If callback returns undefined, then element will not exist in resulted map. + * If callback returns map with key existed in resulted map, then routine prepends new values to the existed value. + * + * @param { * } src - Any entity to make map of indexes. + * @param { String|Function } onEach - The callback executed on elements of entity. + * If {-onEach-} is not defined, then routine uses callback that returns map with pair key-value for Longs + * and maps or element for other types. + * If {-onEach-} is a string, then routine searches elements with equal key. String value should has + * prefix "*\/" ( asterisk + slash ). + * By default, {-onEach-} applies three parameters: element, key, container. If entity is primitive, then + * routine applies only element value, other parameters is undefined. + * + * @example + * _.entityRemapPrepending( null ); + * // returns {} + * + * @example + * _.entityRemapPrepending( null, ( el ) => el ); + * // returns {} + * + * @example + * _.entityRemapPrepending( [ 1, 2, 3, 4 ] ); + * // returns { '0' : 1, '1' : 2, '2' : 3, '3' : 4 } + * + * @example + * _.entityRemapPrepending( [ 1, 2, 3, 4 ], ( el, key ) => el + key ); + * // returns { '0' : 1, '1' : 3, '2' : 5, '3' : 7 } + * + * @example + * _.entityRemapPrepending( { a : 1, b : 2, c : 3 } ); + * // returns { a : 1, b : 2, c : 3 } + * + * @example + * _.entityRemapPrepending( { a : 1, b : 2, c : 3 }, ( el, key, container ) => container.a > 0 ? key : el ); + * // returns { a : 'a', b : 'b', c : 'c' } + * + * @example + * _.entityRemapPrepending( { a : 1, b : 2, c : 3 }, ( el, key, container ) => { return { [ key ] : el, x : el } } ); + * // returns { a : 1, x : [ 3, 2, 1 ], b : 2, c : 3 } + * + * @example + * _.entityRemapPrepending( { a : { f1 : 1, f2 : 3 }, b : { f1 : 2, f2 : 4 } }, '*\/f1' ); + * // returns { a : 1, b : 2 } + * + * @returns { PureMap } - Returns the pure map. Keys of the map defined by keys of provided entity {-src-} + * and values defined by results of callback execution on corresponding elements. If the callback returns map + * with existed key, then routine prepends new values to the existed value. + * @function entityRemapPrepending + * @throws { Error } If arguments.length is less then one or more then two. + * @throws { Error } If {-src-} has value undefined. + * @throws { Error } If {-onEach-} is not undefined, not a function, not a String. + * @throws { Error } If {-onEach-} is a String, but has not prefix '*\/' ( asterisk + slash ). + * @namespace Tools + */ + +let entityRemapPrepending = _entityRemap_functor({ extendRoutine : _.mapExtendPrepending }); + +// + +/** + * The routine entityRemapAppending() returns a new pure map. The keys of the map defined by keys of provided + * entity {-src-} and values defined by result of callback execution on the correspond elements. + * If callback returns undefined, then element will not exist in resulted map. + * If callback returns map with key existed in resulted map, then routine appends new values to the existed value. + * + * @param { * } src - Any entity to make map of indexes. + * @param { String|Function } onEach - The callback executed on elements of entity. + * If {-onEach-} is not defined, then routine uses callback that returns map with pair key-value for Longs + * and maps or element for other types. + * If {-onEach-} is a string, then routine searches elements with equal key. String value should has + * prefix "*\/" ( asterisk + slash ). + * By default, {-onEach-} applies three parameters: element, key, container. If entity is primitive, then + * routine applies only element value, other parameters is undefined. + * + * @example + * _.entityRemapAppending( null ); + * // returns {} + * + * @example + * _.entityRemapAppending( null, ( el ) => el ); + * // returns {} + * + * @example + * _.entityRemapAppending( [ 1, 2, 3, 4 ] ); + * // returns { '0' : 1, '1' : 2, '2' : 3, '3' : 4 } + * + * @example + * _.entityRemapAppending( [ 1, 2, 3, 4 ], ( el, key ) => el + key ); + * // returns { '0' : 1, '1' : 3, '2' : 5, '3' : 7 } + * + * @example + * _.entityRemapAppending( { a : 1, b : 2, c : 3 } ); + * // returns { a : 1, b : 2, c : 3 } + * + * @example + * _.entityRemapAppending( { a : 1, b : 2, c : 3 }, ( el, key, container ) => container.a > 0 ? key : el ); + * // returns { a : 'a', b : 'b', c : 'c' } + * + * @example + * _.entityRemapAppending( { a : 1, b : 2, c : 3 }, ( el, key, container ) => { return { [ key ] : el, x : el } } ); + * // returns { a : 1, x : [ 3, 2, 1 ], b : 2, c : 3 } + * + * @example + * _.entityRemapAppending( { a : { f1 : 1, f2 : 3 }, b : { f1 : 2, f2 : 4 } }, '*\/f1' ); + * // returns { a : 1, b : 2 } + * + * @returns { PureMap } - Returns the pure map. Keys of the map defined by keys of provided entity {-src-} + * and values defined by results of callback execution on corresponding elements. If the callback returns map + * with existed key, then routine appends new values to the existed value. + * @function entityRemapAppending + * @throws { Error } If arguments.length is less then one or more then two. + * @throws { Error } If {-src-} has value undefined. + * @throws { Error } If {-onEach-} is not undefined, not a function, not a String. + * @throws { Error } If {-onEach-} is a String, but has not prefix '*\/' ( asterisk + slash ). + * @namespace Tools + */ + +let entityRemapAppending = _entityRemap_functor({ extendRoutine : _.mapExtendAppending }); + +// -- +// implementation +// -- + +let ToolsExtension = +{ + + // eachSample_, /* xxx : review */ + // eachPermutation_, /* xxx : move out */ + // swapsCount, /* xxx : move out */ + // _factorial, /* xxx : move out */ + // factorial, /* xxx : move out */ + + _entityFilterDeep, + entityFilterDeep, + filterDeep : entityFilterDeep, + + _entityIndex_functor, + entityIndex, + index : entityIndex, + entityIndexSupplementing, + indexSupplementing : entityIndexSupplementing, + entityIndexExtending, + indexExtending : entityIndexExtending, + entityIndexPrepending, + indexPrepending : entityIndexPrepending, + entityIndexAppending, + indexAppending : entityIndexAppending, + + _entityRemap_functor, + entityRemap, + remap : entityRemap, + entityRemapSupplementing, + remapSupplementing : entityRemapSupplementing, + entityRemapExtending, + remapExtending : entityRemapExtending, + entityRemapPrepending, + remapPrepending : entityRemapPrepending, + entityRemapAppending, + remapAppending : entityRemapAppending, + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Functional.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Functional_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Functional_s */ })(); + +/* */ /* begin of file Fuzzy_s */ ( function Fuzzy_s() { function Fuzzy_s_naked() { ( function _l7_Fuzzy_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.fuzzy = _.fuzzy || Object.create( null ); + +// -- +// fuzzy +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +// + +let Extension = +{ + +} + +Object.assign( _, ToolsExtension ); +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Fuzzy.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Fuzzy_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Fuzzy_s */ })(); + +/* */ /* begin of file Global_s */ ( function Global_s() { function Global_s_naked() { ( function _l7_Global_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.global = _.global || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +var Extension = +{ + +} + +// + +Object.assign( _.global, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Global.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Global_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Global_s */ })(); + +/* */ /* begin of file HashMap_s */ ( function HashMap_s() { function HashMap_s_naked() { ( function _l7_HashMap_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.hashMap = _.hashMap || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +// + +let Extension = +{ + +} + +Object.assign( _, ToolsExtension ); +Object.assign( _.hashMap, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/HashMap.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, HashMap_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file HashMap_s */ })(); + +/* */ /* begin of file Interval_s */ ( function Interval_s() { function Interval_s_naked() { ( function _l7_Interval_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// extension +// -- + +let Extension = +{ + +} + +// + +_.props.supplement( _, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Interval.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Interval_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Interval_s */ })(); + +/* */ /* begin of file Intervalc_s */ ( function Intervalc_s() { function Intervalc_s_naked() { ( function _l7_Intervalc_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.cinterval = _.cinterval || Object.create( null ); + +// -- +// +// -- + +// -- +// implementation +// -- + +let Extension = +{ +}; + +// + +_.props.supplement( _.cinterval, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Intervalc.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Intervalc_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Intervalc_s */ })(); + +/* */ /* begin of file Intervall_s */ ( function Intervall_s() { function Intervall_s_naked() { ( function _l7_Intervall_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.linterval = _.linterval || Object.create( null ); + +// -- +// +// -- + +// -- +// +// -- + +let Extension = +{ +}; + +// + +_.props.supplement( _.linterval, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Intervall.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Intervall_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Intervall_s */ })(); + +/* */ /* begin of file Intervalo_s */ ( function Intervalo_s() { function Intervalo_s_naked() { ( function _l7_Intervalo_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.ointerval = _.ointerval || Object.create( null ); + +// -- +// +// -- + +// -- +// implementation +// -- + +let Extension = +{ +}; + +// + +_.props.supplement( _.ointerval, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Intervalo.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Intervalo_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Intervalo_s */ })(); + +/* */ /* begin of file Introspector_s */ ( function Introspector_s() { function Introspector_s_naked() { ( function _l7_Introspector_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global.wTools; +_.introspector = _.introspector || Object.create( null ); + +// -- +// diagnostics +// -- + +let _diagnosticCodeExecuting = 0; +function code( o ) +{ + + _.routine.options( code, o ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( _diagnosticCodeExecuting ) + return; + _diagnosticCodeExecuting += 1; + + try + { + + if( !o.location ) + { + if( o.error ) + o.location = _.introspector.location({ error : o.error, level : o.level }); + else + o.location = _.introspector.location({ stack : o.stack, level : o.stack ? o.level : o.level+1 }); + } + + if( !_.number.is( o.location.line ) ) + return end(); + + /* */ + + if( !o.sourceCode ) + { + + if( !o.location.filePath ) + return end(); + + let codeProvider = _.codeProvider || _.fileProvider; + if( !codeProvider && _globals_.testing && _globals_.testing.wTools ) + codeProvider = _globals_.testing.wTools.codeProvider || _globals_.testing.wTools.fileProvider; + + if( !codeProvider ) + return end(); + + try + { + + let filePath = codeProvider.path.normalizeTolerant( o.location.filePath ); + if( codeProvider.path.isAbsolute( filePath ) ) + o.sourceCode = read( codeProvider, filePath ); + + } + catch( err ) + { + o.sourceCode = ` ! Cant load source code of "${ o.location.filePath }"`; + } + + if( !o.sourceCode ) + return end(); + + } + + /* */ + + let code = _.strLinesSelect + ({ + src : o.sourceCode, + line : o.location.line, + nearestLines : o.nearestLines, + selectMode : o.selectMode, + zeroLine : 1, + numbering : 1, + }); + + if( code && _.strLinesIndentation && o.identation ) + code = o.identation + _.strLinesIndentation( code, o.identation ); + + let result = code; + if( o.withPath ) + { + if( o.asMap ) + result = { path : o.location.filePathLineCol, code }; + else + result = o.location.filePathLineCol + '\n' + code; + } + + return end( result ); + } + catch( err ) + { + console.log( err.toString() ); + return; + } + + /* */ + + function end( result ) + { + _diagnosticCodeExecuting -= 1; + return result; + } + + /* */ + + function read( codeProvider, filePath ) + { + let result = codeProvider.fileRead + ({ + filePath, + sync : 1, + throwing : 0, + }); + return result; + } + + /* */ + +} + +code.defaults = +{ + level : 0, + nearestLines : 5, + withPath : 1, + asMap : 0, + selectMode : 'center', + identation : null, + stack : null, + error : null, + location : null, + sourceCode : null, +} + +// + +function memoryUsageInfo() +{ + var usage = process.memoryUsage(); + return ( usage.heapUsed >> 20 ) + ' / ' + ( usage.heapTotal >> 20 ) + ' / ' + ( usage.rss >> 20 ) + ' Mb'; +} + +// -- +// declare +// -- + +let Extension = +{ + + code, + memoryUsageInfo, + +} + +Object.assign( _.introspector, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Introspector.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Introspector_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Introspector_s */ })(); + +/* */ /* begin of file Logic_s */ ( function Logic_s() { function Logic_s_naked() { ( function _l7_Logic_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// logic extension +// -- + +let LogicExtension = +{ + +} + +Object.assign( _.logic, LogicExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Logic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Logic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Logic_s */ })(); + +/* */ /* begin of file Long_s */ ( function Long_s() { function Long_s_naked() { ( function _l7_Long_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// + +const _ArrayIndexOf = Array.prototype.indexOf; +const _ArrayLastIndexOf = Array.prototype.lastIndexOf; +const _ArraySlice = Array.prototype.slice; +const _ArraySplice = Array.prototype.splice; +const _FunctionBind = Function.prototype.bind; +const _ObjectToString = Object.prototype.toString; +const _ObjectPropertyIsEumerable = Object.propertyIsEnumerable; + +// -- +// long transformer +// -- + +/** + * The routine longOnce() returns the {-dstLong-} with the duplicated elements removed. + * The {-dstLong-} instance will be returned when possible, if not a new instance of the same type is created. + * + * @param { Long } dstLong - The source and destination Long. + * @param { Function } onEvaluate - A callback function. + * + * @example + * _.longOnce( [ 1, 1, 2, 'abc', 'abc', 4, true, true ] ); + * // returns [ 1, 2, 'abc', 4, true ] + * + * @example + * _.longOnce( [ 1, 2, 3, 4, 5 ] ); + * // returns [ 1, 2, 3, 4, 5 ] + * + * @example + * _.longOnce( [ { v : 1 },{ v : 1 }, { v : 1 } ], ( e ) => e.v ); + * // returns [ { v : 1 } ] + * + * @example + * _.longOnce( [ { v : 1 },{ v : 1 }, { v : 1 } ], ( e ) => e.k ); + * // returns [ { v : 1 },{ v : 1 }, { v : 1 } ] + * + * @returns { Long } - If it is possible, returns the source Long without the duplicated elements. + * Otherwise, returns copy of the source Long without the duplicated elements. + * @function longOnce + * @throws { Error } If passed arguments is less than one or more than two. + * @throws { Error } If the first argument is not an long. + * @throws { Error } If the second argument is not a Routine. + * @namespace Tools + */ + +function longOnce( dstLong, onEvaluate ) +{ + _.assert( 1 <= arguments.length || arguments.length <= 2 ); + _.assert( _.longIs( dstLong ), 'Expects Long' ); + + if( _.arrayIs( dstLong ) ) + return _.arrayRemoveDuplicates( dstLong, onEvaluate ); + + if( !dstLong.length ) + return dstLong; + + let length = dstLong.length; + + for( let i = 0; i < dstLong.length; i++ ) + if( _.longLeftIndex( dstLong, dstLong[ i ], i+1, onEvaluate ) !== -1 ) + length--; + + if( length === dstLong.length ) + return dstLong; + + let result = _.long.makeUndefined( dstLong, length ); + result[ 0 ] = dstLong[ 0 ]; + + let j = 1; + for( let i = 1; i < dstLong.length && j < length; i++ ) + if( _.longRightIndex( result, dstLong[ i ], j-1, onEvaluate ) === -1 ) + result[ j++ ] = dstLong[ i ]; + + _.assert( j === length ); + + return result; +} + +// + +function longOnce_( dstLong, srcLong, onEvaluate ) +{ + _.assert( dstLong === null || _.longIs( dstLong ), 'Expects Long' ); + + if( dstLong === null ) + { + if( _.longIs( srcLong ) ) + dstLong = _.long.makeUndefined( srcLong, 0 ); + else + return []; + } + if( arguments.length === 1 ) + { + srcLong = dstLong; + } + else if( arguments.length === 2 ) + { + if( _.routine.is( srcLong ) ) + { + onEvaluate = arguments[ 1 ]; + srcLong = arguments[ 0 ]; + } + } + else if( arguments.length !== 3 ) + _.assert( 0 ); + + _.assert( _.longIs( srcLong ) ); + + let result; + + if( dstLong === srcLong ) + { + if( !dstLong.length ) + return dstLong; + + if( _.arrayIs( dstLong ) ) + return _.arrayRemoveDuplicates( dstLong, onEvaluate ); + + let length = dstLong.length; + + for( let i = 0; i < dstLong.length; i++ ) + if( _.longLeftIndex( dstLong, dstLong[ i ], i + 1, onEvaluate ) !== -1 ) + length--; + + if( length === dstLong.length ) + return dstLong; + + result = _.long.makeUndefined( dstLong, length ); + result[ 0 ] = dstLong[ 0 ]; + + let j = 1; + for( let i = 1; i < dstLong.length && j < length; i++ ) + if( _.longRightIndex( result, dstLong[ i ], j - 1, onEvaluate ) === -1 ) + result[ j++ ] = dstLong[ i ]; + + _.assert( j === length ); + } + else + { + if( _.arrayIs( dstLong ) ) + { + result = _.arrayAppendArrayOnce( dstLong, srcLong, onEvaluate ); + } + else + { + let length = srcLong.length + dstLong.length; + + for( let i = 0; i < srcLong.length; i++ ) + if + ( + _.longLeftIndex( dstLong, srcLong[ i ], onEvaluate ) !== -1 + || _.longLeftIndex( srcLong, srcLong[ i ], i + 1, onEvaluate ) !== -1 + ) + length--; + + if( length === dstLong.length ) + return dstLong; + + result = _.long.makeUndefined( dstLong, length ); + + for( let i = 0; i < dstLong.length; i++ ) + result[ i ] = dstLong[ i ] + + let offset = dstLong.length; + for( let i = dstLong.length ; i < result.length && offset >= -result.length ; ) + { + if( _.longLeftIndex( result, srcLong[ i - offset ], onEvaluate ) === -1 ) + { + result[ i ] = srcLong[ i - offset ]; + i++; + } + else + { + offset--; + } + } + } + } + + + return result; +} + +// + +function longHasUniques( o ) +{ + + if( _.longIs( o ) ) + o = { src : o }; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.longIs( o.src ) ); + _.map.assertHasOnly( o, longHasUniques.defaults ); + + /* */ + + // if( o.onEvaluate ) + // { + // o.src = _.entity.map_( null, o.src, ( e ) => o.onEvaluate( e ) ); + // } + + /* */ + + let number = o.src.length; + let isUnique = []; + let index; + + for( let i = 0 ; i < o.src.length ; i++ ) + isUnique[ i ] = 1; + + for( let i = 0 ; i < o.src.length ; i++ ) + { + index = i; + + if( !isUnique[ i ] ) + continue; + + let currentUnique = 1; + index = _.longLeftIndex( o.src, o.src[ i ], index+1, o.onEvaluate ); + if( index >= 0 ) + do + { + isUnique[ index ] = 0; + number -= 1; + currentUnique = 0; + index = _.longLeftIndex( o.src, o.src[ i ], index+1, o.onEvaluate ); + } + while( index >= 0 ); + + // if( currentUnique && o.src2 ) + // do + // { + // index = o.src2.indexOf( o.src2[ i ], index+1 ); + // if( index !== -1 ) + // currentUnique = 0; + // } + // while( index !== -1 ); + + if( !o.includeFirst ) + if( !currentUnique ) + { + isUnique[ i ] = 0; + number -= 1; + } + + } + + return { number, is : isUnique }; +} + +longHasUniques.defaults = +{ + src : null, + // src2 : null, + onEvaluate : null, + includeFirst : 0, +} + +// + +function longAreRepeatedProbe( srcArray, onEvaluate ) +{ + let isUnique = _.long.makeUndefined( srcArray ); + let result = Object.create( null ); + result.array = _.array.make( srcArray.length ); + result.uniques = srcArray.length; + result.condensed = srcArray.length; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.longIs( srcArray ) ); + + for( let i = 0 ; i < srcArray.length ; i++ ) + { + let element = srcArray[ i ]; + + if( result.array[ i ] > 0 ) + continue; + + result.array[ i ] = 0; + + let left = _.longLeftIndex( srcArray, element, i+1, onEvaluate ); + if( left >= 0 ) + { + result.array[ i ] = 1; + result.uniques -= 1; + do + { + result.uniques -= 1; + result.condensed -= 1; + result.array[ left ] = 1; + left = _.longLeftIndex( srcArray, element, left+1, onEvaluate ); + } + while( left >= 0 ); + } + + } + + return result; + +} + +// + +function longAllAreRepeated( src, onEvalutate ) +{ + let areRepated = _.longAreRepeatedProbe.apply( this, arguments ); + return !areRepated.uniques; +} + +// + +function longAnyAreRepeated( src, onEvalutate ) +{ + let areRepated = _.longAreRepeatedProbe.apply( this, arguments ); + return areRepated.uniques !== src.length; +} + +// + +function longNoneAreRepeated( src, onEvalutate ) +{ + let areRepated = _.longAreRepeatedProbe.apply( this, arguments ); + return areRepated.uniques === src.length; +} + +// + +/** + * The longMask() routine returns a new instance of array that contains the certain value(s) from array (srcArray), + * if an array (mask) contains the truth-value(s). + * + * The longMask() routine checks, how much an array (mask) contain the truth value(s), + * and from that amount of truth values it builds a new array, that contains the certain value(s) of an array (srcArray), + * by corresponding index(es) (the truth value(s)) of the array (mask). + * If amount is equal 0, it returns an empty array. + * + * @param { longIs } srcArray - The source array. + * @param { longIs } mask - The target array. + * + * @example + * _.longMask( [ 1, 2, 3, 4 ], [ undefined, null, 0, '' ] ); + * // returns [] + * + * @example + * _longMask( [ 'a', 'b', 'c', 4, 5 ], [ 0, '', 1, 2, 3 ] ); + * // returns [ "c", 4, 5 ] + * + * @example + * _.longMask( [ 'a', 'b', 'c', 4, 5, 'd' ], [ 3, 7, 0, '', 13, 33 ] ); + * // returns [ 'a', 'b', 5, 'd' ] + * + * @returns { longIs } Returns a new instance of array that contains the certain value(s) from array (srcArray), + * if an array (mask) contains the truth-value(s). + * If (mask) contains all falsy values, it returns an empty array. + * Otherwise, it returns a new array with certain value(s) of an array (srcArray). + * @function longMask + * @throws { Error } Will throw an Error if (arguments.length) is less or more that two. + * @throws { Error } Will throw an Error if (srcArray) is not an array-like. + * @throws { Error } Will throw an Error if (mask) is not an array-like. + * @throws { Error } Will throw an Error if length of both (srcArray and mask) is not equal. + * @namespace Tools + */ + +function longMask( srcArray, mask ) +{ + + let scalarsPerElement = mask.length; + let length = srcArray.length / scalarsPerElement; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.longIs( srcArray ), 'longMask :', 'Expects array-like as srcArray' ); + _.assert( _.longIs( mask ), 'longMask :', 'Expects array-like as mask' ); + _.assert + ( + _.intIs( length ), + 'longMask :', 'Expects mask that has component for each atom of srcArray', + _.entity.exportString + ({ + scalarsPerElement, + 'srcArray.length' : srcArray.length, + }) + ); + + let preserve = 0; + for( let m = 0 ; m < mask.length ; m++ ) + if( mask[ m ] ) + preserve += 1; + + // let dstArray = new srcArray.constructor( length*preserve ); + let dstArray = _.long.makeUndefined( srcArray, length*preserve ); + + if( !preserve ) + return dstArray; + + let c = 0; + for( let i = 0 ; i < length ; i++ ) + for( let m = 0 ; m < mask.length ; m++ ) + if( mask[ m ] ) + { + dstArray[ c ] = srcArray[ i*scalarsPerElement + m ]; + c += 1; + } + + return dstArray; +} + +// + +function longUnmask( o ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( arguments.length === 2 ) + o = + { + src : arguments[ 0 ], + mask : arguments[ 1 ], + } + + _.map.assertHasOnly( o, longUnmask.defaults ); + _.assert( _.longIs( o.src ), 'Expects o.src as ArrayLike' ); + + let scalarsPerElement = o.mask.length; + + let scalarsPerElementPreserved = 0; + for( let m = 0 ; m < o.mask.length ; m++ ) + if( o.mask[ m ] ) + scalarsPerElementPreserved += 1; + + let length = o.src.length / scalarsPerElementPreserved; + if( Math.floor( length ) !== length ) + throw _.err + ( + 'longMask :', + 'Expects mask that has component for each atom of o.src', + _.entity.exportString({ scalarsPerElementPreserved, 'o.src.length' : o.src.length }) + ); + + let dstArray = _.long.makeUndefined( o.src, scalarsPerElement*length ); + // let dstArray = new o.src.constructor( scalarsPerElement*length ); + + let e = []; + for( let i = 0 ; i < length ; i++ ) + { + + for( let m = 0, p = 0 ; m < o.mask.length ; m++ ) + if( o.mask[ m ] ) + { + e[ m ] = o.src[ i*scalarsPerElementPreserved + p ]; + p += 1; + } + else + { + e[ m ] = 0; + } + + if( o.onEach ) + o.onEach( e, i ); + + for( let m = 0 ; m < o.mask.length ; m++ ) + dstArray[ i*scalarsPerElement + m ] = e[ m ]; + + } + + return dstArray; +} + +longUnmask.defaults = +{ + src : null, + mask : null, + onEach : null, +} + +// -- +// array maker +// -- + +/** + * The routine longRandom() returns an array which contains random numbers. + * + * Routine accepts one or three arguments. + * Optionally, routine can accepts one of two sets of parameters. First of them + * is one or three arguments, the other is options map. + * + * Set 1: + * @param { ArrayLike } dst - The destination array. + * @param { Range|Number } range - The range for generating random numbers. + * If {-range-} is number, routine makes range [ range, range ]. + * @param { Number|Range } length - The quantity of generated random numbers. + * If dst.length < {-length-}, then routine makes new container of {-dst-} type. + * If {-length-} is Range, then routine choose random lenght from provided range. + * + * Set 2: + * @param { Object } o - The options map. Options map includes next fields: + * @param { Function } o.onEach - The callback for generating random numbers. + * Accepts three parameters - range, index of element, source container. + * @param { ArrayLike } o.dst - The destination array. + * @param { Range|Number } o.range - The range for generating random numbers. + * If {-range-} is number, routine makes range [ range, range ]. + * @param { Number|Range } o.length - The length of an array. + * If dst.length < length, then routine makes new container of {-dst-} type. + * If {-length-} is Range, then routine choose random lenght from provided range. + * + * @example + * let got = _.longRandom( 3 ); + * // returns array with three elements in range [ 0, 1 ] + * console.log( got ); + * // log [ 0.2054268445, 0.8651654684, 0.5564687461 ] + * + * @example + * let dst = [ 0, 0, 0 ]; + * let got _.longRandom( dst, [ 1, 5 ], 3 ); + * // returns dst array with three elements in range [ 1, 5 ] + * console.log( got ); + * // log [ 4.9883513548, 1.2313468546, 3.8973544247 ] + * console.log( got === dst ); + * // log true + * + * @example + * let dst = [ 0, 0, 0 ]; + * let got _.longRandom( dst, [ 1, 5 ], 4 ); + * // returns dst array with three elements in range [ 1, 5 ] + * console.log( got ); + * // log [ 4.9883513548, 1.2313468546, 3.8973544247, 2.6782254287 ] + * console.log( got === dst ); + * // log false + * + * @example + * _.longRandom + * ({ + * length : 5, + * range : [ 1, 10 ], + * onEach : ( range ) => _.intRandom( range ), + * }); + * // returns [ 6, 2, 4, 7, 8 ] + * + * @example + * let dst = [ 0, 0, 0, 0, 0 ] + * var got = _.longRandom + * ({ + * length : 3, + * range : [ 1, 10 ], + * onEach : ( range ) => _.intRandom( range ), + * }); + * console.log( got ); + * // log [ 1, 10, 4, 0, 0 ] + * console.log( got === dst ); + * // log true + * + * @returns { ArrayLike } - Returns an array of random numbers. + * @function longRandom + * @throws { Error } If arguments.length === 0, arguments.length === 2, arguments.lenght > 3. + * @throws { Error } If arguments.length === 1, and passed argument is not options map {-o-} or {-length-}. + * @throws { Error } If options map {-o-} has unnacessary fields. + * @throws { Error } If {-dst-} or {-o.dst-} is not ArrayLike. + * @throws { Error } If {-range-} or {-o.range-} is not Range or not Number. + * @throws { Error } If {-length-} or {-o.length-} is not Number or not Range. + * @throws { Error } If {-o.onEach-} is not routine. + * @namespace Tools + */ + +function longRandom( o ) +{ + + if( arguments[ 2 ] !== undefined ) + o = { dst : arguments[ 0 ], value : arguments[ 1 ], length : arguments[ 2 ] } + else if( _.number.is( o ) || _.intervalIs( o ) ) + o = { length : o } + _.assert( arguments.length === 1 || arguments.length === 3 ); + _.routine.options( longRandom, o ); + + if( o.onEach === null ) + o.onEach = ( value ) => _.number.random( value ); + + if( o.value === null ) + o.value = [ 0, 1 ]; + if( _.number.is( o.value ) ) + o.value = [ 0, o.value ] + // o.value = [ o.value, o.value ] + + if( _.intervalIs( o.length ) ) + o.length = _.intRandom( o.length ); + if( o.length === null && o.dst ) + o.length = o.dst.length; + if( o.length === null ) + o.length = 1; + + _.assert( _.intIs( o.length ) ); + + if( o.dst === null || o.dst.length < o.length ) + o.dst = _.long.make( o.dst, o.length ); + + for( let i = 0 ; i < o.length ; i++ ) + { + o.dst[ i ] = o.onEach( o.value, i, o ); + } + + return o.dst; +} + +longRandom.defaults = +{ + dst : null, + onEach : null, + value : null, + length : null, +} + +// + +/** + * The longFromRange() routine generate array of arithmetic progression series, + * from the range[ 0 ] to the range[ 1 ] with increment 1. + * + * It iterates over loop from (range[0]) to the (range[ 1 ] - range[ 0 ]), + * and assigns to the each index of the (result) array (range[ 0 ] + 1). + * + * @param { longIs } range - The first (range[ 0 ]) and the last (range[ 1 ] - range[ 0 ]) elements of the progression. + * + * @example + * _.longFromRange( [ 1, 5 ] ); + * // returns [ 1, 2, 3, 4 ] + * + * @example + * _.longFromRange( 5 ); + * // returns [ 0, 1, 2, 3, 4 ] + * + * @returns { array } Returns an array of numbers for the requested range with increment 1. + * May be an empty array if adding the step would not converge toward the end value. + * @function longFromRange + * @throws { Error } If passed arguments is less than one or more than one. + * @throws { Error } If the first argument is not an array-like object. + * @throws { Error } If the length of the (range) is not equal to the two. + * @namespace Tools + */ + +function longFromRange( range ) +{ + + if( _.number.is( range ) ) + range = [ 0, range ]; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( range.length === 2 ); + _.assert( _.longIs( range ) ); + + let step = range[ 0 ] <= range[ 1 ] ? +1 : -1; + + return this.longFromRangeWithStep( range, step ); +} + +// + +function longFromProgressionArithmetic( progression, numberOfSteps ) +{ + let result; /* zzz : review */ + + debugger; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.longIs( progression ) ) + _.assert( isFinite( progression[ 0 ] ) ); + _.assert( isFinite( progression[ 1 ] ) ); + _.assert( isFinite( numberOfSteps ) ); + _.assert( _.routine.is( this.tools.long.default.from ) ); + + debugger; + + if( numberOfSteps === 0 ) + return this.tools.long.default.from(); + + if( numberOfSteps === 1 ) + return this.tools.long.default.from([ progression[ 0 ] ]); + + let range = [ progression[ 0 ], progression[ 0 ]+progression[ 1 ]*(numberOfSteps+1) ]; + let step = ( range[ 1 ]-range[ 0 ] ) / ( numberOfSteps-1 ); + + return this.longFromRangeWithStep( range, step ); +} + +// + +function longFromRangeWithStep( range, step ) +{ + let result; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( isFinite( range[ 0 ] ) ); + _.assert( isFinite( range[ 1 ] ) ); + _.assert( step === undefined || step < 0 || step > 0 ); + _.assert( _.routine.is( this.tools.long.default.from ) ); + + if( range[ 0 ] === range[ 1 ] ) + return this.long.default.make(); + // return this.tools.long.default.from(); + + if( range[ 0 ] < range[ 1 ] ) + { + + if( step === undefined ) + step = 1; + + _.assert( step > 0 ); + + // debugger; + result = this.long.default.from( Math.round( ( range[ 1 ]-range[ 0 ] ) / step ) ); + // result = this.tools.long.default.from( Math.round( ( range[ 1 ]-range[ 0 ] ) / step ) ); + + let i = 0; + while( range[ 0 ] < range[ 1 ] ) + { + result[ i ] = range[ 0 ]; + range[ 0 ] += step; + i += 1; + } + + } + else + { + + if( step === undefined ) + step = -1; + + _.assert( step < 0 ); + + // result = this.tools.long.default.from( Math.round( ( range[ 1 ]-range[ 0 ] ) / step ) ); // Dmytro it's more optimal, range[ 0 ] > range[ 1 ] and step < 0 so result will be positive number + result = this.long.default.from( Math.abs( Math.round( ( range[ 0 ]-range[ 1 ] ) / step ) ) ); + // result = this.tools.long.default.from( Math.abs( Math.round( ( range[ 0 ]-range[ 1 ] ) / step ) ) ); + + let i = 0; + while( range[ 0 ] > range[ 1 ] ) + { + result[ i ] = range[ 0 ]; + range[ 0 ] += step; + i += 1; + } + + } + + return result; +} + +// + +function longFromRangeWithNumberOfSteps( range, numberOfSteps ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( isFinite( range[ 0 ] ) ); + _.assert( isFinite( range[ 1 ] ) ); + _.assert( numberOfSteps >= 0 ); + _.assert( _.routine.is( this.tools.long.default.from ) ); + + if( numberOfSteps === 0 ) + return this.tools.long.default.from(); + + if( numberOfSteps === 1 ) + return this.tools.long.default.from( range[ 0 ] ); + + let step; + + if( range[ 0 ] < range[ 1 ] ) + step = ( range[ 1 ]-range[ 0 ] ) / (numberOfSteps-1); + else + step = ( range[ 0 ]-range[ 1 ] ) / (numberOfSteps-1); + + return this.longFromRangeWithStep( range, step ); +} + +// -- +// array converter +// -- + +/** + * The longToMap() converts an (array) into Object. + * + * @param { longIs } array - To convert into Object. + * + * @example + * _.longToMap( [] ); + * // returns {} + * + * @example + * _.longToMap( [ 3, [ 1, 2, 3 ], 'abc', false, undefined, null, {} ] ); + * // returns { '0' : 3, '1' : [ 1, 2, 3 ], '2' : 'abc', '3' : false, '4' : undefined, '5' : null, '6' : {} } + * + * @example + * let args = ( function() { + * return arguments; + * } )( 3, 'abc', false, undefined, null, { greeting: 'Hello there!' } ); + * _.longToMap( args ); + * // returns { '0' : 3, '1' : 'abc', '2' : false, '3' : undefined, '4' : null, '5' : { greeting: 'Hello there!' } } + * + * @returns { Object } Returns an Object. + * @function longToMap + * @throws { Error } Will throw an Error if (array) is not an array-like. + * @namespace Tools + */ + +function longToMap( array ) +{ + let result = Object.create( null ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.longIs( array ) ); + + for( let a = 0 ; a < array.length ; a++ ) + result[ a ] = array[ a ]; + return result; +} +// +// // +// +// /** +// * The longToStr() routine joins an array {-srcMap-} and returns one string containing each array element separated by space, +// * only types of integer or floating point. +// * +// * @param { longIs } src - The source array. +// * @param { objectLike } [ options = { } ] options - The options. +// * @param { Number } [ options.precision = 5 ] - The precision of numbers. +// * @param { String } [ options.type = 'mixed' ] - The type of elements. +// * +// * @example +// * _.longToStr( [ 1, 2, 3 ], { type : 'int' } ); +// * // returns "1 2 3 " +// * +// * @example +// * _.longToStr( [ 3.5, 13.77, 7.33 ], { type : 'float', precission : 4 } ); +// * // returns "3.500 13.77 7.330" +// * +// * @returns { String } Returns one string containing each array element separated by space, +// * only types of integer or floating point. +// * If (src.length) is empty, it returns the empty string. +// * @function longToStr +// * @throws { Error } Will throw an Error If (options.type) is not the number or float. +// * @namespace Tools +// */ +// +// function longToStr( src, options ) +// { +// +// let result = ''; +// options = options || Object.create( null ); +// +// if( options.precission === undefined ) options.precission = 5; +// if( options.type === undefined ) options.type = 'mixed'; +// +// if( !src.length ) return result; +// +// if( options.type === 'float' ) +// { +// for( var s = 0 ; s < src.length-1 ; s++ ) +// { +// result += src[ s ].toPrecision( options.precission ) + ' '; +// } +// result += src[ s ].toPrecision( options.precission ); +// } +// else if( options.type === 'int' ) +// { +// for( var s = 0 ; s < src.length-1 ; s++ ) +// { +// result += String( src[ s ] ) + ' '; +// } +// result += String( src[ s ] ) + ' '; +// } +// else +// { +// throw _.err( 'not tested' ); +// for( let s = 0 ; s < src.length-1 ; s++ ) +// { +// result += String( src[ s ] ) + ' '; +// } +// result += String( src[ s ] ) + ' '; +// } +// +// return result; +// } + +// -- +// array transformer +// -- + +/** + * The longOnlyWithIndices() routine selects elements from (srcArray) by indexes of (indicesArray). + * + * @param { longIs } srcArray - Values for the new array. + * @param { ( longIs | object ) } [ indicesArray = indicesArray.indices ] - Indexes of elements from the (srcArray) or options map. + * + * @example + * _.longOnlyWithIndices( [ 1, 2, 3, 4, 5 ], [ 2, 3, 4 ] ); + * // returns [ 3, 4, 5 ] + * + * @example + * _.longOnlyWithIndices( [ 1, 2, 3 ], [ 4, 5 ] ); + * // returns [ undefined, undefined ] + * + * @returns { longIs } - Returns a new array with the length equal (indicesArray.length) and elements from (srcArray). + If there is no element with necessary index than the value will be undefined. + * @function longOnlyWithIndices + * @throws { Error } If passed arguments is not array like object. + * @throws { Error } If the scalarsPerElement property is not equal to 1. + * @namespace Tools + */ + +function longOnlyWithIndices( srcArray, indicesArray ) +{ + let scalarsPerElement = 1; + + if( _.object.isBasic( indicesArray ) ) + { + scalarsPerElement = indicesArray.scalarsPerElement || 1; + indicesArray = indicesArray.indices; + } + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.longIs( srcArray ) ); + _.assert( _.longIs( indicesArray ) ); + + // let result = new srcArray.constructor( indicesArray.length ); + let result = _.long.makeUndefined( srcArray, indicesArray.length ); + + if( scalarsPerElement === 1 ) + for( let i = 0, l = indicesArray.length ; i < l ; i += 1 ) + { + result[ i ] = srcArray[ indicesArray[ i ] ]; + } + else + for( let i = 0, l = indicesArray.length ; i < l ; i += 1 ) + { + for( let a = 0 ; a < scalarsPerElement ; a += 1 ) + result[ i*scalarsPerElement+a ] = srcArray[ indicesArray[ i ]*scalarsPerElement+a ]; + } + + return result; +} + +// -- +// long mutator +// -- + +function longShuffle( dst, times ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.longIs( dst ) ); + + if( times === undefined ) + times = dst.length; + + let l = dst.length; + let e1, e2; + for( let t1 = 0 ; t1 < times ; t1++ ) + { + let t2 = Math.floor( Math.random() * l ); + e1 = dst[ t1 ]; + e2 = dst[ t2 ]; + dst[ t1 ] = e2; + dst[ t2 ] = e1; + } + + return dst; +} + +// -- +// array mutator +// -- + +// function longAssign( dst, index, value ) +// { +// _.assert( arguments.length === 3, 'Expects exactly three arguments' ); +// _.assert( dst.length > index ); +// dst[ index ] = value; +// return dst; +// } + +// + +/** + * The longSwapElements() routine reverses the elements by indices (index1) and (index2) in the (dst) array. + * + * @param { Array } dst - The initial array. + * @param { Number } index1 - The first index. + * @param { Number } index2 - The second index. + * + * @example + * _.longSwapElements( [ 1, 2, 3, 4, 5 ], 0, 4 ); + * // returns [ 5, 2, 3, 4, 1 ] + * + * @returns { Array } - Returns the (dst) array that has been modified in place by indexes (index1) and (index2). + * @function longSwapElements + * @throws { Error } If the first argument in not an array. + * @throws { Error } If the second argument is less than 0 and more than a length initial array. + * @throws { Error } If the third argument is less than 0 and more than a length initial array. + * @namespace Tools + */ + +function longSwapElements( dst, index1, index2 ) +{ + + if( arguments.length === 1 ) + { + index1 = 0; + index2 = 1; + } + + _.assert( arguments.length === 1 || arguments.length === 3 ); + _.assert( _.longIs( dst ), 'Expects long' ); + _.assert( 0 <= index1 && index1 < dst.length > 0, 'index1 is out of bound' ); + _.assert( 0 <= index2 && index2 < dst.length > 0, 'index2 is out of bound' ); + + let e = dst[ index1 ]; + dst[ index1 ] = dst[ index2 ]; + dst[ index2 ] = e; + + return dst; +} + +// + +/** + * The longPut() routine puts all values of (arguments[]) after the second argument to the (dstArray) + * in the position (dstOffset) and changes values of the following index. + * + * @param { longIs } dstArray - The source array. + * @param { Number } [ dstOffset = 0 ] dstOffset - The index of element where need to put the new values. + * @param {*} arguments[] - One or more argument(s). + * If the (argument) is an array it iterates over array and adds each element to the next (dstOffset++) index of the (dstArray). + * Otherwise, it adds each (argument) to the next (dstOffset++) index of the (dstArray). + * + * @example + * _.longPut( [ 1, 2, 3, 4, 5, 6, 9 ], 2, 'str', true, [ 7, 8 ] ); + * // returns [ 1, 2, 'str', true, 7, 8, 9 ] + * + * @example + * _.longPut( [ 1, 2, 3, 4, 5, 6, 9 ], 0, 'str', true, [ 7, 8 ] ); + * // returns [ 'str', true, 7, 8, 5, 6, 9 ] + * + * @returns { longIs } - Returns an array containing the changed values. + * @function longPut + * @throws { Error } Will throw an Error if (arguments.length) is less than one. + * @throws { Error } Will throw an Error if (dstArray) is not an array-like. + * @throws { Error } Will throw an Error if (dstOffset) is not a Number. + * @namespace Tools + */ + +function longPut( dstArray, dstOffset ) +{ + _.assert( arguments.length >= 1, 'Expects at least one argument' ); + _.assert( _.longIs( dstArray ) ); + _.assert( _.number.is( dstOffset ) ); + + dstOffset = dstOffset || 0; + + for( let a = 2 ; a < arguments.length ; a++ ) + { + let argument = arguments[ a ]; + let aIs = _.arrayIs( argument ) || _.bufferTypedIs( argument ); + + if( aIs && _.bufferTypedIs( dstArray ) ) + { + dstArray.set( argument, dstOffset ); + dstOffset += argument.length; + } + else if( aIs ) + for( let i = 0 ; i < argument.length ; i++ ) + { + dstArray[ dstOffset ] = argument[ i ]; + dstOffset += 1; + } + else + { + dstArray[ dstOffset ] = argument; + dstOffset += 1; + } + + } + + return dstArray; +} + +// + +/** + * The longSupplement() routine returns an array (dstArray), that contains values from following arrays only type of numbers. + * If the initial (dstArray) isn't contain numbers, they are replaced. + * + * It finds among the arrays the biggest array, and assigns to the variable (length), iterates over from 0 to the (length), + * creates inner loop that iterates over (arguments[...]) from the right (arguments.length - 1) to the (arguments[0]) left, + * checks each element of the arrays, if it contains only type of number. + * If true, it adds element to the array (dstArray) by corresponding index. + * Otherwise, it skips and checks following array from the last executable index, previous array. + * If the last executable index doesn't exist, it adds 'undefined' to the array (dstArray). + * After that it returns to the previous array, and executes again, until (length). + * + * @param { longIs } dstArray - The initial array. + * @param { ...longIs } arguments[...] - The following array(s). + * + * @example + * _.longSupplement( [ 4, 5 ], [ 1, 2, 3 ], [ 6, 7, 8, true, 9 ], [ 'a', 'b', 33, 13, 'e', 7 ] ); + * // returns ? + * + * @returns { longIs } - Returns an array that contains values only type of numbers. + * @function longSupplement + * @throws { Error } Will throw an Error if (dstArray) is not an array-like. + * @throws { Error } Will throw an Error if (arguments[...]) is/are not the array-like. + * @namespace Tools + */ + +function longSupplement( dstArray ) +{ + let result = dstArray; + if( result === null ) + result = []; + + let length = result.length; + _.assert( _.longIs( result ) || _.number.is( result ), 'Expects object as argument' ); + + for( let a = arguments.length-1 ; a >= 1 ; a-- ) + { + _.assert( _.longIs( arguments[ a ] ), 'argument is not defined :', a ); + length = Math.max( length, arguments[ a ].length ); + } + + if( _.number.is( result ) ) + result = arrayFill + ({ + value : result, + times : length, + }); + + for( let k = 0 ; k < length ; k++ ) + { + + if( k in dstArray && isFinite( dstArray[ k ] ) ) + continue; + + let a; + for( a = arguments.length-1 ; a >= 1 ; a-- ) + if( k in arguments[ a ] && !isNaN( arguments[ a ][ k ] ) ) + break; + + if( a === 0 ) + continue; + + result[ k ] = arguments[ a ][ k ]; + + } + + return result; +} + +// + +/** + * The longExtendScreening() routine iterates over (arguments[...]) from the right to the left (arguments[1]), + * and returns a (dstArray) containing the values of the following arrays, + * if the following arrays contains the indexes of the (screenArray). + * + * @param { longIs } screenArray - The source array. + * @param { longIs } dstArray - To add the values from the following arrays, + * if the following arrays contains indexes of the (screenArray). + * If (dstArray) contains values, the certain values will be replaced. + * @param { ...longIs } arguments[...] - The following arrays. + * + * @example + * _.longExtendScreening( [ 1, 2, 3 ], [ ], [ 0, 1, 2 ], [ 3, 4 ], [ 5, 6 ] ); + * // returns [ 5, 6, 2 ] + * + * @example + * _.longExtendScreening( [ 1, 2, 3 ], [ 3, 'abc', 7, 13 ], [ 0, 1, 2 ], [ 3, 4 ], [ 'a', 6 ] ); + * // returns [ 'a', 6, 2, 13 ] + * + * @example + * _.longExtendScreening( [ ], [ 3, 'abc', 7, 13 ], [ 0, 1, 2 ], [ 3, 4 ], [ 'a', 6 ] ); + * // returns [ 3, 'abc', 7, 13 ] + * + * @returns { longIs } Returns a (dstArray) containing the values of the following arrays, + * if the following arrays contains the indexes of the (screenArray). + * If (screenArray) is empty, it returns a (dstArray). + * If (dstArray) is equal to the null, it creates a new array, + * and returns the corresponding values of the following arrays by the indexes of a (screenArray). + * @function longExtendScreening + * @throws { Error } Will throw an Error if (screenArray) is not an array-like. + * @throws { Error } Will throw an Error if (dstArray) is not an array-like. + * @throws { Error } Will throw an Error if (arguments[...]) is/are not an array-like. + * @namespace Tools + */ + +function longExtendScreening( screenArray, dstArray ) +{ + let result = dstArray; + if( result === null ) + result = []; + + if( Config.debug ) + { + _.assert( _.longIs( screenArray ), 'Expects object as screenArray' ); + _.assert( _.longIs( result ), 'Expects object as argument' ); + for( let a = arguments.length-1 ; a >= 2 ; a-- ) + _.assert( !!arguments[ a ], () => `Argument #${a} is not defined` ); + } + + for( let k = 0 ; k < screenArray.length ; k++ ) + { + + if( screenArray[ k ] === undefined ) + continue; + + let a; + for( a = arguments.length-1 ; a >= 2 ; a-- ) + if( k in arguments[ a ] ) + break; + if( a === 1 ) + continue; + + result[ k ] = arguments[ a ][ k ]; + + } + + return result; +} + +// + +/** + * The routine longSort() sorts destination Long {-dstLong-}. + * + * @param { Long|Null } dstLong - The destination Long. If {-dstLong-} is null, then routine makes copy from {-srcLong-}. + * @param { Long } srcArray - Source long. Uses if {-dstLong-} is null. + * @param { Function } onEvaluate - Callback - evaluator or comparator for sorting elements. + * + * @example + * let src = [ 1, 30, -2, 5, -43 ]; + * _.longSort( null, src ); + * // returns [ -43, -2, 1, 30, 5 ] + * + * @example + * let dst = [ 1, 30, -2, 5, -43 ]; + * let src = [ 0 ]; + * let got = _.longSort( dst, src ); + * console.log( got ); + * // log [ -43, -2, 1, 30, 5 ] + * console.log( got === dst ); + * // log true + * + * @example + * let dst = [ 1, 50, -2, 3, -43 ]; + * let onEval = ( e ) => e; + * let got = _.longSort( dst, onEval ); + * console.log( got ); + * // log [ -43, -2, 1, 3, 50 ] + * console.log( got === dst ); + * // log true + * + * @example + * let dst = [ 1, 50, -2, 3, -43 ]; + * let onEval = ( a, b ) => a < b; + * let got = _.longSort( dst, onEval ); + * console.log( got ); + * // log [ 50, 3, 1, -2, -43 ] + * console.log( got === dst ); + * // log true + * + * @returns { Long } Returns sorted {-dstLong-}. + * @function longSort + * @throws { Error } If arguments.length is less then one or more then three. + * @throws { Error } If {-onEvaluate-} is not a routine or not undefined. + * @throws { Error } If {-dstLong-} is not null or not a Long. + * @throws { Error } If arguments.length === 3 and {-srcLong-} is not a Long. + * @throws { Error } If onEvaluate.length is less then one or more then two. + * @namespace Tools + */ + +function longSort( dstLong, srcLong, onEvaluate ) +{ + + if( _.routine.is( arguments[ 1 ] ) ) + { + onEvaluate = arguments[ 1 ]; + srcLong = dstLong; + } + + _.assert( arguments.length === 1 || arguments.length === 2 || arguments.length === 3 ); + _.assert( onEvaluate === undefined || _.routine.is( onEvaluate ) ); + _.assert( _.longIs( srcLong ) ); + _.assert( dstLong === null || _.longIs( dstLong ) ); + + if( dstLong === null ) + dstLong = _.array.make( srcLong ); + if( _.argumentsArray.is( dstLong ) ) // Dmytro : missed + dstLong = this.tools.long.default.from( dstLong ); + + if( onEvaluate === undefined ) + { + dstLong.sort(); + } + else if( onEvaluate.length === 2 ) + { + dstLong.sort( onEvaluate ); + } + else if( onEvaluate.length === 1 ) + { + dstLong.sort( function( a, b ) + { + a = onEvaluate( a ); + b = onEvaluate( b ); + + if( a > b ) + return +1; + else if( a < b ) + return -1; + else + return 0; + }); + } + else _.assert( 0, 'Expects signle-argument evaluator or two-argument comparator' ); + + return dstLong; +} + +// -- +// array etc +// -- + +// function longIndicesOfGreatest( srcArray, numberOfElements, comparator ) +// { +// let result = []; +// let l = srcArray.length; +// +// debugger; +// throw _.err( 'not tested' ); +// +// comparator = _.routine._comparatorFromEvaluator( comparator ); +// +// function rcomparator( a, b ) +// { +// return comparator( srcArray[ a ], srcArray[ b ] ); +// }; +// +// for( let i = 0 ; i < l ; i += 1 ) +// { +// +// if( result.length < numberOfElements ) +// { +// _.sorted.add( result, i, rcomparator ); +// continue; +// } +// +// _.sorted.add( result, i, rcomparator ); +// result.splice( result.length-1, 1 ); +// +// } +// +// return result; +// } +// +// // +// +// /** +// * The longSum() routine returns the sum of an array {-srcMap-}. +// * +// * @param { longIs } src - The source array. +// * @param { Routine } [ onEvaluate = function( e ) { return e } ] - A callback function. +// * +// * @example +// * _.longSum( [ 1, 2, 3, 4, 5 ] ); +// * // returns 15 +// * +// * @example +// * _.longSum( [ 1, 2, 3, 4, 5 ], function( e ) { return e * 2 } ); +// * // returns 29 +// * +// * @example +// * _.longSum( [ true, false, 13, '33' ], function( e ) { return e * 2 } ); +// * // returns 94 +// * +// * @returns { Number } - Returns the sum of an array {-srcMap-}. +// * @function longSum +// * @throws { Error } If passed arguments is less than one or more than two. +// * @throws { Error } If the first argument is not an array-like object. +// * @throws { Error } If the second argument is not a Routine. +// * @namespace Tools +// */ +// +// function longSum( src, onEvaluate ) +// { +// let result = 0; +// +// _.assert( arguments.length === 1 || arguments.length === 2 ); +// _.assert( _.longIs( src ), 'Expects ArrayLike' ); +// +// if( onEvaluate === undefined ) +// onEvaluate = function( e ){ return e; }; +// +// _.assert( _.routine.is( onEvaluate ) ); +// +// for( let i = 0 ; i < src.length ; i++ ) +// { +// result += onEvaluate( src[ i ], i, src ); +// } +// +// return result; +// } + +// -- +// declaration +// -- + +let ToolsExtension = +{ + + // long repeater + + longOnce, /* zzz : review */ /* !!! : use instead of longOnce */ + longOnce_, + + longHasUniques, + longAreRepeatedProbe, + longAllAreRepeated, + longAnyAreRepeated, + longNoneAreRepeated, + + longMask, /* dubious */ + longUnmask, /* dubious */ + + // array maker + + longRandom, + + longFromRange, + longFromProgressionArithmetic, /* qqq : light coverage required */ + longFromRangeWithStep, + longFromRangeWithNumberOfSteps, + + // // array converter + // + longToMap, /* dubious */ /* Yevhen : uncommented, routine is used in module::wChangeTransactor */ + // longToStr, /* dubious */ + + // long transformer + + longOnlyWithIndices, + + // long mutator + + longShuffle, + + // long mutator + + longSwapElements, + longPut, + + longSupplement, /* experimental */ + longExtendScreening, /* experimental */ + + longSort, + + // // array etc + // + // longIndicesOfGreatest, /* dubious */ + // longSum, /* dubious */ + +} + +// + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Long.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Long_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Long_s */ })(); + +/* */ /* begin of file Map_s */ ( function Map_s() { function Map_s_naked() { ( function _l0_l7_Map_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.map = _.map || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +let ExtensionMap = +{ + +} + +Object.assign( _.map, ExtensionMap ); +_.assert( _.aux.is( _.map ) ); + +// + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Map.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Map_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Map_s */ })(); + +/* */ /* begin of file Module_s */ ( function Module_s() { function Module_s_naked() { ( function _l5_Module_s_() +{ + +'use strict'; + +// + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// declare +// -- + +var ModuleExtension = +{ + +} + +Object.assign( _.module, ModuleExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Module.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Module_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Module_s */ })(); + +/* */ /* begin of file Number_s */ ( function Number_s() { function Number_s_naked() { ( function _l7_Number_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// number +// -- + +function numbersTotal( numbers ) +{ + let result = 0; + _.assert( _.longIs( numbers ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + for( let n = 0 ; n < numbers.length ; n++ ) + { + let number = numbers[ n ]; + _.assert( _.number.is( number ) ) + result += number; + } + return result; +} + +// + +function from( src ) +{ + _.assert( arguments.length === 1 ); + if( _.strIs( src ) ) + { + return parseFloat( src ); + } + return Number( src ); +} + +// + +function numbersFrom( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.strIs( src ) ) + return _.number.from( src ); + + if( _.number.is( src ) ) + return src; + + let result; + + if( _.longIs( src ) ) + { + result = []; + for( let s = 0 ; s < src.length ; s++ ) + result[ s ] = _.number.from( src[ s ] ); + } + else if( _.object.isBasic( src ) ) + { + result = Object.create( null ); + for( let s in src ) + result[ s ] = _.number.from( src[ s ] ); + } + else + { + result = _.number.from( src ); + } + + return result; +} + +// + +function fromStr( src ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.strIs( src ) ) + let result = parseFloat( src ); + return result; +} + +// + +// function numberFromStrMaybe( src ) +function fromStrMaybe( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ) || _.number.is( src ) ); + + if( _.number.is( src ) ) + return src; + if( !src ) /* qqq : cover */ + return src; + + // let parsed = !src ? NaN : Number( src ); /* Dmytro : it is strange code, the previous branch checks this condition */ + // if( !isNaN( parsed ) ) + // return parsed; + // return src; + + let parsed = src ? Number( src ) : NaN; + if( !isNaN( parsed ) ) + return parsed; + return src; +} + +// + +function numbersSlice( src, f, l ) +{ + if( _.argumentsArray.like( src ) ) + _.assert( _.number.s.areAll( src ) ) + + if( _.number.is( src ) ) + return src; + return _.longSlice( src, f, l ); +} + +// + +/** + * The routine numberRandom() returns a random float number, the value of which is within a + * range {-range-} . + * + * @param { Range|Number } range - The range for generating random numbers. + * If {-range-} is number, routine generates random number from zero to provided value. + * + * @example + * let got = _.number.random( 0 ); + * // returns random number in range [ 0, 0 ] + * console.log( got ); + * // log 0 + * + * @example + * let got = _.number.random( 3 ); + * // returns random number in range [ 0, 3 ] + * console.log( got ); + * // log 0.10161347203073712 + * + * @example + * let got = _.number.random( -3 ); + * // returns random number in range [ -3, 0 ] + * console.log( got ); + * // log -1.4184648844870276 + * + * @example + * let got = _.number.random( [ 3, 3 ] ); + * console.log( got ); + * // log 3 + * + * @example + * let got = _.number.random( [ -3, 0 ] ); + * console.log( got ); + * // log -1.5699334307486583 + * + * @example + * let got = _.number.random( [ 0, 3 ] ); + * console.log( got ); + * // log 0.6154656826553855 + * + * @example + * let got = _.number.random( [ -3, 3 ] ); + * console.log( got ); + * // log 1.9835540787557022 + * + * @returns { Number } - Returns a random float number. + * @function numberRandom + * @throws { Error } If arguments.length is less or more then one. + * @throws { Error } If range {-range-} is not a Number or not a Range. + * @namespace Tools + */ + +function random( range ) +{ + + if( _.number.is( range ) ) + range = range >= 0 ? [ 0, range ] : [ range, 0 ]; + _.assert( arguments.length === 1 && _.intervalIs( range ), 'Expects range' ); + + let result = Math.random()*( range[ 1 ] - range[ 0 ] ) + range[ 0 ]; + return result; +} + +// + +/** + * The routine intRandom() returns a random integer number, the value of which is within a + * range {-range-} . + * + * @param { Range|Number } range - The range for generating random numbers. + * If {-range-} is number, routine generates random number from zero to provided value. + * + * @example + * let got = _.intRandom( 0 ); + * // returns random number in range [ 0, 0 ] + * console.log( got ); + * // log 0 + * + * @example + * let got = _.intRandom( 1 ); + * // returns random number in range [ 0, 1 ] + * console.log( got ); + * // log 1 + * + * @example + * let got = _.intRandom( 3 ); + * // returns random number in range [ 0, 3 ] + * console.log( got ); + * // log 1 + * + * @example + * let got = _.intRandom( -3 ); + * // returns random number in range [ -3, 0 ] + * console.log( got ); + * // log -2 + * + * @example + * let got = _.intRandom( [ 3, 3 ] ); + * console.log( got ); + * // log 3 + * + * @example + * let got = _.intRandom( [ -3, 0 ] ); + * console.log( got ); + * // log -1 + * + * @example + * let got = _.intRandom( [ 0, 3 ] ); + * console.log( got ); + * // log 1 + * + * @example + * let got = _.intRandom( [ -3, 3 ] ); + * console.log( got ); + * // log -2 + * + * @returns { Number } - Returns a random integer number. + * @function intRandom + * @throws { Error } If arguments.length is less or more then one. + * @throws { Error } If range {-range-} is not a Number or not a Range. + * @namespace Tools + */ + +function intRandom( range ) +{ + + if( _.number.is( range ) ) + range = range >= 0 ? [ 0, range ] : [ range, 0 ]; + _.assert( arguments.length === 1 && _.intervalIs( range ), 'Expects range' ); + + let result = Math.floor( range[ 0 ] + Math.random()*( range[ 1 ] - range[ 0 ] ) ); + return result; +} + +// + +function intRandomBut( range ) +{ + let result; + let attempts = 50; + + if( _.number.is( range ) ) + range = [ 0, range ]; + else if( _.arrayIs( range ) ) + range = range; + else throw _.err( 'intRandom', 'unexpected argument' ); + + for( let attempt = 0 ; attempt < attempts ; attempt++ ) + { + // if( attempt === attempts-2 ) + // debugger; + // if( attempt === attempts-1 ) + // debugger; + + /*result = _.intRandom( range ); */ + let result = Math.floor( range[ 0 ] + Math.random()*( range[ 1 ] - range[ 0 ] ) ); + + let bad = false; + for( let a = 1 ; a < arguments.length ; a++ ) + if( _.routine.is( arguments[ a ] ) ) + { + if( !arguments[ a ]( result ) ) + bad = true; + } + else + { + if( result === arguments[ a ] ) + bad = true; + } + + if( bad ) + continue; + return result; + } + + result = NaN; + return result; +} + +// + +/** + * The routine numbersMake() returns an array of numbers with a length of {-length-} . + * + * @param { src|Number|Array } src - source number or array of numbers. + * If {-src-} is a Number, routine generates an array of length {-length-} filled with {-src-}. + * If {-src-} is an Array of numbers and {-src-}.length === {-length-}, the routine returns {-src-}. + * + * @param { length|Number } length - the size of the returned array. + * + * @example + * let got = _.number.s.make( 1, 0 ); + * // returns an empty array + * console.log( got ) + * // log [] + * + * @example + * let got = _.number.s.make( 1, 3 ); + * // returns an array of size 3 filled with ones + * console.log( got ) + * // log [ 1, 1, 1 ] + * + * @example + * let got = _.number.s.make( -5.22, 3 ); + * // returns an array of size 3 filled with -5.22 + * console.log( got ) + * // log [ -5.22, -5.22, -5.22 ] + * + * @example + * let got = _.number.s.make( NaN, 3 ); + * // returns an array of size 3 filled with NaN + * console.log( got ) + * // log [ NaN, NaN, NaN ] + * + * @example + * let got = _.number.s.make( [ 1, 2, 3 ], 3 ); + * // returns source array + * console.log( got ) + * // log [ 1, 2, 3 ] + * + * @example + * let got = _.number.s.make( [ 1.00, -2.777, 3.00 ], 3 ); + * // returns source array + * console.log( got ) + * // log [ 1.00, -2.777, 3.00 ] + * + * @example + * let got = _.number.s.make( [ NaN, Infinity, -Infinity ], 3 ); + * // returns source array + * console.log( got ) + * // log [ NaN, Infinity, -Infinity ] + * + * @returns { Array } - Returns an array of numbers. + * @function numbersMake + * @throws { Error } If {-src-} is array and {-src-}.length !== {-length-}. + * @throws { Error } If {-src-} is array and {-src-} contains not a number. + * @throws { Error } If {-src-} is not an array or a Number. + * @throws { Error } arguments.length === 0 or arguments.length > 2. + * @namespace Tools + */ + +function numbersMake( src, length ) +{ + let result; + + if( _.vector.adapterIs( src ) ) + src = _.vectorAdapter.slice( src ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.number.is( src ) || _.argumentsArray.like( src ) ); + + if( _.argumentsArray.like( src ) ) + { + _.assert( src.length === length ); + result = _.long.makeUndefined( length ); + for( let i = 0 ; i < length ; i++ ) + result[ i ] = src[ i ]; + } + else + { + result = _.long.makeUndefined( length ); + for( let i = 0 ; i < length ; i++ ) + result[ i ] = src; + } + + return result; +} + +// + +/** + * The routine numbersFromNumber() returns an array of numbers with a length of {-length-} . + * + * @param { src|Number|Array } src - source number or array of numbers. + * If {-src-} is a Number, routine generates an array of length {-length-} filled with {-src-}. + * If {-src-} is an Array of numbers and {-src-}.length === {-length-}, the routine returns {-src-}. + * + * @param { length|Number } length - the size of the returned array. + * + * @example + * let got = _.number.s.fromNumber( 1, 0 ); + * // returns an empty array + * console.log( got ) + * // log [] + * + * @example + * let got = _.number.s.fromNumber( 1, 3 ); + * // returns an array of size 3 filled with ones + * console.log( got ) + * // log [ 1, 1, 1 ] + * + * @example + * let got = _.number.s.fromNumber( -5.22, 3 ); + * // returns an array of size 3 filled with -5.22 + * console.log( got ) + * // log [ -5.22, -5.22, -5.22 ] + * + * @example + * let got = _.number.s.fromNumber( NaN, 3 ); + * // returns an array of size 3 filled with NaN + * console.log( got ) + * // log [ NaN, NaN, NaN ] + * + * @example + * let got = _.number.s.fromNumber( [ 1, 2, 3 ], 3 ); + * // returns source array + * console.log( got ) + * // log [ 1, 2, 3 ] + * + * @example + * let got = _.number.s.fromNumber( [ 1.00, -2.777, 3.00 ], 3 ); + * // returns source array + * console.log( got ) + * // log [ 1.00, -2.777, 3.00 ] + * + * @example + * let got = _.number.s.fromNumber( [ NaN, Infinity, -Infinity ], 3 ); + * // returns source array + * console.log( got ) + * // log [ NaN, Infinity, -Infinity ] + * + * @returns { Array } - Returns an array of numbers. + * @function numbersFromNumber + * @throws { Error } If {-src-} is array and {-src-}.length !== {-length-}. + * @throws { Error } If {-src-} is array and {-src-} contains not a number. + * @throws { Error } If {-src-} is not an array or a Number. + * @throws { Error } arguments.length === 0 or arguments.length > 2. + * @namespace Tools + */ + +function numbersFromNumber( src, length ) +{ + + if( _.vector.adapterIs( src ) ) + src = _.vectorAdapter.slice( src ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.number.is( src ) || _.argumentsArray.like( src ) ); + + if( _.argumentsArray.like( src ) ) + { + _.assert( src.length === length ); + return src; + } + + // debugger; /* xxx2 : test */ + let result = _.long.makeUndefined( length ); + for( let i = 0 ; i < length ; i++ ) + result[ i ] = src; + + return result; +} + +// + +/** + * The routine numbersFromInt() returns an array of integers with a length of {-length-} . + * + * @param { src|Number|Array } src - source number or array of integers. + * If {-src-} is an integer Number, routine generates an array of length {-length-} filled with {-src-}. + * If {-src-} is an Array of integers and {-src-}.length === {-length-}, the routine returns {-src-}. + * + * @param { length|Number } length - the size of the returned array. + * + * @example + * let got = _.number.s.fromInt( 1, 0 ); + * // returns an empty array + * console.log( got ) + * // log [] + * + * @example + * let got = _.number.s.fromInt( 1, 3 ); + * // returns an array of size 3 filled with ones + * console.log( got ) + * // log [ 1, 1, 1 ] + * + * @example + * let got = _.number.s.fromInt( [ 1, 2, 3 ], 3 ); + * // returns source array + * console.log( got ) + * // log [ 1, 2, 3 ] + * + * @example + * let got = _.number.s.fromInt( [ 1.00, -2.00, 3.00 ], 3 ); + * // returns source array + * console.log( got ) + * // log [ 1.00, -2.00, 3.00 ] + * + * @returns { Array } - Returns an array of integers. + * @function numbersFromInt + * @throws { Error } If {-src-} is array and {-src-}.length !== {-length-}. + * @throws { Error } If {-src-} is array and {-src-} contains not an integer Number. + * @throws { Error } If {-src-} is not an array or an integer. + * @throws { Error } arguments.length === 0 or arguments.length > 2. + * @namespace Tools + */ + +function numbersFromInt( dst, length ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.intIs( dst ) || _.arrayIs( dst ), 'Expects array of number as argument' ); + _.assert( length >= 0 ); + + if( _.number.is( dst ) ) + { + debugger; + // dst = _.longFillTimes( [], length , dst ); + dst = _.longFill( [], dst, length ); + } + else + { + for( let i = 0 ; i < dst.length ; i++ ) + _.assert( _.intIs( dst[ i ] ), 'Expects integer, but got', dst[ i ] ); + _.assert( dst.length === length, 'Expects array of length', length, 'but got', dst ); + } + + return dst; +} + +// + +function numbersMake_functor( length ) +{ + // let _ = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.number.is( length ) ); + + function numbersMake( src ) + { + return _.number.s.make( src, length ); + } + + return numbersMake; +} + +// + +function numbersFrom_functor( length ) +{ + // let _ = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.number.is( length ) ); + + function numbersFromNumber( src ) + { + return _.number.s.fromNumber( src, length ); + } + + return numbersFromNumber; +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + + numbersTotal, + + numberFrom : from, + numbersFrom, + numberFromStr : fromStr, + numberFromStrMaybe : fromStrMaybe, /* qqq : cover */ + + numbersSlice, + + numberRandom : random, + intRandom, + intRandomBut, /* dubious */ + + numbersMake, + numbersFromNumber, + numbersFromInt, + + numbersMake_functor, + numbersFrom_functor, + +} + +Object.assign( _, ToolsExtension ); + +// + +let NumberExtension = +{ + + + from, + fromStr, + fromStrMaybe, /* qqq : cover */ + + random, + intRandom, + intRandomBut, /* dubious */ + +} + +Object.assign( _.number, NumberExtension ); + +// + +let NumbersExtension = +{ + + total : numbersTotal, + from : numbersFrom, + slice : numbersSlice, + + make : numbersMake, + fromNumber : numbersFromNumber, + fromInt : numbersFromInt, + + make_functor : numbersMake_functor, + from_functor : numbersFrom_functor, + +} + +Object.assign( _.number.s, NumbersExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Number.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Number_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Number_s */ })(); + +/* */ /* begin of file Object_s */ ( function Object_s() { function Object_s_naked() { ( function _l7_Object_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.object = _.object || Object.create( null ); + +// -- +// dichotomy +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +let ObjectExtension = +{ + +} + +Object.assign( _.object, ObjectExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Object.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Object_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Object_s */ })(); + +/* */ /* begin of file Pair_s */ ( function Pair_s() { function Pair_s_naked() { ( function _l7_Pair_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +function isOf( src, Element ) +{ + if( !Element ) + return false; + if( !this.is( src ) ) + return false; + return src[ 0 ] instanceof Element && src[ 1 ] instanceof Element; +} + +// + +var Extension = +{ + isOf, +} + +// + +_.assert( _.pair !== undefined ); +_.props.supplement( _.pair, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Pair.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Pair_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Pair_s */ })(); + +/* */ /* begin of file Path_s */ ( function Path_s() { function Path_s_naked() { ( function _l7_Path_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.path = _.path || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +let Extension = +{ +} + +// + +Object.assign( _.path, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Path.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Path_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Path_s */ })(); + +/* */ /* begin of file Primitive_s */ ( function Primitive_s() { function Primitive_s_naked() { ( function _l7_Primitive_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.primitive = _.primitive || Object.create( null ); + +// -- +// primitive +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +// + +let Extension = +{ + +} + +Object.assign( _, ToolsExtension ); +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Primitive.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Primitive_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Primitive_s */ })(); + +/* */ /* begin of file Printer_s */ ( function Printer_s() { function Printer_s_naked() { ( function _l7_Printer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.printer = _.printer || Object.create( null ); + +// -- +// printer +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +// + +let Extension = +{ + +} + +Object.assign( Self, Extension ); +Object.assign( _, ToolsExtension ); + +/* xxx : investigate */ + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Printer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Printer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Printer_s */ })(); + +/* */ /* begin of file Process_s */ ( function Process_s() { function Process_s_naked() { ( function _l7_Process_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.process = _.process || Object.create( null ); + +// -- +// implementation +// -- + +/** + * The routine ready() delays execution of code to moment when web-page ( or program itself ) is loaded. + * Optionally routine accept additional time out {-timeOut-} and callback {-onReady-} to execute after + * loading. + * + * @example + * let result = []; + * _.process.ready(); + * // the code will continue execution when the page is loaded + * + * @example + * let result = []; + * let onReady = () => result.push( 'ready' ); + * _.process.ready( 500, onReady ); + * // the code will continue execution when the page is loaded and simultaneously routine adds delayed + * // execution of callback `onReady` + * + * First parameter set : + * @param { Number } timeOut - The time delay. + * @param { Function } onReady - Callback to execute. + * Second parameter set : + * @param { Map|Aux } o - Options map. + * @param { Number } o.timeOut - The time delay. + * @param { Function } o.onReady - Callback to execute. + * @returns { Undefined } - Returns not a value, executes code when a web-page is ready. + * @function ready + * @throws { Error } If arguments.length is greater than 2. + * @throws { Error } If {-timeOut-} has defined non integer value or not finite value. + * @namespace wTools.process + * @extends Tools + */ + +function ready_head( routine, args ) +{ + let o = args[ 0 ]; + if( !_.mapIs( o ) ) + { + o = Object.create( null ); + + if( args.length === 2 ) + { + o.timeOut = args[ 0 ]; + o.onReady = args[ 1 ]; + } + else + { + o.onReady = args[ 0 ]; + } + } + + _.routine.options( routine, o ); + + if( !o.timeOut ) + o.timeOut = 0; + + _.assert( 0 <= args.length || args.length <= 2 ); + _.assert( _.intIs( o.timeOut ) ); + _.assert( _.routine.is( o.onReady ) || o.onReady === null || o.onReady === undefined ); + + return o; +} + +// + +function ready_body( o ) +{ + + if( typeof window !== 'undefined' && typeof document !== 'undefined' && document.readyState !== 'complete' ) + window.addEventListener( 'load', handleReady ); + else + handleReady(); + + /* */ + + function handleReady() + { + _.time.begin( o.timeOut, o.onReady ); + } +} + +ready_body.defaults = +{ + timeOut : 0, + onReady : null, +}; + +// + +let ready = _.routine.unite( ready_head, ready_body ); + +// -- +// declaration +// -- + +let Extension = +{ + + ready, + +} + +Object.assign( _.process, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Process.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Process_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Process_s */ })(); + +/* */ /* begin of file PropertyTransformer_s */ ( function PropertyTransformer_s() { function PropertyTransformer_s_naked() { ( function _l7_PropertyTransformer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// +// -- + +// -- +// +// -- + +let Extension = +{ +}; + +_.props.supplement( _.props, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/PropertyTransformer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, PropertyTransformer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file PropertyTransformer_s */ })(); + +/* */ /* begin of file Props_s */ ( function Props_s() { function Props_s_naked() { ( function _l7_Property_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// extension +// -- + +let Extension = +{ +} + +// + +Object.assign( _.props, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Props.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Props_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Props_s */ })(); + +/* */ /* begin of file Prototype_s */ ( function Prototype_s() { function Prototype_s_naked() { ( function _l7_Prototype_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.prototype = _.prototype || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +var Extension = +{ +} + +// + +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Prototype.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Prototype_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Prototype_s */ })(); + +/* */ /* begin of file Regexp_s */ ( function Regexp_s() { function Regexp_s_naked() { ( function _l7_Regexp_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +const _ArrayIndexOf = Array.prototype.indexOf; +const _ArrayLastIndexOf = Array.prototype.lastIndexOf; +const _ArraySlice = Array.prototype.slice; +const _ArraySplice = Array.prototype.splice; +const _FunctionBind = Function.prototype.bind; +const _ObjectToString = Object.prototype.toString; +const _ObjectPropertyIsEumerable = Object.propertyIsEnumerable; + +// -- +// regexp +// -- + +let regexpsEscape = null; + +// + +/** + * Make regexp from string. + * + * @example + * _.regexp.from( 'Hello. How are you?' ); + * // returns /Hello\. How are you\?/ + * + * @param {RegexpLike} src - string or regexp + * @returns {String} Regexp + * @throws {Error} Throw error with message 'unknown type of expression, expects regexp or string, but got' error + if src not string-like ( string or regexp ) + * @function from + * @namespace Tools + */ + +function from( src, flags ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( flags === undefined || _.strIs( flags ) ); + + if( _.regexpIs( src ) ) + return src; + + _.assert( _.strIs( src ) ); + + return new RegExp( _.regexpEscape( src ), flags ); +} + +// + +function maybeFrom( o ) +{ + if( !_.mapIs( o ) ) + o = { srcStr : arguments[ 0 ] } + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( o.srcStr ) || _.regexpIs( o.srcStr ) ); + _.routine.options( maybeFrom, o ); + + let result = o.srcStr; + let strips; + + if( _.strIs( result ) ) + { + + if( o.stringWithRegexp ) + { + let optionsExtract = + { + delimeter : '//', + src : result, + } + // let strips = _.strSplitInlined( optionsExtract ); // Dmytro : it's local variable + strips = _.strSplitInlined( optionsExtract ); + } + else + { + // let strips = [ result ]; // Dmytro : it's local variable + strips = [ result ]; + } + + for( let s = 0 ; s < strips.length ; s++ ) + { + let strip = strips[ s ]; + + if( s % 2 === 0 ) + { + strip = _.regexpEscape( strip ); + if( o.toleratingSpaces ) + strip = strip.replace( /\s+/g, '\\s*' ); + } + + strips[ s ] = strip; + } + + result = RegExp( strips.join( '' ), o.flags ); + } + + return result; +} + +maybeFrom.defaults = +{ + srcStr : null, + stringWithRegexp : 1, + toleratingSpaces : 1, + flags : 'g', +} + +// + +let regexpsMaybeFrom = _.routineVectorize_functor( { routine : maybeFrom, select : 'srcStr' } ); + +// + +function regexpsSources( o ) +{ + if( _.arrayIs( arguments[ 0 ] ) ) + { + o = Object.create( null ); + o.sources = arguments[ 0 ]; + } + + // o.sources = o.sources ? _.longSlice( o.sources ) : []; + o.sources = _.longSlice( o.sources ); + if( o.flags === undefined ) + o.flags = null; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options( regexpsSources, o ); + + /* */ + + for( let s = 0 ; s < o.sources.length ; s++ ) + { + let src = o.sources[ s ]; + if( _.regexpIs( src ) ) + { + o.sources[ s ] = src.source; + _.assert + ( + o.flags === null || src.flags === o.flags, + () => `All RegExps should have flags field with the same value "${ src.flags }" != "${ o.flags }"` + ); + if( o.flags === null ) + o.flags = src.flags; + } + else + { + if( o.escaping ) + o.sources[ s ] = _.regexpEscape( src ); + } + _.assert( _.strIs( o.sources[ s ] ) ); + } + + /* */ + + return o; +} + +regexpsSources.defaults = +{ + sources : null, + flags : null, + escaping : 0, +} + +// + +function regexpsJoin( o ) +{ + if( !_.mapIs( o ) ) + o = { sources : o } + + _.routine.options( regexpsJoin, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + let src = o.sources[ 0 ]; + o = _.regexpsSources( o ); + if( o.sources.length === 1 && _.regexpIs( src ) ) + return src; + + let result = o.sources.join( '' ); + + return new RegExp( result, o.flags || '' ); +} + +regexpsJoin.defaults = +{ + flags : null, + sources : null, + escaping : 0, +} + +// + +function regexpsJoinEscaping( o ) +{ + if( !_.mapIs( o ) ) + o = { sources : o } + + _.routine.options( regexpsJoinEscaping, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( !!o.escaping ); + + return _.regexpsJoin( o ); +} + +var defaults = regexpsJoinEscaping.defaults = Object.create( regexpsJoin.defaults ); + +defaults.escaping = 1; + +// + +function regexpsAtLeastFirst( o ) +{ + + if( !_.mapIs( o ) ) + o = { sources : o } + + _.routine.options( regexpsAtLeastFirst, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + let src = o.sources[ 0 ]; + o = _.regexpsSources( o ); + if( o.sources.length === 1 && _.regexpIs( src ) ) + return src; + + let result = ''; + let prefix = ''; + let postfix = ''; + + for( let s = 0 ; s < o.sources.length ; s++ ) + { + let src = o.sources[ s ]; + + if( s === 0 ) + { + prefix = prefix + src; + } + else + { + prefix = prefix + '(?:' + src; + postfix = ')?' + postfix + } + + } + + result = prefix + postfix; + return new RegExp( result, o.flags || '' ); +} + +regexpsAtLeastFirst.defaults = +{ + flags : null, + sources : null, + escaping : 0, +} + +// + +function regexpsAtLeastFirstOnly( o ) +{ + + if( !_.mapIs( o ) ) + o = { sources : o } + + _.routine.options( regexpsAtLeastFirst, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + let src = o.sources[ 0 ]; + o = _.regexpsSources( o ); + if( o.sources.length === 1 && _.regexpIs( src ) ) + return src; + + let result = ''; + + if( o.sources.length === 1 ) + { + result = o.sources[ 0 ] + } + else for( let s = 0 ; s < o.sources.length ; s++ ) + { + let src = o.sources[ s ]; + if( s < o.sources.length-1 ) + result += '(?:' + o.sources.slice( 0, s+1 ).join( '' ) + '$)|'; + else + result += '(?:' + o.sources.slice( 0, s+1 ).join( '' ) + ')'; + } + + return new RegExp( result, o.flags || '' ); +} + +regexpsAtLeastFirst.defaults = +{ + flags : null, + sources : null, + escaping : 0, +} + +// + +/** + * Generates "but" regular expression pattern. Accepts a list of words, which will be used in regexp. + * The result regexp matches the strings that do not contain any of those words. + * + * @example + * _.regexpsNone( 'yellow', 'red', 'green' ); + * // returns /^(?:(?!yellow|red|green).)+$/ + * + * let options = + * { + * but : [ 'yellow', 'red', 'green' ], + * atLeastOnce : false + * }; + * _.regexpsNone(options); + * // returns /^(?:(?!yellow|red|green).)*$/ + * + * @param {Object} [options] options for generate regexp. If this argument omitted then default options will be used + * @param {String[]} [options.but=null] a list of words, from each will consist regexp + * @param {boolean} [options.atLeastOne=true] indicates whether search matches at least once + * @param {...String} [words] a list of words, from each will consist regexp. This arguments can be used instead + * options map. + * @returns {RegExp} Result regexp + * @throws {Error} If passed arguments are not strings or options map. + * @throws {Error} If options contains any different from 'but' or 'atLeastOnce' properties. + * @function regexpsNone + * @namespace Tools + */ + +function regexpsNone( o ) +{ + if( !_.mapIs( o ) ) + o = { sources : o } + + _.routine.options( regexpsNone, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + o = _.regexpsSources( o ); + + /* ^(?:(?!(?:abc)).)+$ */ + + let result = '^(?:(?!(?:'; + result += o.sources.join( ')|(?:' ); + result += ')).)+$'; + + return new RegExp( result, o.flags || '' ); +} + +regexpsNone.defaults = +{ + flags : null, + sources : null, + escaping : 0, +} + +// + +function regexpsAny( o ) +{ + if( !_.mapIs( o ) ) + o = { sources : o } + + _.routine.options( regexpsAny, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.regexpIs( o.sources ) ) + { + _.assert( o.sources.flags === o.flags || o.flags === null ); + return o.sources; + } + + _.assert( !!o.sources ); + let src = o.sources[ 0 ]; + o = _.regexpsSources( o ); + if( o.sources.length === 1 && _.regexpIs( src ) ) + return src; + + let result = '(?:'; + result += o.sources.join( ')|(?:' ); + result += ')'; + + return new RegExp( result, o.flags || '' ); +} + +regexpsAny.defaults = +{ + flags : null, + sources : null, + escaping : 0, +} + +// + +function regexpsAll( o ) +{ + if( !_.mapIs( o ) ) + o = { sources : o } + + _.routine.options( regexpsAll, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.regexpIs( o.sources ) ) + { + _.assert( o.sources.flags === o.flags || o.flags === null ); + return o.sources; + } + + let src = o.sources[ 0 ]; + o = _.regexpsSources( o ); + if( o.sources.length === 1 && _.regexpIs( src ) ) + return src; + + let result = '' + + if( o.sources.length > 0 ) + { + + if( o.sources.length > 1 ) + { + result += '(?='; + result += o.sources.slice( 0, o.sources.length-1 ).join( ')(?=' ); + result += ')'; + } + + result += '(?:'; + result += o.sources[ o.sources.length-1 ]; + result += ')'; + + } + + return new RegExp( result, o.flags || '' ); +} + +regexpsAll.defaults = +{ + flags : null, + sources : null, + escaping : 0, +} + +// + +/** + * Wraps regexp(s) into array and returns it. If in `src` passed string - turn it into regexp + * + * @example + * _.regexp.array.make( ['red', 'white', /[a-z]/] ); + * // returns [ /red/, /white/, /[a-z]/ ] + * + * @param {String[]|String} src - array of strings/regexps or single string/regexp + * @returns {RegExp[]} Array of regexps + * @throw {Error} if `src` in not string, regexp, or array + * @function arrayMake + * @namespace Tools + */ + +function arrayMake( src ) +{ + + _.assert( _.regexpLike( src ) || _.argumentsArray.like( src ), 'Expects array/regexp/string, got ' + _.entity.strType( src ) ); + + src = _.arrayFlatten( [], _.array.as( src ) ); + + for( let k = src.length-1 ; k >= 0 ; k-- ) + { + let e = src[ k ] + + if( e === null ) + { + src.splice( k, 1 ); + continue; + } + + src[ k ] = _.regexpFrom( e ); + + } + + return src; +} + +// + +/** + * Routine arrayIndex() returns the index of the first regular expression that matches substring + * Otherwise, it returns -1. + * + * @example + * let str = "The RGB color model is an additive color model in which red, green, and blue light are added together in various ways to reproduce a broad array of colors"; + * let regArr1 = [/white/, /green/, /blue/]; + * _.regexp.arrayIndex(regArr1, str); + * // returns 1 + * + * @param {RegExp[]} arr Array for regular expressions. + * @param {String} ins String, inside which will be execute search + * @returns {number} Index of first matching or -1. + * @throws {Error} If first argument is not array. + * @throws {Error} If second argument is not string. + * @throws {Error} If element of array is not RegExp. + * @function arrayIndex + * @namespace Tools + */ + +function arrayIndex( arr, ins ) +{ + _.assert( _.arrayIs( arr ) ); + _.assert( _.strIs( ins ) ); + + for( let a = 0 ; a < arr.length ; a++ ) + { + let regexp = arr[ a ]; + _.assert( _.regexpIs( regexp ) ); + if( regexp.test( ins ) ) + return a; + } + + return -1; +} + +// + +/** + * Checks if any regexp passed in `arr` is found in string `ins` + * If match was found - returns match index + * If no matches found and regexp array is not empty - returns false + * If regexp array is empty - returns some default value passed in the `ifEmpty` input param + * + * @example + * let str = "The RGB color model is an additive color model in which red, green, and blue light are added together in various ways to reproduce a broad array of colors"; + * let regArr2 = [/yellow/, /blue/, /red/]; + * _.arrayAny(regArr2, str, false); + * // returns 1 + * + * @example + * let regArr3 = [/yellow/, /white/, /greey/] + * _.regexp.arrayAny(regArr3, str, false); + * // returns false + * + * @param {String[]} arr Array of regular expressions strings + * @param {String} ins - string that is tested by regular expressions passed in `arr` parameter + * @param {*} none - Default return value if array is empty + * @returns {*} Returns the first match index, false if input array of regexp was empty or default value otherwise + * @thows {Error} If missed one of arguments + * @function arrayAny + * @namespace Tools + */ + +function arrayAny( arr, ins, ifEmpty ) +{ + + _.assert( _.arrayIs( arr ) || _.regexpIs( src ) ); + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + + arr = _.array.as( arr ); + for( let m = 0 ; m < arr.length ; m++ ) + { + _.assert( _.routine.is( arr[ m ].test ) ); + if( arr[ m ].test( ins ) ) + return m; + } + + return arr.length ? false : ifEmpty; +} + +// + +/** + * Checks if all regexps passed in `arr` are found in string `ins` + * If any of regex was not found - returns match index + * If regexp array is not empty and all regexps passed test - returns true + * If regexp array is empty - returns some default value passed in the `ifEmpty` input param + * + * @example + * let str = "The RGB color model is an additive color model in which red, green, and blue light are added together in various ways to reproduce a broad array of colors"; + * let regArr1 = [/red/, /green/, /blue/]; + * _.regexp.arrayAll(regArr1, str, false); + * // returns true + * + * @example + * let regArr2 = [/yellow/, /blue/, /red/]; + * _.regexp.arrayAll(regArr2, str, false); + * // returns 0 + * + * @param {String[]} arr Array of regular expressions strings + * @param {String} ins - string that is tested by regular expressions passed in `arr` parameter + * @param {*} none - Default return value if array is empty + * @returns {*} Returns the first match index, false if input array of regexp was empty or default value otherwise + * @thows {Error} If missed one of arguments + * @function arrayAll + * @namespace Tools + */ + +function arrayAll( arr, ins, ifEmpty ) +{ + _.assert( _.arrayIs( arr ) || _.regexpIs( src ) ); + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + + arr = _.array.as( arr ); + for( let m = 0 ; m < arr.length ; m++ ) + { + if( !arr[ m ].test( ins ) ) + return m; + } + + return arr.length ? true : ifEmpty; +} + +// + +function arrayNone( arr, ins, ifEmpty ) +{ + + _.assert( _.arrayIs( arr ) || _.regexpIs( src ) ); + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + + arr = _.array.as( arr ); + for( let m = 0 ; m < arr.length ; m++ ) + { + _.assert( _.routine.is( arr[ m ].test ) ); + if( arr[ m ].test( ins ) ) + return false; + } + + return arr.length ? true : ifEmpty; +} + +// -- +// regexp extension +// -- + +let RegexpExtension = +{ + + // regexp + + from, + + maybeFrom, + + arrayMake, + arrayIndex, + arrayAny, + arrayAll, + arrayNone, + +} + +Object.assign( _.regexp, RegexpExtension ); + +// -- +// regexps extension +// -- + +let RegexpsExtension = +{ + + // regexps + + maybeFrom : regexpsMaybeFrom, + + sources : regexpsSources, + join : regexpsJoin, + joinEscaping : regexpsJoinEscaping, + atLeastFirst : regexpsAtLeastFirst, + atLeastFirstOnly : regexpsAtLeastFirstOnly, + + none : regexpsNone, + any : regexpsAny, + all : regexpsAll, + +} + +Object.assign( _.regexps, RegexpsExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + regexpFrom : from, + + regexpMaybeFrom : maybeFrom, + regexpsMaybeFrom, + + regexpsSources, + regexpsJoin, + regexpsJoinEscaping, + regexpsAtLeastFirst, + regexpsAtLeastFirstOnly, + + regexpsNone, + regexpsAny, + regexpsAll, + + regexpArrayMake : arrayMake, + regexpArrayIndex : arrayIndex, + regexpArrayAny : arrayAny, + regexpArrayAll : arrayAll, + regexpArrayNone : arrayNone, + +} + +Object.assign( _, ToolsExtension ); + +// + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Regexp.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Regexp_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Regexp_s */ })(); + +/* */ /* begin of file Routine_s */ ( function Routine_s() { function Routine_s_naked() { ( function _l7_Routine_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// routine +// -- + +function routineCallButOnly( /* context, routine, options, but, only */ ) +{ + let context = arguments[ 0 ]; + let routine = arguments[ 1 ]; + let options = arguments[ 2 ]; + let but = arguments[ 3 ]; + let only = arguments[ 4 ]; + + if( _.routine.is( routine ) || _.strIs( routine ) ) + { + + _.assert( arguments.length === 3 || arguments.length === 4 || arguments.length === 5 ); + _.assert( _.mapIs( options ) ); + + if( _.strIs( routine ) ) + routine = context[ routine ]; + + } + else + { + + routine = arguments[ 0 ]; + options = arguments[ 1 ]; + but = arguments[ 2 ]; + only = arguments[ 3 ]; + + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4 ); + _.assert( _.mapIs( options ) ); + + } + + _.assert( _.routine.is( routine ) ); + + if( !only ) + only = routine.defaults + + if( but ) + options = _.mapBut_( null, options, but ) + if( only ) + options = _.mapOnly_( null, options, only ) + + return routine.call( context, options ); +} + +// + +function _routinesComposeWithSingleArgument_head( routine, args ) +{ + let o = _.routine.s.compose.head.call( this, routine, args ); + + _.assert( args.length === 1 ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + return o; +} + +// + +function routinesComposeReturningLast() +{ + let o = _.routine.s.composeReturningLast.head( routinesComposeReturningLast, arguments ); + let result = _.routine.s.composeReturningLast.body( o ); + return result; +} + +routinesComposeReturningLast.head = _.routine.s.compose.head; +routinesComposeReturningLast.body = _.routine.s.compose.body; +routinesComposeReturningLast.defaults = Object.create( _.routine.s.compose.defaults ); + +routinesComposeReturningLast.defaults.tail = _.routine.tail.returningLast; + +function routinesComposeAll() +{ + let o = _.routine.s.composeAll.head( routinesComposeAll, arguments ); + let result = _.routine.s.composeAll.body( o ); + return result; +} + +routinesComposeAll.head = _routinesComposeWithSingleArgument_head; +routinesComposeAll.body = _.routine.s.compose.body; + +var defaults = routinesComposeAll.defaults = Object.create( _.routine.s.compose.defaults ); +defaults.chainer = _.routine.chainer.composeAll; +defaults.tail = _.routine.tail.composeAll; + +_.assert( _.routine.is( _.routine.chainer.originalWithDont ) ); +_.assert( _.routine.is( _.routine.tail.composeAll ) ); + +// + +function routinesComposeAllReturningLast() +{ + let o = _.routine.s.composeAllReturningLast.head( routinesComposeAllReturningLast, arguments ); + let result = _.routine.s.composeAllReturningLast.body( o ); + return result; +} + +routinesComposeAllReturningLast.head = _routinesComposeWithSingleArgument_head; +routinesComposeAllReturningLast.body = _.routine.s.compose.body; + +var defaults = routinesComposeAllReturningLast.defaults = Object.create( _.routine.s.compose.defaults ); +defaults.chainer = _.routine.chainer.originalWithDont; +defaults.tail = _.routine.tail.returningLast; + +// + +function routinesChain() +{ + let o = _.routine.s.chain.head( routinesChain, arguments ); + let result = _.routine.s.chain.body( o ); + return result; +} + +routinesChain.head = _routinesComposeWithSingleArgument_head; +routinesChain.body = _.routine.s.compose.body; + +var defaults = routinesChain.defaults = Object.create( _.routine.s.compose.defaults ); +defaults.chainer = _.routine.chainer.chaining; +defaults.tail = _.routine.tail.chaining; + +// + +function _equalizerFromMapper( mapper ) +{ + + if( mapper === undefined ) + mapper = function mapper( a, b ){ return a === b }; + + _.assert( 0, 'not tested' ) + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( mapper.length === 1 || mapper.length === 2 ); + + if( mapper.length === 1 ) + { + let equalizer = equalizerFromMapper; + return equalizer; + } + + return mapper; + + function equalizerFromMapper( a, b ) + { + return mapper( a ) === mapper( b ); + } +} + +// + +function _comparatorFromEvaluator( evaluator ) +{ + + if( evaluator === undefined ) + evaluator = function comparator( a, b ){ return a-b }; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( evaluator.length === 1 || evaluator.length === 2 ); + + if( evaluator.length === 1 ) + { + let comparator = comparatorFromEvaluator; + return comparator; + } + + return evaluator; + + function comparatorFromEvaluator( a, b ) + { + return evaluator( a ) - evaluator( b ); + } +} + +// -- +// routine extension +// -- + +let RoutineExtension = +{ + + callButOnly : routineCallButOnly, /* qqq : cover please */ + + _equalizerFromMapper, + _comparatorFromEvaluator, /* xxx : move out */ + +} + +Object.assign( _.routine, RoutineExtension ); + +// -- +// routines extension +// -- + +let RoutinesExtension = +{ + + composeReturningLast : routinesComposeReturningLast, + composeAll : routinesComposeAll, + composeAllReturningLast : routinesComposeAllReturningLast, /* xxx */ + chain : routinesChain, + +} + +Object.assign( _.routines, RoutinesExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + routineCallButOnly, /* qqq : cover please */ + + routinesComposeReturningLast, + routinesComposeAll, + routinesComposeAllReturningLast, /* xxx */ + routinesChain, + + _equalizerFromMapper, + _comparatorFromEvaluator, /* xxx : move out */ + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Routine.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Routine_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Routine_s */ })(); + +/* */ /* begin of file Seeker_s */ ( function Seeker_s() { function Seeker_s_naked() { ( function _l7_Seeker_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// seeker extension +// -- + +let SeekerExtension = +{ + +} + +Object.assign( _.seeker, SeekerExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Seeker.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Seeker_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Seeker_s */ })(); + +/* */ /* begin of file Set_s */ ( function Set_s() { function Set_s_naked() { ( function _l7_Set_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// function adapterLike( src ) +// { +// if( !src ) +// return false; +// if( _.set.like( src ) ) +// return true; +// if( !_.containerAdapter || _.containerAdapter.Set ) +// return false; +// if( src instanceof _.containerAdapter.Set ) +// return true; +// return false; +// } + +// -- +// extension +// -- + +let ToolsExtension = +{ + + // setAdapterLike : adapterLike, + +} + +Object.assign( _, ToolsExtension ); + +// + +let SetExtension = +{ + + // adapterLike, /* xxx : move out */ + +} + +Object.assign( _.set, SetExtension ); + +// + +let SetsExtension = +{ + +} + +// + +Object.assign( _.set.s, SetsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Set.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Set_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Set_s */ })(); + +/* */ /* begin of file Sorted_s */ ( function Sorted_s() { function Sorted_s_naked() { ( function _l5_Sorted_s_() +{ + +'use strict'; + +// + +const _global = _global_; +const _ = _global_.wTools; +_.sorted = _.sorted || Object.create( null ); + +// -- +// +// -- + +// -- +// extension +// -- + +let Extension = +{ +}; + +_.props.supplement( _.sorted, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Sorted.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Sorted_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Sorted_s */ })(); + +/* */ /* begin of file Str_s */ ( function Str_s() { function Str_s_naked() { ( function _l7_String_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +const _ArraySlice = Array.prototype.slice; +const _FunctionBind = Function.prototype.bind; +const _ObjectToString = Object.prototype.toString; + +// -- +// str +// -- + +function strIsolate_head( routine, args ) +{ + let o; + + if( args.length > 1 ) + { + if( args.length === 3 ) + o = { src : args[ 0 ], delimeter : args[ 1 ], times : args[ 2 ] }; + else if( args.length === 2 ) + o = { src : args[ 0 ], delimeter : args[ 1 ] }; + else + o = { src : args[ 0 ] }; + } + else + { + o = args[ 0 ]; + _.assert( args.length === 1, 'Expects single argument' ); + } + + _.routine.options( routine, o ); + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( o.src ) ); + _.assert( _.regexpsLikeAll( o.delimeter ) ) + _.assert( _.number.is( o.times ) ); + + return o; +} + +// + +/** +* @typedef {object} wTools.entity.exportStringInhalfOptions +* @property {string} [ o.src=null ] - Source string. +* @property {string | array} [ o.delimeter=' ' ] - Splitter of the string. +* @property {boolean} [ o.left=1 ] - Finds occurrence from begining of the string. +*/ + +/** + * Finds occurrence of delimeter( o.delimeter ) in source( o.src ) and splits string in finded position by half. + * If function finds more then one occurrence, it separates string in the position of the last. + * + * @param {wTools.entity.exportStringInhalfOptions} o - Contains data and options {@link wTools.entity.exportStringInhalfOptions}. + * @returns {array} Returns array with separated parts of string( o.src ) or original string if nothing finded. + * + * @example + * _.strIsolate( { src : 'sample, string', delimeter : [ ',' ] } ); + * // returns [ 'sample', 'string' ] + * + * @example + *_.strIsolate( { src : 'sample string', delimeter : ' ' } ) + * // returns [ 'sample', 'string' ] + * + * @example + * _.strIsolate( { src : 'sample string, name string', delimeter : [ ',', ' ' ] } ) + * // returns [ 'sample string, name', 'string' ] + * + * @method strIsolate + * @throws { Exception } Throw an exception if no argument provided. + * @throws { Exception } Throw an exception if( o ) is not a Map. + * @throws { Exception } Throw an exception if( o.src ) is not a String. + * @throws { Exception } Throw an exception if( o.delimeter ) is not a Array or String. + * @throws { Exception } Throw an exception if( o ) is extended by unknown property. + * @namespace Tools + * + */ + +// function strIsolate( o ) +// { +// let result = []; +// let times = o.times; +// let delimeter +// let index = o.left ? -1 : o.src.length; +// +// _.routine.assertOptions( strIsolate, o ); +// _.assert( arguments.length === 1, 'Expects single argument' ); +// _.assert( _.strIs( o.src ), 'Expects string {-o.src-}, got', _.entity.strType( o.src ) ); +// _.assert( _.strIs( o.delimeter ) || _.arrayIs( o.delimeter ) ); +// _.assert( _.number.is( o.times ) ); +// +// /* */ +// +// if( !( times >= 1 ) ) +// { +// return everything( o.left ^ o.none ); +// } +// +// if( _.arrayIs( o.delimeter ) && o.delimeter.length === 1 ) +// o.delimeter = o.delimeter[ 0 ]; +// +// let closest = o.left ? strLeft : strRight; +// +// /* */ +// +// while( times > 0 ) +// { +// +// index += o.left ? +1 : -1; +// +// if( _.arrayIs( o.delimeter ) ) +// { +// +// if( !o.delimeter.length ) +// { +// return everything( o.left ^ o.none ); +// } +// +// let c = closest( index ); +// +// delimeter = c.element; +// index = c.value; +// +// if( o.times === 1 && index === o.src.length && o.left ) +// index = -1; +// +// } +// else +// { +// +// delimeter = o.delimeter; +// index = o.left ? o.src.indexOf( delimeter, index ) : o.src.lastIndexOf( delimeter, index ); +// +// if( o.left && !( index >= 0 ) && o.times > 1 ) +// { +// index = o.src.length; +// break; +// } +// +// } +// +// /* */ +// +// if( !o.left && times > 1 && index === 0 ) +// { +// return everything( !o.none ) +// } +// +// if( !( index >= 0 ) && o.times === 1 ) +// { +// return everything( o.left ^ o.none ) +// } +// +// times -= 1; +// +// } +// +// /* */ +// +// result.push( o.src.substring( 0, index ) ); +// result.push( delimeter ); +// result.push( o.src.substring( index + delimeter.length ) ); +// +// return result; +// +// /* */ +// +// function everything( side ) +// { +// return ( side ) ? [ o.src, '', '' ] : [ '', '', o.src ]; +// } +// +// /* */ +// +// function strLeft( index ) +// { +// return _.entityMin( o.delimeter, function( a ) +// { +// let i = o.src.indexOf( a, index ); +// if( i === -1 ) +// return o.src.length; +// return i; +// }); +// } +// +// /* */ +// +// function strRight( index ) +// { +// return _.entityMax( o.delimeter, function( a ) +// { +// let i = o.src.lastIndexOf( a, index ); +// return i; +// }); +// } +// +// } +// +// strIsolate.defaults = +// { +// src : null, +// delimeter : ' ', +// quote : null, +// left : 1, +// times : 1, +// none : 1, +// } + +function strIsolate_body( o ) +{ + let result = []; + let times = o.times; + let delimeter + let index = o.left ? 0 : o.src.length; + let more = o.left ? strLeft : strRight; + let delta = ( o.left ? +1 : -1 ); + + _.routine.assertOptions( strIsolate_body, arguments ); + + /* */ + + if( _.arrayIs( o.delimeter ) && o.delimeter.length === 1 ) + o.delimeter = o.delimeter[ 0 ]; + + let quote; + if( o.quote ) + quote = _.strQuoteAnalyze({ src : o.src, quote : o.quote }); + + /* */ + + while( times > 0 ) + { + let found = more( index ); + + if( found.entry === undefined ) + break; + + times -= 1; + + if( o.left ) + index = found.index + delta; + else + index = found.index + found.entry.length + delta; + + if( times === 0 ) + { + result.push( o.src.substring( 0, found.index ) ); + result.push( found.entry ); + result.push( o.src.substring( found.index + found.entry.length ) ); + return result; + } + + /* */ + + if( o.left ) + { + if( index >= o.src.length ) + break; + } + else + { + if( index <= 0 ) + break; + } + + } + + /* */ + + if( !result.length ) + { + + if( o.times === 0 ) + return everything( !o.left ); + else if( times === o.times ) + return everything( o.left ^ o.none ); + else + return everything( o.left ); + + } + + return result; + + /* */ + + function everything( side ) + { + return ( side ) ? [ o.src, undefined, '' ] : [ '', undefined, o.src ]; + } + + /* */ + + function strLeft( index ) + { + // let r = _._strLeftSingle( o.src, o.delimeter, [ index, undefined ] ); + let r = _._strLeftSingle_( o.src, o.delimeter, [ index, undefined ] ); + if( quote ) + if( r.entry !== undefined ) + { + let range = inQuoteRange( r.index ); + if( range ) + return strLeft( range[ 1 ]+1 ); + } + return r; + } + + /* */ + + function strRight( index ) + { + // let r = _._strRightSingle( o.src, o.delimeter, [ undefined, index ] ); + let r = _._strRightSingle_( o.src, o.delimeter, [ undefined, index-1 ] ); + if( quote ) + if( r.entry !== undefined ) + { + let range = inQuoteRange( r.index ); + if( range ) + return strRight( range[ 0 ] ); + } + return r; + } + + /* */ + + function inQuoteRange( offset ) + { + let i = _.sorted.searchFirstIndex( quote.ranges, offset ); + if( i % 2 ) + { + i -= 1; + } + if( i < 0 || i >= quote.ranges.length ) + return false; + let b = quote.ranges[ i ]; + let e = quote.ranges[ i+1 ]; + if( !( b <= offset && offset <= e ) ) + return false; + return [ b, e ]; + } + + /* */ + + // function binSearch( val ) + // { + // let l = 0; + // let r = quote.ranges.length; + // let m; + // if( quote.ranges.length ) + // debugger; + // do + // { + // m = Math.floor( ( l + r ) / 2 ); + // if( quote.ranges[ m ] < val ) + // l = m+1; + // else if( quote.ranges[ m ] > val ) + // r = m; + // else + // return m; + // } + // while( l < r ); + // if( quote.ranges[ m ] < val ) + // return m+1; + // return m; + // } + + /* */ + + // let quotedRanges = []; + // + // function quoteRangesSetup( index ) + // { + // let quotes = []; + // for( let i = 0 ; i < o.src.length ; i++ ) + // { + // if( _.arrayHas( o.quote, ) ) + // } + // } + // + // function quoteRange( index ) + // { + // for( let i = 0 ; i < x ; i++ ) + // + // } + +} + +strIsolate_body.defaults = +{ + src : null, + delimeter : ' ', + quote : 0, + // quoting : [ '"', '`', '\'' ], + left : 1, + times : 1, + none : 1, +} + +// + +/** + * Short-cut for strIsolate function. + * Finds occurrence of delimeter( o.delimeter ) from begining of ( o.src ) and splits string in finded position by half. + * + * @param {wTools.entity.exportStringInhalfOptions} o - Contains data and options {@link wTools.entity.exportStringInhalfOptions}. + * @returns {array} Returns array with separated parts of string( o.src ) or original string if nothing finded. + * + * @example + * _.strIsolateLeftOrNone( { src : 'sample, string', delimeter : [ ', ' ] } ); + * // returns [ 'sample', 'string' ] + * + * @example + *_.strIsolateLeftOrNone( { src : 'sample string', delimeter : ' ' } ) + * // returns [ 'sample', 'string' ] + * + * @example + * _.strIsolateLeftOrNone( 'sample string, name string', ',' ) + * // returns [ 'sample string, name', 'string' ] + * + * @method strIsolateLeftOrNone + * @throws { Exception } Throw an exception if no argument provided. + * @throws { Exception } Throw an exception if( o ) is not a Map. + * @throws { Exception } Throw an exception if( o.src ) is not a String. + * @namespace Tools + * + */ + +function strIsolateLeftOrNone_body( o ) +{ + o.left = 1; + o.none = 1; + let result = _.strIsolate.body( o ); + return result; +} + +strIsolateLeftOrNone_body.defaults = +{ + src : null, + delimeter : ' ', + times : 1, + quote : null, +} + +// + +function strIsolateLeftOrAll_body( o ) +{ + o.left = 1; + o.none = 0; + let result = _.strIsolate.body( o ); + return result; +} + +strIsolateLeftOrAll_body.defaults = +{ + src : null, + delimeter : ' ', + times : 1, + quote : null, +} + +// + +/** + * Short-cut for strIsolate function. + * Finds occurrence of delimeter( o.delimeter ) from end of ( o.src ) and splits string in finded position by half. + * + * @param {wTools.entity.exportStringInhalfOptions} o - Contains data and options {@link wTools.entity.exportStringInhalfOptions}. + * @returns {array} Returns array with separated parts of string( o.src ) or original string if nothing finded. + * + * @example + * _.strIsolateRightOrNone( { src : 'sample, string', delimeter : [ ',' ] } ); + * // returns [ 'sample', 'string' ] + * + * @example + *_.strIsolateRightOrNone( { src : 'sample string', delimeter : ' ' } ) + * // returns [ 'sample', 'string' ] + * + * @method strIsolateRightOrNone + * @throws { Exception } Throw an exception if no argument provided. + * @throws { Exception } Throw an exception if( o ) is not a Map. + * @throws { Exception } Throw an exception if( o.src ) is not a String. + * @namespace Tools + * + */ + +function strIsolateRightOrNone_body( o ) +{ + o.left = 0; + o.none = 1; + let result = _.strIsolate.body( o ); + return result; +} + +strIsolateRightOrNone_body.defaults = +{ + src : null, + delimeter : ' ', + times : 1, + quote : null, +} + +// + +function strIsolateRightOrAll_body( o ) +{ + o.left = 0; + o.none = 0; + let result = _.strIsolate.body( o ); + return result; +} + +strIsolateRightOrAll_body.defaults = +{ + src : null, + delimeter : ' ', + times : 1, + quote : null, +} + +// + +// function strIsolateInsideOrNoneSingle( src, begin, end ) +// { +// +// _.assert( _.strIs( src ), 'Expects string {-src-}' ); +// _.assert( arguments.length === 3, 'Expects exactly three arguments' ); +// +// let b = _.strLeft( src, begin ); +// +// if( b.entry === undefined ) +// return notFound(); +// +// let e = _.strRight( src, end ); +// +// if( e.entry === undefined ) +// return notFound(); +// +// if( e.index < b.index + b.entry.length ) +// return notFound(); +// +// let result = +// [ +// src.substring( 0, b.index ), +// b.entry, +// src.substring( b.index + b.entry.length, e.index ), +// e.entry, +// src.substring( e.index+e.entry.length, src.length ) +// ]; +// +// return result; +// +// function notFound() +// { +// return []; +// } +// } +// +// // +// +// function strIsolateInsideOrNone( src, begin, end ) +// { +// +// _.assert( arguments.length === 3, 'Expects exactly three arguments' ); +// +// if( _.argumentsArray.like( src ) ) +// { +// let result = []; +// for( let s = 0 ; s < src.length ; s++ ) +// result[ s ] = _.strIsolateInsideOrNoneSingle( src[ s ], begin, end ); +// return result; +// } +// else +// { +// return _.strIsolateInsideOrNoneSingle( src, begin, end ); +// } +// +// } + +// + +/** + * Routine isolateInsideSignle() split source strings {-src-} into parts separated by delimeters {-begin-} and {-end-}. Routine returns + * an array with parts of source string {-src-}. + * The array contains of five parts: + * - substring from start of source string to begin of first delimeter {-begin-}. + * - delimeter {-begin-}. + * - substring between delimeters {-begin-} and {-end-}. + * - delimeter {-end-}. + * - substring from end of delimeter {-end-} to end of source line. + * If routine does not find part between {-begin-} and {-end-} delimeters, then routine transform begin and end substrings to empty + * strings and delimeters to undefined. + * So, finally routine returns the array with source string: [ '', undefined, {-src-}, undefined, '' ]. + * + * @param { String } src - The source string. + * @param { String|Array } begin - String or array of strings to find begin of split part in the source string. + * @param { String|Array } end - String or array of strings to find end of split part in the source source. + * + * @example + * _.strIsolateInsideSignle( 'aabdcdd', 'a', 'd' ); + * // returns [ '', 'a', 'abdcd', 'd', '' ] + * + * @example + * _.strIsolateInsideSignle( 'cabdcdc', 'a', 'd' ); + * // returns [ 'c', 'a', 'bdc', 'd', 'c' ] + * + * @example + * _.strIsolateInsideSignle( 'cabdcdc', 'f', 'd' ); + * // returns [ '', undefined, 'cabdcdc', undefined, '' ] + * + * @example + * _.strIsolateInsideSignle( 'cabdcdc', 'a', 'f' ); + * // returns [ '', undefined, 'cabdcdc', undefined, '' ] + * + * @example + * _.strIsolateInsideSignle( 'cabdcdc', [ 'f', 'b' ], 'd' ); + * // returns [ 'ca', 'b', 'dc', 'd', 'c' ] + * + * @example + * _.strIsolateInsideSignle( 'cabdcdc', 'b', [ 'f', 'd' ] ); + * // returns [ 'ca', 'b', 'dc', 'd', 'c' ] + * + * @example + * _.strIsolateInsideSignle( 'cabdcdc', [ 'b', 'c' ], [ 'c', 'd' ] ); + * // returns [ 'ca', 'b', 'dcd', 'c', '' ] + * + * @returns { Array } - Returns array with parts of source string. + * @function isolateInsideSignle + * @throws { Exception } If arguments.length is less then one or more then three. + * @throws { Exception } If source string {-str-} is not a String. + * @throws { Exception } If delimeter {-begin-} is not a String or an Array of strings. + * @throws { Exception } If delimeter {-end-} is not a String or an Array of strings. + * @namespace Tools + */ + +function isolateInsideSignle( src, begin, end ) +{ + + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( arguments.length === 2 || arguments.length === 3 ); + let b, e; + + if( end === undefined ) + { + let pairs = arguments[ 1 ]; + _.assert( _.strIs( pairs ) || _.arrayIs( pairs ) ); + pairs = _.strQuotePairsNormalize( pairs ); + + let l = 0; + let begin = []; + for( let q = 0 ; q < pairs.length ; q++ ) + { + let quotingPair = pairs[ q ]; + begin.push( quotingPair[ 0 ] ); + } + + do + { + + // b = _.strLeft( src, begin, [ l, src.length ] ); + b = _.strLeft_( src, begin, [ l, src.length-1 ] ); + + if( b.entry === undefined ) + return notFound(); + + _.assert( _.number.is( b.instanceIndex ) ); + let end = pairs[ b.instanceIndex ][ 1 ]; + + // e = _.strRight( src, end, Math.min( b.index+1, src.length ) ); + // e = _.strRight_( src, end, Math.min( b.index, src.length-1 ) ); /* Dmytro : if cinterval is a Number, it is defined first index, not last */ + e = _.strRight_( src, end, Math.min( b.index, src.length ) ); + + if( e.entry === undefined ) + l = b.index+1; + else + break; + // return notFound(); + + } + while( l < src.length ); + + if( e.entry === undefined ) + return notFound(); + + } + else + { + + // b = _.strLeft( src, begin ); + b = _.strLeft_( src, begin ); + + if( b.entry === undefined ) + return notFound(); + + // e = _.strRight( src, end, Math.min( b.index+1, src.length ) ); + // e = _.strRight_( src, end, Math.min( b.index, src.length-1 ) ); /* Dmytro : if cinterval is a Number, it is defined first index, not last */ + e = _.strRight_( src, end, Math.min( b.index, src.length ) ); + + if( e.entry === undefined ) + return notFound(); + + } + + if( e.index < b.index + b.entry.length ) + return notFound(); + + let result = + [ + src.substring( 0, b.index ), + b.entry, + src.substring( b.index + b.entry.length, e.index ), + e.entry, + src.substring( e.index + e.entry.length, src.length ) + ]; + + return result; + + function notFound() + { + // return [ '', '', src, '', '' ]; + return [ '', undefined, src, undefined, '' ]; + } +} + +// + +/** + * Routine isolateInside() split source strings of vector {-src-} into parts separated by delimeters {-begin-} and {-end-}. Routine + * returns a vector with arrays. Each array of vector corresponds to element of vector {-src-}. + * Each array contains of five parts: + * - substring from start of source string to begin of first delimeter {-begin-}. + * - delimeter {-begin-}. + * - substring between delimeters {-begin-} and {-end-}. + * - delimeter {-end-}. + * - substring from end of delimeter {-end-} to end of source line. + * If routine does not find part between {-begin-} and {-end-} delimeters, then routine transform begin and end substrings to empty + * strings and delimeters to undefined. + * So, finally routine returns the array with source string: [ '', undefined, {-src-}, undefined, '' ]. + * + * @param { String|Array } src - The source string or vector of source strings. If {-src-} is a vector, then routine returns vector + * with resulted arrays. Otherwise, routine returns only one resulted array for scalar source string. + * @param { String|Array } begin - String or array of strings to find begin of split part in the source string. + * @param { String|Array } end - String or array of strings to find end of split part in the source source. + * + * @example + * _.strIsolateInside( 'aabdcdd', 'a', 'd' ); + * // returns [ '', 'a', 'abdcd', 'd', '' ] + * + * @example + * _.strIsolateInside( 'cabdcdc', 'a', 'd' ); + * // returns [ 'c', 'a', 'bdc', 'd', 'c' ] + * + * @example + * _.strIsolateInside( 'cabdcdc', 'f', 'd' ); + * // returns [ '', undefined, 'cabdcdc', undefined, '' ] + * + * @example + * _.strIsolateInsideSignle( 'cabdcdc', 'a', 'f' ); + * // returns [ '', undefined, 'cabdcdc', undefined, '' ] + * + * @example + * _.strIsolateInside( 'cabdcdc', [ 'f', 'b' ], 'd' ); + * // returns [ 'ca', 'b', 'dc', 'd', 'c' ] + * + * @example + * _.strIsolateInside( 'cabdcdc', 'b', [ 'f', 'd' ] ); + * // returns [ 'ca', 'b', 'dc', 'd', 'c' ] + * + * @example + * _.strIsolateInside( 'cabdcdc', [ 'b', 'c' ], [ 'c', 'd' ] ); + * // returns [ 'ca', 'b', 'dcd', 'c', '' ] + * + * @example + * _.strIsolateInside( [ 'cabdcdc', 'ddccbbaa' ], 'b', 'd' ); + * // returns [ [ 'ca', 'b', 'dc', 'd', 'c' ], [ '', '', 'ddccbbaa', '', '' ] ] + * + * @example + * _.strIsolateInside( [ 'cabdcdc', 'ddccbbaa' ], [ 'b', 'c' ], [ 'c', 'd' ] ); + * // returns [ [ 'ca', 'b', 'dcd', 'c', '' ], [ 'dd', 'c', '', 'c', 'bbaa' ] ] + * + * @returns { Array|ArraysVector } - If source string is a scalar, then routine returns array with parts of source string. + * If source string is a vector, then routine returns vector of arrays. + * @function isolateInside + * @throws { Exception } If arguments.length is less then one or more then three. + * @throws { Exception } If source string {-str-} is not a String. + * @throws { Exception } If delimeter {-begin-} is not a String or an Array of strings. + * @throws { Exception } If delimeter {-end-} is not a String or an Array of strings. + * @namespace Tools + */ + +function isolateInside( src, begin, end ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( _.argumentsArray.like( src ) ) + { + let result = []; + for( let s = 0 ; s < src.length ; s++ ) + result[ s ] = _.strIsolateInsideSignle( src[ s ], begin, end ); + return result; + } + else + { + return _.strIsolateInsideSignle( src, begin, end ); + } + +} + +// -- +// str extension +// -- + +let StrExtension = +{ + + isolate : _.routine.unite( strIsolate_head, strIsolate_body ), + isolateLeftOrNone : _.routine.unite( strIsolate_head, strIsolateLeftOrNone_body ), + isolateLeftOrAll : _.routine.unite( strIsolate_head, strIsolateLeftOrAll_body ), + isolateRightOrNone : _.routine.unite( strIsolate_head, strIsolateRightOrNone_body ), + isolateRightOrAll : _.routine.unite( strIsolate_head, strIsolateRightOrAll_body ), + + isolateInsideSignle, + isolateInside, + +} + +Object.assign( _.str, StrExtension ); + +// -- +// extension +// -- + +let ToolsExtension = +{ + + strIsolate : _.routine.unite( strIsolate_head, strIsolate_body ), + strIsolateLeftOrNone : _.routine.unite( strIsolate_head, strIsolateLeftOrNone_body ), + strIsolateLeftOrAll : _.routine.unite( strIsolate_head, strIsolateLeftOrAll_body ), + strIsolateRightOrNone : _.routine.unite( strIsolate_head, strIsolateRightOrNone_body ), + strIsolateRightOrAll : _.routine.unite( strIsolate_head, strIsolateRightOrAll_body ), + + // strIsolateInsideOrNoneSingle, + // strIsolateInsideOrNone, + strIsolateInsideSignle : isolateInsideSignle, + strIsolateInside : isolateInside, + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Str.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Str_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Str_s */ })(); + +/* */ /* begin of file Stringer_s */ ( function Stringer_s() { function Stringer_s_naked() { ( function _l7_Stringer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// stringer extension +// -- + +let StringerExtension = +{ + +} + +Object.assign( _.stringer, StringerExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Stringer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Stringer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Stringer_s */ })(); + +/* */ /* begin of file Symbol_s */ ( function Symbol_s() { function Symbol_s_naked() { ( function _l7_Symbol_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.symbol = _.symbol || Object.create( null ); + +// -- +// symbol +// -- + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +// + +let Extension = +{ + +} + +Object.assign( _, ToolsExtension ); +Object.assign( Self, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Symbol.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Symbol_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Symbol_s */ })(); + +/* */ /* begin of file Time_s */ ( function Time_s() { function Time_s_naked() { ( function _l7_Time_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +function rarely_functor( perTime, routine ) +{ + let lastTime = _.time.now() - perTime; + + _.assert( arguments.length === 2 ); + _.assert( _.number.is( perTime ) ); + _.assert( _.routine.is( routine ) ); + + return function fewer() + { + let now = _.time.now(); + let elapsed = now - lastTime; + if( elapsed < perTime ) + return; + lastTime = now; + return routine.apply( this, arguments ); + } + +} + +// + +function once( delay, onBegin, onEnd ) +{ + let con = _.Consequence ? new _.Consequence({ /* sourcePath : 2 */ }) : undefined; + let taken = false; + let options; + let optionsDefault = + { + delay : null, + onBegin : null, + onEnd : null, + } + + if( _.object.isBasic( delay ) ) + { + options = delay; + _.assert( arguments.length === 1, 'Expects single argument' ); + _.map.assertHasOnly( options, optionsDefault ); + delay = options.delay; + onBegin = options.onBegin; + onEnd = options.onEnd; + } + else + { + _.assert( 2 <= arguments.length && arguments.length <= 3 ); + } + + // _.assert( 0, 'not tested' ); + _.assert( delay >= 0 ); + _.assert( _.primitive.is( onBegin ) || _.routine.is( onBegin ) || _.object.isBasic( onBegin ) ); + _.assert( _.primitive.is( onEnd ) || _.routine.is( onEnd ) || _.object.isBasic( onEnd ) ); + + return function once() + { + + if( taken ) + { + /*console.log( 'once :', 'was taken' );*/ + return; + } + taken = true; + + if( onBegin ) + { + if( _.routine.is( onBegin ) ) onBegin.apply( this, arguments ); + else if( _.object.isBasic( onBegin ) ) onBegin.take( arguments ); + if( con ) + con.take( null ); + } + + _.time.out( delay, function() + { + + if( onEnd ) + { + if( _.routine.is( onEnd ) ) onEnd.apply( this, arguments ); + else if( _.object.isBasic( onEnd ) ) onEnd.take( arguments ); + if( con ) + con.take( null ); + } + taken = false; + + }); + + return con; + } + +} + +// + +function debounce( o ) /* Dmytro : routine returns routine. Is it valid result? */ +{ + _.assert( arguments.length <= 3 ); + + if( arguments.length > 1 ) + { + o = + { + routine : arguments[ 0 ], + delay : arguments[ 1 ], + immediate : ( arguments.length > 2 ? arguments[ 2 ] : null ), + } + } + + _.routine.options( debounce, o ); + + _.assert( _.routine.is( o.routine ) ); + _.assert( _.number.is( o.delay ) ); + + let timer, lastCallTime, routine, result; + + return debounced; + + /* */ + + function debounced() + { + lastCallTime = _.time.now(); + routine = _.routine.join( this, o.routine, arguments ); + let execNow = o.immediate && !timer + if( !timer ) + timer = setTimeout( onDelay, o.delay ); + if( execNow ) + result = routine(); + return result; + }; + + function onDelay() + { + var elapsed = _.time.now() - lastCallTime; + + if( elapsed > o.delay ) + { + timer = null; + if( !o.immediate ) + result = routine(); + } + else + { + timer = setTimeout( onDelay, o.delay - elapsed ); + } + }; +} + +debounce.defaults = +{ + routine : null, + delay : 100, + immediate : false +} + +// -- +// declaration +// -- + +let TimeExtension = +{ + + rarely_functor, /* check */ + once, /* qqq : cover by light test */ + + debounce + +} + +// + +_.props.supplement( _.time, TimeExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Time.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Time_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Time_s */ })(); + +/* */ /* begin of file Type_s */ ( function Type_s() { function Type_s_naked() { ( function _l7_Type_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// +// -- + +// -- +// +// -- + +let Extension = +{ +}; + +// + +_.props.supplement( _, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Type.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Type_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Type_s */ })(); + +/* */ /* begin of file Units_s */ ( function Units_s() { function Units_s_naked() { ( function _l7_Units_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.units = _.units || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +var Extension = +{ + +} + +// + +var ToolsExtension = +{ + +} + +// + +Object.assign( _.units, Extension ); +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Units.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Units_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Units_s */ })(); + +/* */ /* begin of file Unroll_s */ ( function Unroll_s() { function Unroll_s_naked() { ( function _l7_Unroll_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// +// -- + +// -- +// +// -- + +let Extension = +{ +}; + +// + +_.props.supplement( _, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Unroll.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Unroll_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Unroll_s */ })(); + +/* */ /* begin of file Vector_s */ ( function Vector_s() { function Vector_s_naked() { ( function _l7_Vector_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.vector = _.vector || Object.create( null ); + +// -- +// implementation +// -- + +// -- +// extension +// -- + +var Extension = +{ + +} + +// + +Object.assign( _.vector, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7/Vector.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Vector_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Vector_s */ })(); + +/* */ /* begin of file Setup_s */ ( function Setup_s() { function Setup_s_naked() { ( function _Setup_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global.wTools; +const Self = _.setup = _.setup || Object.create( null ); +_.error = _.error || Object.create( null ); + +// -- +// setup +// -- + +function _setupConfig() +{ + + if( _global.__GLOBAL_NAME__ !== 'real' ) + return; + + if( !_global.Config ) + _global.Config = Object.create( null ); + + if( _global.Config.debug === undefined ) + _global.Config.debug = true; + + _global.Config.debug = !!_global.Config.debug; + +} + +// + +function _setupLoggerPlaceholder() +{ + + if( !_global.console.debug ) + _global.console.debug = function debug() + { + this.log.apply( this, arguments ); + } + + if( !_global.logger ) + _global.logger = + { + log : function log() { console.log.apply( console, arguments ); }, + logUp : function logUp() { console.log.apply( console, arguments ); }, + logDown : function logDown() { console.log.apply( console, arguments ); }, + error : function error() { console.error.apply( console, arguments ); }, + errorUp : function errorUp() { console.error.apply( console, arguments ); }, + errorDown : function errorDown() { console.error.apply( console, arguments ); }, + info : function info() { console.info.apply( console, arguments ); }, + warn : function warn() { console.warn.apply( console, arguments ); }, + debug : function debug() { console.debug.apply( console, arguments ); }, + } + +} + +// + +function _setupTesterPlaceholder() +{ + + if( !_global.wTestSuite ) + _global.wTestSuite = function wTestSuite( testSuit ) + { + + if( !_realGlobal_.wTests ) + _realGlobal_.wTests = Object.create( null ); + + if( !testSuit.suiteFilePath ) + testSuit.suiteFilePath = _.introspector.location( 1 ).filePath; + + if( !testSuit.suiteFileLocation ) + testSuit.suiteFileLocation = _.introspector.location( 1 ).fileNameLineCol; + + _.assert( _.strDefined( testSuit.suiteFileLocation ), 'Test suit expects a mandatory option ( suiteFileLocation )' ); + _.assert( _.object.isBasic( testSuit ) ); + + if( !testSuit.abstract ) + _.assert( !_realGlobal_.wTests[ testSuit.name ], 'Test suit with name "' + testSuit.name + '" already registered!' ); + _realGlobal_.wTests[ testSuit.name ] = testSuit; + + testSuit.inherit = function inherit() + { + this.inherit = _.longSlice( arguments ); + } + + return testSuit; + } + + /* */ + + if( !_realGlobal_.wTester ) + { + _realGlobal_.wTester = Object.create( null ); + _realGlobal_.wTester.test = function test( testSuitName ) + { + if( _.workerIs() ) /* xxx : temp */ + return; + if( Config.interpreter !== 'njs' ) /* xxx : temp. remove aster fixing starter */ + return; + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.strIs( testSuitName ) || testSuitName === undefined, 'test : expects string {-testSuitName-}' ); + debugger; + _.process.ready( function() + { + debugger; + if( _realGlobal_.wTester.test === test ) + throw _.err( 'Cant run tests. Include module::wTesting.' ); + _realGlobal_.wTester.test.call( _realGlobal_.wTester, testSuitName ); + }); + } + } + +} + +// + +function _setupProcedure() +{ + + if + ( + _realGlobal_ !== _global + && _realGlobal_.wTools + && _realGlobal_.wTools.setup + && _realGlobal_.wTools.setup._entryProcedureStack + ) + { + Self._entryProcedureStack = _realGlobal_.wTools.setup._entryProcedureStack; + } + + if( Self._entryProcedureStack ) + return; + + let stack = _.introspector.stack().split( '\n' ); + for( let s = stack.length-1 ; s >= 0 ; s-- ) + { + let call = stack[ s ]; + let location = _.introspector.locationFromStackFrame( call ); + if( !location.internal && !location.abstraction ) + { + stack.splice( s+1, stack.length ); + stack.splice( 0, s ); + break; + } + } + + Self._entryProcedureStack = stack.join( '\n' ); +} + +// + +function _setupTime() +{ + + _.assert( !!_.time && !!_.time.now ); + _.setup.startTime = _.time.now(); + +} + +// + +function _validate() +{ + + if( !Config.debug ) + return; + + _.assert( _.routine.is( _.array._elementWithKey ) ); + _.assert( _.routine.is( _.argumentsArray._elementWithKey ) ); + _.assert( _.routine.is( _.long._elementWithKey ) ); + _.assert( _.routine.is( _.map._elementWithKey ) ); + _.assert( _.routine.is( _.object._elementWithKey ) ); + + if( !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe ) + { + debugger; + throw new Error( 'Failed to include module::wTools' ); + } + +} + +// + +function _Setup9() +{ + + _.assert( _global._WTOOLS_SETUP_EXPECTED_ !== false ); + + if( _global._WTOOLS_SETUP_EXPECTED_ !== false ) + { + _.setup._setupConfig(); + _.error._setupUncaughtErrorHandler9(); + _.setup._setupLoggerPlaceholder(); + _.setup._setupTesterPlaceholder(); + _.setup._setupProcedure(); + _.setup._setupTime(); + _.setup._validate(); + } + +} + +// -- +// implementation +// -- + +let SetupExtension = +{ + + _setupConfig, + _setupLoggerPlaceholder, + _setupTesterPlaceholder, + _setupProcedure, + _setupTime, + _validate, + + _Setup9, + + // + + startTime : null, + _entryProcedureStack : null, + +} + +Object.assign( _.setup, SetupExtension ); +Self._Setup9(); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l8/Setup.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l0/l8' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Setup_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Setup_s */ })(); + +/* */ /* begin of file Include_s */ ( function Include_s() { function Include_s_naked() { //#! /usr/bin/env node +( function _l1_Include_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + module[ 'exports' ] = require( '../l0/Include.s' ); + + require( './l1/Collection.s' ); + require( './l1/ContainerAdapter.s' ); + require( './l1/ContainerAdapterArray.s' ); + require( './l1/ContainerAdapterSet.s' ); + require( './l1/NameTools.s' ); + require( './l1/StrBasic.s' ); + // require( './l1/TreeMap.s' ); + // require( './l1/Trie.s' ); +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/Include.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Include_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Include_s */ })(); + +/* */ /* begin of file Collection_s */ ( function Collection_s() { function Collection_s_naked() { ( function _l1_Collection_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.collection = _.collection || Object.create( null ); + +// -- +// implementation +// -- + +function _commandPreform( command, commandRoutine, commandPhrase ) +{ + let aggregator = this; + + if( commandRoutine === null ) + commandRoutine = command.routine || command.e; + if( command === null ) + command = commandRoutine.command || Object.create( null ); + + if( command.phrase ) + command.phrase = aggregator.vocabulary.phraseNormalize( command.phrase ); + if( commandPhrase ) + commandPhrase = aggregator.vocabulary.phraseNormalize( commandPhrase ); + commandPhrase = commandPhrase || command.phrase || ( commandRoutine.command ? commandRoutine.command.phrase : null ) || null; + + if( commandRoutine && commandRoutine.command ) + if( command !== commandRoutine.command ) + { + _.assert( _.aux.is( commandRoutine.command ) ); + if( commandRoutine.command.phrase ) + commandRoutine.command.phrase = aggregator.vocabulary.phraseNormalize( commandRoutine.command.phrase ); + for( let k in commandRoutine.command ) + { + _.assert + ( + !_.props.has( command, k ) || command[ k ] === commandRoutine.command[ k ] + , () => `Inconsistent field "${k}" of command "${commandPhrase}"` + ); + command[ k ] = commandRoutine.command[ k ]; + } + delete commandRoutine.command; + } + + /* qqq : fill in asserts explanations */ + _.assert + ( + !command.aggregator, + () => `Command "${command.phrase}" already associated with a command aggregator.` + + ` Each Command should be used only once.` + ); + _.assert( _.routine.is( commandRoutine ), `Command "${commandPhrase}" does not have defined routine.` ); + _.assert( _.aux.is( command ) ); + _.assert( !_.props.has( command, 'ro' ) || commandRoutine === command.ro ); /* xxx : rename e to ro? */ + _.assert( !_.props.has( command, 'routine' ) || commandRoutine === command.routine ); + _.assert + ( + !_.props.has( command, 'phrase' ) || commandPhrase === command.phrase, + () => `Command ${commandPhrase} has phrases mismatch ${commandPhrase} <> ${command.phrase}` + ); + _.assert( !_.props.own( commandRoutine, 'command' ) || commandRoutine.command === command ); + _.map.assertHasOnly( command, aggregator.CommandAllFields ); + + if( commandPhrase ) + command.phrase = commandPhrase; + command.routine = commandRoutine; + commandRoutine.command = command; + aggregator._CommandShortFiledsToLongFields( command, command ); + + return command; + + /* - */ + + function _CommandShortFiledsToLongFields( dst, fields ) + { + _.assert( arguments.length === 2 ); + let filter = Self.CommandShortToLongFields; + for( let k in fields ) + { + if( _.props.has( filter, k ) ) + { + _.assert + ( + !_.props.has( dst, filter[ k ] ) || dst[ filter[ k ] ] === fields[ k ] + , () => `Inconsistent field "${k}" of command "${commandPhraseGet()}"` + ); + _.assert( !_.props.has( dst, filter[ k ] ) || dst[ filter[ k ] ] === fields[ k ] ); + dst[ filter[ k ] ] = fields[ k ]; + delete fields[ k ]; + } + } + + function commandPhraseGet() + { + return dst.phrase || ( dst.command ? dst.command.phrase : null ) || null; + } + } + +} + +// + +function toMapOfHandles( commandMap ) +{ + let aggregator = this; + let result = Object.create( null ); + let visited = new Set(); + + if( _.aux.is( commandMap ) ) + { + for( let k in commandMap ) + { + let command = commandMap[ k ]; + let commandRoutine = command; + + if( _.routine.is( commandRoutine ) ) + command = null; + else + commandRoutine = command.ro || command.routine; + + let commandPhrase = aggregator.vocabulary.phraseNormalize( k ); + command = aggregator._commandPreform( command, commandRoutine, commandPhrase ); + command.aggregator = aggregator; + aggregator.commandValidate( command ); + + _.assert + ( + !visited.has( command.routine ), + `Duplication of command "${command.phrase}"` + ); + visited.add( command.routine ); + + result[ command.phrase ] = command; + } + } + else if( _.longIs( commandMap ) ) + { + for( let k = 0 ; k < commandMap.length ; k++ ) + { + let command = commandMap[ k ]; + let commandRoutine = command; + if( _.routine.is( commandRoutine ) ) + command = null; + else + commandRoutine = command.ro || command.routine; + + command = aggregator._commandPreform( command, commandRoutine ); + command.aggregator = aggregator; + aggregator.commandValidate( command ); + + _.assert + ( + !visited.has( command.routine ), + `Duplication of command "${command.phrase}"` + ); + visited.add( command.routine ); + + result[ command.phrase ] = command; + } + } + else _.assert( 0 ); + + _.assert( _.aux.is( result ) ); + + return result; + + /* - */ + + function commandIs( src ) + { + if( !_.aux.is( src ) ) + return false; + if( src.handle === undefined ) + return false; + return true; + } + + /* - */ + + function commandValidate( command ) + { + let aggregator = this; + _.assert( aggregator.commandIs( command ), 'Not a command' ); + _.assert( _.routineIs( command.routine ) ); + _.assert( command.routine.command === command ); + _.assert( _.strDefined( command.phrase ) ); + _.assert( command.aggregator === undefined || command.aggregator === aggregator ); + if( _.routineIs( command.routine ) ) + _.map.assertHasOnly( command.routine, aggregator.CommandRoutineFields, 'Command routine should not have redundant fields' ); + _.map.assertHasOnly( command, aggregator.CommandNormalFields, 'Command should not have' ); + return true; + } + + /* - */ + + function _commandMapValidate( commandMap ) + { + let aggregator = this; + _.assert( _.mapIs( commandMap ) ); + for( let k in commandMap ) + { + let command = commandMap[ k ] + aggregator.commandValidate( command ); + } + return commandMap; + } + + /* - */ + +} + +// -- +// extension +// -- + +let ToolsExtension = +{ + +} + +// + +let ExtensionMap = +{ + + toMapOfHandles, + +} + +Object.assign( _, ToolsExtension ); +Object.assign( _.collection, ExtensionMap ); +_.assert( _.aux.is( _.collection ) ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1/Collection.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Collection_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Collection_s */ })(); + +/* */ /* begin of file ContainerAdapter_s */ ( function ContainerAdapter_s() { function ContainerAdapter_s_naked() { ( function _ContainerAdapter_s_() +{ + +'use strict'; + +const _global = _realGlobal_; +const _ = _global_.wTools; + +if( _global !== _realGlobal_ && _realGlobal_.wTools.containerAdapter ) +return ExportTo( _global, _realGlobal_ ); + +_.assert( _.routine.is( _.longLeft ) ); + +// -- +// type test +// -- + +function make( container ) +{ + + _.assert( arguments.length === 1 ); + + if( _.set.is( container ) ) + { + return new _.containerAdapter.Set( container ); + } + else if( _.arrayIs( container ) ) + { + return new _.containerAdapter.Array( container ); + } + else if( this.is( container ) ) + { + return container.make(); + } + else _.assert( 0, 'Unknown type of container' ); + +} + +// + +function from( container ) +{ + _.assert( arguments.length === 1 ); + if( container instanceof ContainerAdapterAbstract ) + { + return container; + } + else if( _.set.is( container ) ) + { + return new _.containerAdapter.Set( container ); + } + else if( _.arrayIs( container ) ) + { + return new _.containerAdapter.Array( container ); + } + else _.assert( 0, 'Unknown type of container' ); +} + +// + +function toOriginal( dst ) +{ + if( !dst ) + return dst; + if( dst instanceof ContainerAdapterAbstract ) + return dst.original; + return dst; +} + +// + +function toOriginals( dsts, srcs ) +{ + if( srcs === undefined ) + srcs = dsts; + + if( srcs === dsts ) + { + if( _.longIs( dsts ) ) /* Dmytro : in this context needs to check instance of some long */ + // if( _.argumentsArray.like( dsts ) ) + { + for( let s = 0 ; s < dsts.length ; s++ ) + dsts[ s ] = this.toOriginal( dsts[ s ] ); + return dsts; + } + return this.toOriginal( dsts ); + } + else + { + if( dsts === null ) + dsts = []; + + if( _.arrayIs( dsts ) ) + { + if( _.longIs( srcs ) ) /* Dmytro : in this context needs to check instance of some long */ + // if( _.argumentsArray.like( srcs ) ) + { + for( let s = 0 ; s < srcs.length ; s++ ) + // for( let e of srcs ) /* Dmytro : not optimal for longs */ + dsts.push( this.toOriginal( srcs[ s ] ) ); + return dsts; + } + else + dsts.push( this.toOriginal( srcs ) ); + return dsts; + } + else + { + if( _.longIs( srcs ) ) /* Dmytro : in this context needs to check instance of some long */ + // if( _.argumentsArray.like( srcs ) ) + { + let result = []; + result.push( this.toOriginal( dsts ) ); + for( let e of srcs ) + result.push( this.toOriginal( e ) ); + return result; + } + return this.toOriginals( [], arguments ); + } + } +} + +// -- +// +// -- + +class ContainerAdapterAbstract +{ + constructor( container ) + { + _.assert( arguments.length === 1 ); + this.original = container; + } + static ToOriginal( container ) + { + if( container instanceof ContainerAdapterAbstract ) + return container.original; + return container; + } + ToOriginal( container ) + { + return this.constructor.ToOriginal( container ); + } + static Is( src ) + { + return _.containerAdapter.is( src ); + } + Is( src ) + { + return this.constructor.Is( src ); + } + static IsContainer( src ) + { + return _.containerAdapter.isContainer( src ); + } + IsContainer( src ) + { + return this.constructor.IsContainer( src ); + } + static Make( src ) + { + return _.containerAdapter.make( ... arguments ); + } + Make( src ) + { + return this.constructor.Make( ... arguments ); + } + static From( src ) + { + return _.containerAdapter.from( src ); + } + From( src ) + { + return this.constructor.From( src ); + } + _filterArguments( dst, onEach ) + { + if( _.routine.is( arguments[ 0 ] ) ) + { + _.assert( onEach === undefined ); + onEach = dst; + dst = null; + } + if( dst === null || ( !dst && !onEach ) ) + dst = this.MakeEmpty(); + else if( dst === _.self ) + dst = this; + else + dst = this.From( dst ); + return [ dst, onEach ]; + } + _onlyArguments( /* dst, src2, onEvaluate1, onEvaluate2 */ ) + { + let dst = arguments[ 0 ]; + let src2 = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + if( _.routine.is( src2 ) || src2 === undefined ) + { + if( dst === undefined ) + dst = null; + + onEvaluate2 = onEvaluate1; + onEvaluate1 = src2; + src2 = dst; + dst = null; + } + + if( dst === _.self ) + dst = this; + else if( dst ) + dst = this.From( dst ); + else + dst = this.MakeEmpty(); + + if( src2 === _.self ) + src2 = this; + else if( src2 ) + src2 = this.From( src2 ); + else + src2 = this.MakeEmpty(); + + return [ dst, src2, onEvaluate1, onEvaluate2 ]; + } + _same( src ) + { + return src.original === this.original; + } + same( src ) + { + if( !src ) + return false; + if( src instanceof ContainerAdapterAbstract ) + return this._same( src ); + return this.original === src; + } + removedContainer( src ) + { + let result = 0; + let self = this; + + if( self._same( src ) ) + src = self.From( [ ... src.original ] ); + else + src = self.From( src ); + + src.each( ( e ) => result += self.removed( e ) ); + return result; + } + removedContainerOnce( src, onEvaluate1, onEvaluate2 ) + { + let result = 0; + let self = this; + + if( self._same( src ) ) + src = self.From( [ ... src.original ] ); + else + src = self.From( src ); + + src.each( ( e ) => + { + let r = self.removedOnce( e, onEvaluate1, onEvaluate2 ); + if( r !== -1 ) + result++; + }); + return result; + } + removedContainerOnceStrictly( src, onEvaluate1, onEvaluate2 ) + { + let self = this; + + if( self._same( src ) ) + src = self.From( [ ... src.original ] ); + else + src = self.From( src ); + + let result = src.length; + src.each( ( e ) => self.removeOnceStrictly( e, onEvaluate1, onEvaluate2 ) ); + + return result; + } + removeContainer( src ) + { + let self = this; + self.removedContainer.apply( self, arguments ); + return self; + } + removeContainerOnce( src, onEvaluate1, onEvaluate2 ) + { + let self = this; + self.removedContainerOnce.apply( self, arguments ); + return self; + } + removeContainerOnceStrictly( src, onEvaluate1, onEvaluate2 ) + { + let self = this; + self.removedContainerOnceStrictly.apply( self, arguments ); + return self; + } + min( onEach ) + { + let self = this; + if( onEach ) + return self.reduce( +Infinity, ( a, e ) => Math.min( a, onEach( e ) ) ); + else + return self.reduce( +Infinity, ( a, e ) => Math.min( a, e ) ); + } + max( onEach ) + { + let self = this; + if( onEach ) + return self.reduce( -Infinity, ( a, e ) => Math.max( a, onEach( e ) ) ); + else + return self.reduce( -Infinity, ( a, e ) => Math.max( a, e ) ); + } + least( dst, onEach ) + { + let self = this; + [ dst, onEach ] = this._filterArguments( ... arguments ); + let min = self.min( onEach ); + if( onEach ) + return self.filter( dst, ( e ) => onEach( e ) === min ? e : undefined ); + else + return self.filter( dst, ( e ) => e === min ? e : undefined ); + } + most( dst, onEach ) + { + let self = this; + [ dst, onEach ] = this._filterArguments( ... arguments ); + let max = self.max( onEach ); + if( onEach ) + return self.filter( dst, ( e ) => onEach( e ) === max ? e : undefined ); + else + return self.filter( dst, ( e ) => e === max ? e : undefined ); + } + only( /* dst, src2, onEvaluate1, onEvaluate2 */ ) + { + let dst = arguments[ 0 ]; + let src2 = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + + let self = this; + let container = self.original; + + [ dst, src2, onEvaluate1, onEvaluate2 ] = self._onlyArguments( ... arguments ); + + if( self._same( src2 ) ) + { + return self; + } + + if( self._same( dst ) ) + { + let temp = [ ... container ]; + + for( let i = 0; i < temp.length; i++ ) + { + if( !src2.has( temp[ i ], onEvaluate1, onEvaluate2 ) ) + dst.removeOnce( temp[ i ] ); + } + } + else + { + src2.each( ( e ) => + { + if( self.has( e, onEvaluate1, onEvaluate2 ) ) + dst.appendOnce( e ); + }); + } + + return dst; + } + but( /* dst, src2, onEvaluate1, onEvaluate2 */ ) + { + let dst = arguments[ 0 ]; + let src2 = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + + let self = this; + let container = self.original; + + [ dst, src2, onEvaluate1, onEvaluate2 ] = self._onlyArguments( ... arguments ); + + if( self._same( src2 ) ) + { + self.empty(); + return self; + } + + if( self._same( dst ) ) + { + let temp = [ ... container ]; + + for( let i = 0; i < temp.length; i++ ) + { + if( src2.has( temp[ i ], onEvaluate1, onEvaluate2 ) ) + dst.removeOnce( temp[ i ] ); + } + } + else + { + self.each( ( e ) => + { + if( !src2.has( e, onEvaluate1, onEvaluate2 ) ) + dst.appendOnce( e ); + }); + } + + return dst; + } + select( selector ) + { + let self = this; + let container = self.original; + + let result = []; + for( let e of container ) + { + if( _.select( e, selector ) ) + result.push( e ) + } + + return result; + } +} + +// -- +// meta +// -- + +function ExportTo( dstGlobal, srcGlobal ) +{ + let _ = dstGlobal.wTools; + _.assert( _.containerAdapter === undefined ); + _.assert( _.mapIs( srcGlobal.wTools.containerAdapter ) ); + _.containerAdapter = srcGlobal.wTools.containerAdapter; + if( typeof module !== 'undefined' ) + module[ 'exports' ] = _.containerAdapter; +} + +// -- +// declare +// -- + +var Extension = +{ + + make, + from, + + toOriginal, + toOriginals, + + Abstract : ContainerAdapterAbstract, + +} + +// + +Object.assign( _.containerAdapter, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +if( _global !== _realGlobal_ ) +return ExportTo( _realGlobal_, _global ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1/ContainerAdapter.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ContainerAdapter_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ContainerAdapter_s */ })(); + +/* */ /* begin of file ContainerAdapterArray_s */ ( function ContainerAdapterArray_s() { function ContainerAdapterArray_s_naked() { ( function _ContainerAdapterArray_s_() +{ + +'use strict'; + +const _global = _realGlobal_; +const _ = _global_.wTools; + +if( _global !== _realGlobal_ && _realGlobal_.wTools.containerAdapter ) +return ExportTo( _global, _realGlobal_ ); + +_.assert( _.routine.is( _.containerAdapter.Abstract ) ); +_.assert( _.routine.is( _.longLeft ) ); + +// -- +// implementation +// -- + +function make() +{ + _.assert( arguments.length === 0, 'Expects no arguments' ); + return new ContainerAdapterArray( this.original.slice() ); +} + +// + +function MakeEmpty() +{ + _.assert( arguments.length === 0, 'Expects no arguments' ); + return new ContainerAdapterArray( new Array ); +} + +// + +function makeEmpty() +{ + return this.constructor.MakeEmpty(); +} + +// + +function Make( src ) +{ + if( src === undefined || src === null ) + return this.MakeEmpty(); + else if( _.number.is( src ) ) + return new ContainerAdapterArray( new Array( src ) ); + else if( this.IsContainer( src ) ) + return new ContainerAdapterArray( [ ... src ] ); + else if( this.Is( src ) ) + return new ContainerAdapterArray( [ ... src.original ] ); +} + +// + +class ContainerAdapterArray extends _.containerAdapter.Abstract +{ + constructor( container ) + { + if( container === undefined ) + container = new Array; + super( container ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.longLike( container ) ); + } + // make = make; // Dmytro : simple assigning methods as a property is able in NodeJs v12 and later. So, I assign this properties after class declaration. + // static MakeEmpty = MakeEmpty; + // MakeEmpty = makeEmpty; + // static Make = Make; + has( e, onEvaluate1, onEvaluate2 ) + { + if( _.routine.is( onEvaluate1 ) || _.routine.is( onEvaluate2 ) ) + { + if( _.longLeftIndex( this.original, e, onEvaluate1, onEvaluate2 ) !== -1 ) + return true; + return false; + } + return this.original.includes( e ); + } + count( e, onEvaluate1, onEvaluate2 ) + { + return _.longCountElement( this.original, e, onEvaluate1, onEvaluate2 ); + } + copyFrom( src ) + { + let self = this; + let container = self.original; + + if( self.same( src ) ) + return self; + + if( !self.IsContainer( src ) && !self.Is( src ) ) + _.assert( 0, '{-src-} should be container' ); + + let i = 0; + for( let e of src ) + { + container[ i ] = e; + i++; + } + + return self; + } + append( e ) + { + this.original.push( e ); + return this; + } + appendOnce( e, onEvaluate1, onEvaluate2 ) + { + _.arrayAppendOnce( this.original, e, onEvaluate1, onEvaluate2 ); + return this; + } + appendOnceStrictly( e, onEvaluate1, onEvaluate2 ) + { + _.arrayAppendOnceStrictly( this.original, e, onEvaluate1, onEvaluate2 ) + return this; + } + push( e ) + { + return this.original.push( e ); + } + appendContainer( container ) + { + container = this.ToOriginal( container ); + if( _.longIs( container ) ) + { + _.arrayAppendArray( this.original, container ); + } + else if( _.set.is( container ) ) + { + for( let e of container ) + { + this.original.push( e ); + } + } + else + { + _.assert( 0, 'Unexpected data type' ); + } + return this; + } + appendContainerOnce( container, onEvaluate1, onEvaluate2 ) + { + container = this.ToOriginal( container ); + if( _.longIs( container ) ) + _.arrayAppendArrayOnce( this.original, container, onEvaluate1, onEvaluate2 ); + else if( _.set.is( container ) ) + _.arrayAppendArrayOnce( this.original, [ ... container ], onEvaluate1, onEvaluate2 ); + else _.assert( 0, 'Unexpected data type' ); + return this; + } + appendContainerOnceStrictly( container, onEvaluate1, onEvaluate2 ) + { + container = this.ToOriginal( container ); + if( _.longIs( container ) ) + _.arrayAppendArrayOnceStrictly( this.original, container, onEvaluate1, onEvaluate2 ); + else if( _.set.is( container ) ) + _.arrayAppendArrayOnceStrictly( this.original, [ ... container ], onEvaluate1, onEvaluate2 ); + else _.assert( 0, 'Unexpected data type' ); + return this; + } + pop( e, onEvaluate1, onEvaluate2 ) + { + var poped = this.original.pop(); + _.assert( e === undefined || _.entity.equal( poped, e, onEvaluate1, onEvaluate2 ) ); + return poped; + } + popStrictly( e, onEvaluate1, onEvaluate2 ) + { + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + _.assert( _.entity.equal( this.last(), e, onEvaluate1, onEvaluate2 ), 'Container does not have such element' ); + + var poped = this.original.pop(); + return poped; + } + removed( e, onEvaluate1, onEvaluate2 ) + { + return _.arrayRemoved( this.original, e, onEvaluate1, onEvaluate2 ); + } + removedOnce( e, onEvaluate1, onEvaluate2 ) + { + return _.arrayRemovedOnce( this.original, e, onEvaluate1, onEvaluate2 ); + } + removedOnceLeft( e, onEvaluate1, onEvaluate2 ) + { + return _.arrayRemovedOnce( this.original, e, onEvaluate1, onEvaluate2 ); + } + removedOnceRight( e, onEvaluate1, onEvaluate2 ) + { + let index = _.longRightIndex( this.original, e, onEvaluate1, onEvaluate2 ); + if( index !== -1 ) + this.original.splice( index, 1 ); + return index; + } + removedOnceStrictly( e, onEvaluate1, onEvaluate2 ) + { + return _.arrayRemovedOnceStrictly( this.original, e, onEvaluate1, onEvaluate2 ); + } + removedOnceStrictlyLeft( e, onEvaluate1, onEvaluate2 ) + { + return _.arrayRemovedOnceStrictly( this.original, e, onEvaluate1, onEvaluate2 ); + } + removedOnceStrictlyRight( e, onEvaluate1, onEvaluate2 ) + { + let container = this.original; + let index = _.longRightIndex( container, e, onEvaluate1, onEvaluate2 ); + _.assert( index !== -1, () => 'Container has not element ' + _.entity.exportStringDiagnosticShallow( e ) ); + container.splice( index, 1 ); + if( _.number.is( onEvaluate1 ) ) + onEvaluate1--; + _.assert( _.longRightIndex( container, e, onEvaluate1, onEvaluate2 ) === -1, () => 'The element ' + _.entity.exportStringDiagnosticShallow( e ) + ' is several times in dstArray' ); + return index; + } + remove( e, onEvaluate1, onEvaluate2 ) + { + _.arrayRemove( this.original, e, onEvaluate1, onEvaluate2 ); + return this; + } + removeOnce( e, onEvaluate1, onEvaluate2 ) + { + _.arrayRemoveOnce( this.original, e, onEvaluate1, onEvaluate2 ); + return this; + } + removeOnceLeft( e, onEvaluate1, onEvaluate2 ) + { + _.arrayRemoveOnce( this.original, e, onEvaluate1, onEvaluate2 ); + return this; + } + removeOnceRight( e, onEvaluate1, onEvaluate2 ) + { + this.removedOnceRight( e, onEvaluate1, onEvaluate2 ); + return this; + } + removeOnceStrictly( e, onEvaluate1, onEvaluate2 ) + { + _.arrayRemovedOnceStrictly( this.original, e, onEvaluate1, onEvaluate2 ); + return this; + } + removeOnceStrictlyLeft( e, onEvaluate1, onEvaluate2 ) + { + _.arrayRemovedOnceStrictly( this.original, e, onEvaluate1, onEvaluate2 ); + return this; + } + removeOnceStrictlyRight( e, onEvaluate1, onEvaluate2 ) + { + this.removedOnceStrictlyRight( e, onEvaluate1, onEvaluate2 ); + return this; + } + empty() + { + this.original.splice( 0, this.original.length ); + } + map( dst, onEach ) + { + let self = this; + let container = this.original; + [ dst, onEach ] = this._filterArguments( ... arguments ); + if( this._same( dst ) ) + { + for( let k = 0 ; k < container.length ; k++ ) + { + let e = container[ k ]; + let e2 = onEach( e, k, self ); + if( e2 !== undefined ) + { + container[ k ] = e2; + } + } + } + else + { + for( let k = 0 ; k < container.length ; k++ ) + { + let e = container[ k ]; + let e2 = onEach( e, k, self ); + if( e2 !== undefined ) + dst.append( e2 ); + else + dst.append( e ); + } + } + return dst; + } + mapLeft( dst, onEach ) + { + return this.map.apply( this, arguments ); + } + mapRight( dst, onEach ) + { + let container = this.original; + [ dst, onEach ] = this._filterArguments( ... arguments ); + if( this._same( dst ) ) + { + for( let k = container.length - 1; k >= 0; k-- ) + { + let e2 = onEach( container[ k ], k, this ); + if( e2 !== undefined ) + container[ k ] = e2; + } + } + else + { + for( let k = container.length - 1; k >= 0; k-- ) + { + let e2 = onEach( container[ k ], k, this ); + if( e2 !== undefined ) + dst.append( e2 ); + else + dst.append( container[ k ] ); + } + } + return dst; + } + filter( dst, onEach ) + { + let self = this; + let container = this.original; + [ dst, onEach ] = this._filterArguments( ... arguments ); + + if( this._same( dst ) ) + { + for( let k = 0; k < container.length; k++ ) + { + let e = container[ k ]; + let e2 = onEach( e, k, container ); + if( e2 === undefined ) + { + container.splice( k, 1 ); + k--; + } + else if( e2 !== e ) + { + container[ k ] = e2; + } + } + } + else + { + for( let k = 0; k < container.length; k++ ) + { + let e = container[ k ]; + let e2 = onEach( e, k, container ); + if( e2 !== undefined ) + dst.append( e2 ); + } + } + + return dst; + } + filterLeft( dst, onEach ) + { + return this.filter.apply( this, arguments ); + } + filterRight( dst, onEach ) + { + let self = this; + let container = this.original; + [ dst, onEach ] = this._filterArguments( ... arguments ); + + if( this._same( dst ) ) + { + for( let k = container.length - 1; k >= 0; k-- ) + { + let e2 = onEach( container[ k ], k, container ); + if( e2 === undefined ) + container.splice( k, 1 ); + else if( container[ k ] !== e2 ) + container[ k ] = e2; + } + } + else + { + for( let k = container.length - 1; k >= 0; k-- ) + { + let e2 = onEach( container[ k ], k, container ); + if( e2 !== undefined ) + dst.append( e2 ); + } + } + + return dst; + } + flatFilter( dst, onEach ) + { + let self = this; + let container = self.original; + [ dst, onEach ] = self._filterArguments( ... arguments ); + + if( self._same( dst ) ) + { + for( let k = 0; k < container.length; k++ ) + { + let e = container[ k ]; + let e2 = onEach( e, k, self ); + if( e2 === undefined ) + { + container.splice( k, 1 ) + k--; + } + else if( self.IsContainer( e2 ) || self.Is( e2 ) ) + { + k += e2.length - 1; + container.splice( k, 1, ... e2 ); + } + else if( e2 !== e ) + { + container[ k ] = e2; + } + } + } + else + { + for( let k = 0; k < container.length; k++ ) + { + let e = container[ k ]; + let e2 = onEach( e, k, container ); + if( self.IsContainer( e2 ) || self.Is( e2 ) ) + dst.appendContainer( e2 ) + else if( e2 !== undefined ) + dst.append( e2 ); + } + } + + return dst; + } + flatFilterLeft( dst, onEach ) + { + return this.flatFilter.apply( this, arguments ); + } + flatFilterRight( dst, onEach ) + { + let self = this; + let container = self.original; + [ dst, onEach ] = self._filterArguments( ... arguments ); + + if( self._same( dst ) ) + { + for( let k = container.length - 1; k >= 0; k-- ) + { + let e = container[ k ]; + let e2 = onEach( e, k, self ); + + if( e2 === undefined ) + container.splice( k, 1 ); + else if( self.IsContainer( e2 ) || self.Is( e2 ) ) + container.splice( k, 1, ... e2 ); + else if( e2 !== e ) + container[ k ] = e2; + } + } + else + { + for( let k = container.length - 1; k >= 0; k-- ) + { + let e = container[ k ]; + let e2 = onEach( e, k, container ); + + if( self.IsContainer( e2 ) || self.Is( e2 ) ) + dst.appendContainer( e2 ) + else if( e2 !== undefined ) + dst.append( e2 ); + } + } + + return dst; + } + once( dst, onEvaluate1, onEvaluate2 ) + { + let container = this.original; + [ dst, dst, onEvaluate1, onEvaluate2 ] = this._onlyArguments( null, dst, onEvaluate1, onEvaluate2 ); + + if( this._same( dst ) ) + _.longOnce( container, onEvaluate1, onEvaluate2 ); + else + dst.appendContainerOnce( container, onEvaluate1, onEvaluate2 ); + + return dst; + } + onceLeft( dst, onEvaluate1, onEvaluate2 ) + { + return this.once.apply( this, arguments ); + } + onceRight( dst, onEvaluate1, onEvaluate2 ) + { + let container = this.original; + [ dst, dst, onEvaluate1, onEvaluate2 ] = this._onlyArguments( null, dst, onEvaluate1, onEvaluate2 ); + + if( this._same( dst ) ) + { + _.longOnce( container, onEvaluate1, onEvaluate2 ); + } + else + { + for( let i = container.length - 1; i >= 0; i-- ) + dst.appendOnce( container[ i ], onEvaluate1, onEvaluate2 ); + } + + return dst; + } + withIndex( index ) + { + let self = this; + return self.original[ index ]; + } + first( onEach ) + { + let self = this; + let container = this.original; + if( onEach ) + { + if( !container.length ) + return undefined; + return onEach( container[ 0 ], 0, self ); + } + else + { + return container[ 0 ]; + } + } + last( onEach ) + { + let self = this; + let container = this.original; + let l = container.length-1; + if( onEach ) + { + if( !container.length ) + return undefined; + return onEach( container[ l ], l, self ); + } + else + { + return container[ l ]; + } + } + each( onEach ) + { + return this.eachLeft( onEach ); + } + eachLeft( onEach ) + { + let container = this.original; + for( let i = 0; i < container.length; i++ ) + onEach( container[ i ], i, this ); + return this; + } + eachRight( onEach ) + { + let self = this; + let container = this.original; + for( let k = container.length - 1 ; k >= 0 ; k-- ) + onEach( container[ k ], k, container ); + return this; + } + reduce( accumulator, onEach ) + { + let self = this; + let container = this.original; + if( arguments[ 1 ] === undefined ) + { + onEach = arguments[ 0 ]; + accumulator = undefined; + } + for( let k = 0, l = container.length ; k < l ; k++ ) + { + let e = container[ k ]; + accumulator = onEach( accumulator, e, k, self ); + } + return accumulator; + } + reduceLeft( accumulator, onEach ) + { + return this.reduce.apply( this, arguments ); + } + reduceRight( accumulator, onEach ) + { + let self = this; + let container = this.original; + if( arguments[ 1 ] === undefined ) + { + onEach = arguments[ 0 ]; + accumulator = undefined; + } + for( let k = container.length - 1; k >= 0; k-- ) + { + let e = container[ k ]; + accumulator = onEach( accumulator, e, k, self ); + } + return accumulator; + } + all( onEach ) + { + return this.allLeft( onEach ); + } + allLeft( onEach ) + { + let container = this.original; + for( let i = 0; i < container.length; i++ ) + { + let r = onEach( container[ i ], i, container ); + if( !r ) + return false; + } + return true; + } + allRight( onEach ) + { + let container = this.original; + for( let i = container.length - 1; i >= 0; i-- ) + { + let r = onEach( container[ i ], i, container ); + if( !r ) + return false; + } + return true; + } + any( onEach ) + { + return this.anyLeft( onEach ); + } + anyLeft( onEach ) + { + let container = this.original; + for( let i = 0; i < container.length; i++ ) + { + let r = onEach( container[ i ], i, container ); + if( r ) + return true; + } + return false; + } + anyRight( onEach ) + { + let container = this.original; + for( let i = container.length-1; i >= 0; i-- ) + { + let r = onEach( container[ i ], i, container ); + if( r ) + return true; + } + return false; + } + none( onEach ) + { + return this.noneLeft( onEach ); + } + noneLeft( onEach ) + { + let container = this.original; + for( let i = 0; i < container.length; i++ ) + { + let r = onEach( container[ i ], i, container ); + if( r ) + return false; + } + return true; + } + noneRight( onEach ) + { + let container = this.original; + for( let i = container.length - 1; i >= 0; i-- ) + { + let r = onEach( container[ i ], i, container ); + if( r ) + return false; + } + return true; + } + left( /* element, fromIndex, onEvaluate1, onEvaluate2 */ ) + { + let element = arguments[ 0 ]; + let fromIndex = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + return _.longLeft( this.original, element, fromIndex, onEvaluate1, onEvaluate2 ); + } + right( /* element, fromIndex, onEvaluate1, onEvaluate2 */ ) + { + let element = arguments[ 0 ]; + let fromIndex = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + return _.longRight( this.original, element, fromIndex, onEvaluate1, onEvaluate2 ); + } + reverse( dst ) + { + let srcContainer = this.original; + + if( !dst ) + { + dst = this.Make( this.length ); + let dstContainer = dst.original; + for( let i1 = srcContainer.length - 1, i2 = 0; i1 >= 0; i1--, i2++ ) + { + dstContainer[ i1 ] = srcContainer[ i2 ]; + } + } + else + { + dst = this.From( dst ); + let dstContainer = dst.original; + if( srcContainer === dstContainer ) + { + let last2 = ( srcContainer.length - srcContainer.length % 2 ) / 2; + let last1 = ( srcContainer.length % 2 ? last2 : last2-1 ); + for( let i1 = last1, i2 = last2; i1 >= 0; i1--, i2++ ) + { + let e = srcContainer[ i1 ]; + srcContainer[ i1 ] = srcContainer[ i2 ]; + srcContainer[ i2 ] = e; + } + } + else + { + for( let i = srcContainer.length - 1; i >= 0; i-- ) + { + dst.append( srcContainer[ i ] ); + } + } + } + return dst; + } + join( delimeter ) + { + return this.original.join( delimeter ); + } + toArray() + { + return this; + } + toSet() + { + return new _.containerAdapter.Set( new Set([ ... this.original ]) ); + } + [ Symbol.iterator ]() + { + return this.original[ Symbol.iterator ](); + } + get length() + { + return this.original.length; + } +} +ContainerAdapterArray.Make = Make; +ContainerAdapterArray.MakeEmpty = MakeEmpty; +ContainerAdapterArray.prototype.make = make; +ContainerAdapterArray.prototype.MakeEmpty = makeEmpty; + +// -- +// meta +// -- + +function ExportTo( dstGlobal, srcGlobal ) +{ + debugger; + let _ = dstGlobal.wTools; + _.assert( _.containerAdapter === srcGlobal.wTools.containerAdapter ); + _.assert( _.mapIs( srcGlobal.wTools.containerAdapter ) ); + if( typeof module !== 'undefined' ) + module[ 'exports' ] = _.containerAdapter; +} + +// -- +// declare +// -- + +const Self = _.containerAdapter; + +// + +var Extension = +{ + + Array : ContainerAdapterArray, + +} + +// + +Object.assign( _.containerAdapter, Extension ); +_.assert( _.containerAdapter === Self ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +if( _global !== _realGlobal_ ) +return ExportTo( _realGlobal_, _global ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1/ContainerAdapterArray.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ContainerAdapterArray_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ContainerAdapterArray_s */ })(); + +/* */ /* begin of file ContainerAdapterSet_s */ ( function ContainerAdapterSet_s() { function ContainerAdapterSet_s_naked() { ( function _ContainerAdapterSet_s_() +{ + +'use strict'; + +const _global = _realGlobal_; +const _ = _global_.wTools; + +if( _global !== _realGlobal_ && _realGlobal_.wTools.containerAdapter ) +return ExportTo( _global, _realGlobal_ ); + +_.assert( _.routine.is( _.containerAdapter.Abstract ) ); +_.assert( _.routine.is( _.longLeft ) ); + +// -- +// implementation +// -- + +function make() +{ + _.assert( arguments.length === 0, 'Expects no arguments' ); + return new ContainerAdapterSet( new Set( this.original ) ); +} + +// + +function MakeEmpty() +{ + _.assert( arguments.length === 0, 'Expects no arguments' ); + return new ContainerAdapterSet( new Set ); +} + +// + +function Make( src ) +{ + if( src === undefined || src === null ) + return this.MakeEmpty(); + else if( _.number.is( src ) ) + return new ContainerAdapterSet( new Set ); + else if( this.IsContainer( src ) ) + return new ContainerAdapterSet( new Set( src ) ); + else if( this.Is( src ) ) + return new ContainerAdapterSet( new Set( src.original ) ); +} + +// + +function makeEmpty() +{ + return this.constructor.MakeEmpty(); +} + +// + +class ContainerAdapterSet extends _.containerAdapter.Abstract +{ + // Dmytro : using constructor and super() method is old syntax, it can be deleted + // aaa : cover constructors /* Dmytro : covered */ + constructor( container ) + { + if( container === undefined ) + container = new Set; + super( container ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.set.like( container ) ); + } + // make = make; // Dmytro : simple assigning methods as a property is able in NodeJs v12 and later. So, I assign this properties after class declaration. + // static MakeEmpty = MakeEmpty; + // MakeEmpty = makeEmpty; + // static Make = Make; + has( e, onEvaluate1, onEvaluate2 ) + { + _.assert( onEvaluate2 === undefined || _.routine.is( onEvaluate2 ) ); + + let fromIndex = 0; + if( _.number.is( onEvaluate1 ) ) + { + fromIndex = onEvaluate1; + onEvaluate1 = onEvaluate2; + onEvaluate2 = undefined; + } + + if( _.routine.is( onEvaluate1 ) ) + { + if( onEvaluate1.length === 2 ) + { + _.assert( !onEvaluate2 ); + + for( let el of this.original ) + { + if( fromIndex === 0 ) + { + if( onEvaluate1( el, e ) ) + return true; + } + else + { + fromIndex -= 1; + } + } + + return false; + } + else if( onEvaluate1.length === 1 ) + { + _.assert( !onEvaluate2 || onEvaluate2.length === 1 ); + + if( onEvaluate2 ) + e = onEvaluate2( e ); + else + e = onEvaluate1( e ); + + for( let el of this.original ) + { + if( fromIndex === 0 ) + { + if( onEvaluate1( el ) === e ) + return true; + } + else + { + fromIndex -= 1; + } + } + + return false; + } + else _.assert( 0 ); + } + else if( onEvaluate1 === undefined || onEvaluate1 === null ) + { + return this.original.has( e ); + } + else _.assert( 0 ); + } + count( e, onEvaluate1, onEvaluate2 ) + { + let container = this.original; + + if( _.routine.is( onEvaluate1 ) || _.routine.is( onEvaluate2 ) ) + { + let from = 0; + let result = 0; + if( _.number.is( onEvaluate1 ) ) + { + from = onEvaluate1; + onEvaluate1 = onEvaluate2; + onEvaluate2 = undefined; + } + + for( let v of this.original ) + { + if( from === 0 ) + { + if( _.entity.equal( v, e, onEvaluate1, onEvaluate2 ) ) + result++; + } + else + { + from--; + } + } + return result; + } + else + { + return container.has( e ) ? 1 : 0; + } + } + copyFrom( src ) + { + let self = this; + let container = self.original; + + if( self.same( src ) ) + return self; + + if( !self.IsContainer( src ) && !self.Is( src ) ) + _.assert( 0, '{-src-} should be container' ); + + if( self.length <= ( src.length || src.size ) ) + { + self.empty(); + for( let e of src ) + { + self.append( e ); + } + } + else + { + // let temp = [ ... container ]; + // + // self.empty(); + // for( let e of src ) + // self.append( e ); + // for( let i = self.length; i < temp.length; i++ ) + // self.append( temp[ i ] ); + + let length = this.length; + let srcLength = src.length !== undefined ? src.length : src.size; + let lengthDiff = length - srcLength; + for( let e of src ) + { + for( let v of container ) + { + self.remove( v ); + break; + } + self.append( e ); + } + for( let e of container ) + { + if( lengthDiff !== 0 ) + { + self.remove( e ); + self.append( e ); + lengthDiff--; + } + else + { + break; + } + } + } + + return self; + } + append( e ) + { + this.original.add( e ); + return this; + } + appendOnce( e, onEvaluate1, onEvaluate2 ) + { + let container = this.original; + + if( onEvaluate1 || _.routine.is( onEvaluate2 ) ) + { + if( !this.has( e, onEvaluate1, onEvaluate2 ) ) + container.add( e ); + } + else + { + container.add( e ); + } + + return this; + } + appendOnceStrictly( e, onEvaluate1, onEvaluate2 ) + { + let container = this.original; + + if( onEvaluate1 || _.routine.is( onEvaluate2 ) ) + { + if( !this.has( e, onEvaluate1, onEvaluate2 ) ) + container.add( e ); + else + _.assert( 0, 'Set already has such element' ); + } + else + { + _.assert( !this.original.has( e ), 'Set already has such element' ); + container.add( e ); + } + return this; + } + appendContainer( container ) + { + container = this.ToOriginal( container ); + if( _.longIs( container ) ) + { + for( let k = 0, l = container.length ; k < l ; k++ ) + this.original.add( container[ k ] ); + } + else if( _.set.is( container ) ) + { + for( let e of container ) + this.original.add( e ); + } + else + { + _.assert( 0, 'Unexpected data type' ); + } + return this; + } + appendContainerOnce( container, onEvaluate1, onEvaluate2 ) + { + if( onEvaluate1 || _.routine.is( onEvaluate2 ) ) + { + container = this.ToOriginal( container ); + + if( _.longIs( container ) ) + { + for( let i = 0; i < container.length; i++ ) + if( !this.has( container[ i ], onEvaluate1, onEvaluate2 ) ) + this.append( container[ i ] ); + } + else if( _.set.is( container ) ) + { + for( let e of container ) + if( !this.has( e, onEvaluate1, onEvaluate2 ) ) + this.append( e ); + } + + return this; + } + else + { + return this.appendContainer( container ); + } + } + appendContainerOnceStrictly( container, onEvaluate1, onEvaluate2 ) + { + container = this.ToOriginal( container ); + + if( _.longIs( container ) ) + { + for( let i = 0; i < container.length; i++ ) + { + _.assert( !this.has( container[ i ], onEvaluate1, onEvaluate2 ) ); + this.append( container[ i ] ); + } + } + else if( _.set.is( container ) ) + { + for( let e of container ) + { + _.assert( !this.has( e, onEvaluate1, onEvaluate2 ) ); + this.append( e ); + } + } + else _.assert( 0, 'Unexpected data type' ); + + return this; + } + push( e ) + { + this.original.add( e ); + return this.original.size; + } + pop( e, onEvaluate1, onEvaluate2 ) + { + let self = this; + let container = self.original; + + if( !onEvaluate1 || e === undefined ) + { + if( e === undefined ) + e = self.last(); + let r = container.delete( e ); + _.assert( r === true ); + return e; + } + else + { + // aaa | Dmytro : tabs are removed + // aaa : not clear. explain during call + let last = _.nothing; + self.reduce( ( a, e2 ) => _.entity.equal( e2, e, onEvaluate1, onEvaluate2 ) ? last = e2 : undefined ); + _.assert( last !== _.nothing ); + container.delete( last ); + return last; + } + } + popStrictly( e, onEvaluate1, onEvaluate2 ) + { + let last = this.last(); + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + _.assert( _.entity.equal( last, e, onEvaluate1, onEvaluate2 ), 'Set does not have such an element' ); + + this.original.delete( last ); + return last; + } + removed( e, onEvaluate1, onEvaluate2 ) + { + if( onEvaluate1 || _.routine.is( onEvaluate2 ) ) + { + let from = 0; + let result = 0; + if( _.number.is( onEvaluate1 ) ) + { + from = onEvaluate1; + onEvaluate1 = onEvaluate2; + onEvaluate2 = undefined; + } + + for( let v of this.original ) + { + if( from === 0 ) + { + if( _.entity.equal( v, e, onEvaluate1, onEvaluate2 ) ) + { + this.original.delete( v ); + result++; + } + } + else + { + from--; + } + } + + return result; + } + else + { + return this.original.delete( e ) ? 1 : 0; + } + } + removedOnce( e, onEvaluate1, onEvaluate2 ) + { + let from = 0; + let index = -1; + + if( _.number.is( onEvaluate1 ) ) + { + from = onEvaluate1; + onEvaluate1 = onEvaluate2; + onEvaluate2 = undefined; + } + + for( let v of this.original ) + { + if( from === 0 ) + { + if( _.entity.equal( v, e, onEvaluate1, onEvaluate2 ) ) + { + this.original.delete( v ); + return ++index; + } + } + else + { + from--; + } + index++; + } + return -1; + } + removedOnceLeft( e, onEvaluate1, onEvaluate2 ) + { + return this.removedOnce.apply( this, arguments ); + } + removedOnceRight( e, onEvaluate1, onEvaluate2 ) + { + let temp = [ ... this.original ]; + let to = this.length; + if( _.number.is( onEvaluate1 ) ) + { + to = onEvaluate1; + onEvaluate1 = onEvaluate2; + onEvaluate2 = undefined; + } + + for( let i = to - 1; i >= 0; i-- ) + { + if( _.entity.equal( temp[ i ], e, onEvaluate1, onEvaluate2 ) ) + { + this.original.delete( temp[ i ] ); + return i; + } + } + return -1; + } + removedOnceStrictly( e, onEvaluate1, onEvaluate2 ) + { + let from = 0; + let index = -1; + let result; + + if( _.number.is( onEvaluate1 ) ) + { + from = onEvaluate1; + onEvaluate1 = onEvaluate2; + onEvaluate2 = undefined; + } + + for( let v of this.original ) + { + if( from === 0 ) + { + if( _.entity.equal( v, e, onEvaluate1, onEvaluate2 ) ) + { + if( result === undefined ) + { + this.original.delete( v ); + result = index + 1; + } + else + { + _.assert( 0, () => 'The element ' + _.entity.exportStringDiagnosticShallow( e ) + ' is several times in dstArray' ); + } + } + } + else + { + from--; + } + index++; + } + + _.assert( result !== undefined, 'Container does not have such an element' ); + return result; + } + removedOnceStrictlyLeft( e, onEvaluate1, onEvaluate2 ) + { + return this.removedOnceStrictly.apply( this, arguments ); + } + removedOnceStrictlyRight( e, onEvaluate1, onEvaluate2 ) + { + let to = this.length; + let temp = [ ... this.original ]; + let result; + + if( _.number.is( onEvaluate1 ) ) + { + to = onEvaluate1; + onEvaluate1 = onEvaluate2; + onEvaluate2 = undefined; + } + + for( let i = to - 1; i >= 0; i-- ) + { + if( _.entity.equal( temp[ i ], e, onEvaluate1, onEvaluate2 ) ) + { + if( result === undefined ) + { + this.original.delete( temp[ i ] ); + result = i; + } + else + { + _.assert( 0, () => 'The element ' + _.entity.exportStringDiagnosticShallow( e ) + ' is several times in dstArray' ) + } + } + } + _.assert( result !== undefined, 'Container does not have such an element' ); + return result; + } + remove( e, onEvaluate1, onEvaluate2 ) + { + this.removed.apply( this, arguments ); + return this; + } + removeOnce( e, onEvaluate1, onEvaluate2 ) + { + this.removedOnce.apply( this, arguments ); + return this; + } + removeOnceLeft( e, onEvaluate1, onEvaluate2 ) + { + this.removedOnceLeft.apply( this, arguments ); + return this; + } + removeOnceRight( e, onEvaluate1, onEvaluate2 ) + { + this.removedOnceRight.apply( this, arguments ); + return this; + } + removeOnceStrictly( e, onEvaluate1, onEvaluate2 ) + { + this.removedOnceStrictly.apply( this, arguments ); + return this; + } + removeOnceStrictlyLeft( e, onEvaluate1, onEvaluate2 ) + { + this.removedOnceStrictlyLeft.apply( this, arguments ); + return this; + } + removeOnceStrictlyRight( e, onEvaluate1, onEvaluate2 ) + { + this.removedOnceStrictlyRight.apply( this, arguments ); + return this; + } + empty() + { + this.original.clear(); + } + map( dst, onEach ) + { + let self = this; + let container = self.original; + [ dst, onEach ] = self._filterArguments( ... arguments ); + let length = self.length; + let index = -1; + + if( self._same( dst ) ) + { + for( let e of container ) + { + index += 1; + if( index === length ) + break; + + let e2 = onEach( e, index, container ); + container.delete( e ); + if( e2 !== undefined && e !== e2 ) + container.add( e2 ); + else + container.add( e ); + } + } + else + { + for( let e of container ) + { + index += 1; + let e2 = onEach( e, index, self ); + if( e2 !== undefined ) + dst.append( e2 ); + else + dst.append( e ); + } + } + + return dst; + } + mapLeft( dst, onEach ) + { + return this.map.apply( this, arguments ); + } + mapRight( dst, onEach ) + { + let self = this; + let container = self.original; + let temp = [ ... container ]; + [ dst, onEach ] = self._filterArguments( ... arguments ); + + if( this._same( dst ) ) + { + for( let i = temp.length - 1; i >= 0; i-- ) + { + let e2 = onEach( temp[ i ], i, container ); + if( e2 !== undefined && temp[ i ] !== e2 ) + temp[ i ] = e2; + } + self.empty(); + temp.forEach( ( e ) => self.push( e ) ) + } + else + { + for( let i = temp.length - 1; i >= 0; i-- ) + { + let e2 = onEach( temp[ i ], i, self ); + if( e2 !== undefined ) + dst.append( e2 ); + else + dst.append( temp[ i ] ); + } + } + + return dst; + } + filter( dst, onEach ) + { + let self = this; + let container = self.original; + [ dst, onEach ] = self._filterArguments( ... arguments ); + let length = self.length; + let index = -1; + + if( self._same( dst ) ) + { + + for( let e of container ) + { + index += 1; + if( index === length ) + break; + + let e2 = onEach( e, index, container ); + + if( e2 === undefined ) + { + container.delete( e ); + } + else if( e !== e2 ) + { + container.add( e2 ); + container.delete( e ); + } + else + { + container.add( e ); + } + } + } + else + { + for( let e of container ) + { + index += 1; + let e2 = onEach( e, index, self ); + if( e2 !== undefined ) + dst.append( e2 ); + } + } + + return dst; + } + filterLeft( dst, onEach ) + { + return this.filter.apply( this, arguments ); + } + filterRight( dst, onEach ) + { + let self = this; + let container = self.original; + let temp = [ ... container ]; + [ dst, onEach ] = self._filterArguments( ... arguments ); + + if( self._same( dst ) ) + { + for( let i = temp.length - 1; i >= 0; i-- ) + { + let e2 = onEach( temp[ i ], i, container ); + if( e2 === undefined ) + temp.splice( i, 1 ); + else if( temp[ i ] !== e2 ) + temp[ i ] = e2; + } + self.empty(); + temp.forEach( ( e ) => self.push( e ) ); + } + else + { + for( let i = temp.length - 1; i >= 0; i-- ) + { + let e2 = onEach( temp[ i ], i, self ); + if( e2 !== undefined ) + dst.append( e2 ); + } + } + + return dst; + } + flatFilter( dst, onEach ) + { + let self = this; + let container = self.original; + [ dst, onEach ] = self._filterArguments( ... arguments ); + let length = container.size; + let index = -1; + + if( self._same( dst ) ) + { + for( let e of container ) + { + index += 1; + if( index === length ) + break; + + let e2 = onEach( e, index, self ); + self.remove( e ); + + if( self.IsContainer( e2 ) || self.Is( e2 ) ) + self.appendContainer( e2 ); + else if( e2 !== undefined ) + self.append( e2 ) + else if( e2 === e && e !== undefined ) + self.append( e ); + } + } + else + { + for( let e of container ) + { + index += 1; + let e2 = onEach( e, index, self ); + + if( self.IsContainer( e2 ) || self.Is( e2 ) ) + dst.appendContainer( e2 ); + else if( e2 !== undefined ) + dst.append( e2 ); + } + } + return dst; + } + flatFilterLeft( dst, onEach ) + { + return this.flatFilter.apply( this, arguments ); + } + flatFilterRight( dst, onEach ) + { + let self = this; + let container = self.original; + let temp = [ ... container ]; + [ dst, onEach ] = self._filterArguments( ... arguments ); + let length = container.size; + let index = -1; + + if( self._same( dst ) ) + { + for( let i = temp.length - 1; i >= 0; i-- ) + { + let e2 = onEach( temp[ i ], i, self ); + + if( self.IsContainer( e2 ) || self.Is( e2 ) ) + temp.splice( i, 1, ... e2 ); + else if( e2 !== undefined && e2 !== temp[ i ] ) + temp[ i ] = e2; + else if( e2 === undefined ) + temp.splice( i, 1 ); + self.empty(); + temp.forEach( ( e ) => self.push( e ) ); + } + } + else + { + for( let i = temp.length - 1; i >= 0; i-- ) + { + let e2 = onEach( temp[ i ], i, self ); + + if( self.IsContainer( e2 ) || self.Is( e2 ) ) + dst.appendContainer( e2 ); + else if( e2 !== undefined ) + dst.append( e2 ); + } + } + return dst; + } + once( dst, onEvaluate1, onEvaluate2 ) + { + let self = this; + let container = self.original; + [ dst, dst, onEvaluate1, onEvaluate2 ] = self._onlyArguments( null, dst, onEvaluate1, onEvaluate2 ); + if( self._same( dst ) ) + { + if( onEvaluate1 || _.routine.is( onEvaluate2 ) ) + { + let length = this.length; + let startLength = length; + for( let e of container ) + { + if( length === startLength ) + { + self.append( e ); + length--; + } + else if( length !== 0 ) + { + self.remove( e ); + self.appendOnce( e, onEvaluate1, onEvaluate2 ) + length--; + } + } + } + } + else + { + dst.appendContainerOnce( container, onEvaluate1, onEvaluate2 ); + } + + return dst; + } + onceLeft( dst, onEvaluate1, onEvaluate2 ) + { + return this.once.apply( this, arguments ); + } + onceRight( dst, onEvaluate1, onEvaluate2 ) + { + let self = this; + let container = self.original; + let temp = [ ... container ]; + [ dst, dst, onEvaluate1, onEvaluate2 ] = self._onlyArguments( null, dst, onEvaluate1, onEvaluate2 ); + if( self._same( dst ) ) + { + if( onEvaluate1 || _.routine.is( onEvaluate2 ) ) + { + self.empty(); + for( let i = 0; i < temp.length; i++ ) + self.appendOnce( temp[ i ], onEvaluate1, onEvaluate2 ); + } + } + else + { + for( let i = temp.length - 1; i >= 0; i-- ) + dst.appendOnce( temp[ i ], onEvaluate1, onEvaluate2 ); + } + + return dst; + } + withIndex( index ) + { + let self = this; + return [ ... self.original ][ index ]; + } + first( onEach ) + { + let self = this; + let container = this.original; + if( !container.size ) + return undefined; + if( onEach ) + for( let e of container ) + { + return onEach( e, 0, self ); + } + else + { + for( let e of container ) + { + return e; + } + } + } + last( onEach ) + { + let last = this.reduce( ( a, e ) => e ); + if( onEach ) + return onEach( last, this.length - 1, this ); + else + return last; + } + each( onEach ) + { + return this.eachLeft( onEach ); + } + eachLeft( onEach ) + { + let self = this; + let container = self.original; + let index = -1; + for( let e of container ) + { + index += 1; + onEach( e, index, self ); + } + return self; + } + eachRight( onEach ) + { + let self = this; + let container = self.original; + let temp = [ ... container ]; + for( let i = temp.length - 1; i >= 0; i-- ) + onEach( temp[ i ], i, self ); + return self; + } + reduce( accumulator, onEach ) + { + let self = this; + let container = self.original; + if( arguments[ 1 ] === undefined ) + { + onEach = arguments[ 0 ]; + accumulator = undefined; + } + let index = -1; + for( let e of container ) + { + index += 1; + accumulator = onEach( accumulator, e, index, self ); + } + return accumulator; + } + reduceLeft( accumulator, onEach ) + { + return this.reduce.apply( this, arguments ); + } + reduceRight( accumulator, onEach ) + { + let self = this; + let container = self.original; + let temp = [ ... container ]; + if( arguments[ 1 ] === undefined ) + { + onEach = arguments[ 0 ]; + accumulator = undefined; + } + for( let i = temp.length - 1; i >= 0; i-- ) + { + accumulator = onEach( accumulator, temp[ i ], i, self ); + } + return accumulator; + } + all( onEach ) + { + return this.allLeft( onEach ); + } + allLeft( onEach ) + { + let self = this; + let container = self.original; + let index = -1; + for( let e of container ) + { + index += 1; + let r = onEach( e, index, self ); + if( !r ) + return false; + } + return true; + } + allRight( onEach ) + { + let self = this; + let container = this.original; + let temp = [ ... container ]; + for( let k = temp.length - 1; k >= 0; k-- ) + { + let r = onEach( temp[ k ], k, self ); + if( !r ) + return false; + } + return true; + } + any( onEach ) + { + return this.anyLeft( onEach ); + } + anyLeft( onEach ) + { + let self = this; + let container = self.original; + let index = -1; + for( let e of container ) + { + index += 1; + let r = onEach( e, index, self ); + if( r ) + return true; + } + return false; + } + anyRight( onEach ) + { + let self = this; + let container = self.original; + let temp = [ ... container ]; + for( let k = temp.length - 1; k >= 0; k-- ) + { + let r = onEach( temp[ k ], k, self ); + if( r ) + return true; + } + return false; + } + none( onEach ) + { + return this.noneLeft( onEach ); + } + noneLeft( onEach ) + { + let self = this; + let container = self.original; + let index = -1; + for( let e of container ) + { + index += 1; + let r = onEach( e, index, self ); + if( r ) + return false; + } + return true; + } + noneRight( onEach ) + { + let self = this; + let container = self.original; + let temp = [ ... container ]; + for( let k = temp.length - 1; k >= 0; k-- ) + { + let r = onEach( temp[ k ], k, self ); + if( r ) + return false; + } + return true; + } + left( /* element, fromIndex, onEvaluate1, onEvaluate2 */ ) + { + let element = arguments[ 0 ]; + let fromIndex = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + return _.arraySet.left( this.original, element, fromIndex, onEvaluate1, onEvaluate2 ); + } + right( /* element, fromIndex, onEvaluate1, onEvaluate2 */ ) + { + let element = arguments[ 0 ]; + let fromIndex = arguments[ 1 ]; + let onEvaluate1 = arguments[ 2 ]; + let onEvaluate2 = arguments[ 3 ]; + + _.assert( 1 <= arguments.length && arguments.length <= 4 ); + return _.arraySet.right( this.original, element, fromIndex, onEvaluate1, onEvaluate2 ); + } + reverse( dst ) + { + + let self = this; + let container = self.original; + let temp = [ ... container ]; + + if( !dst ) + dst = this.MakeEmpty(); + else + dst = this.From( dst ); + + if( self._same( dst ) ) + { + self.empty(); + for( let i = temp.length - 1; i >= 0; i-- ) + self.append( temp[ i ] ); + } + else + { + for( let i = temp.length - 1; i >= 0; i-- ) + dst.append( temp[ i ] ); + } + + return dst; + } + join( delimeter ) + { + return [ ... this.original ].join( delimeter ); + } + toArray() + { + return new _.containerAdapter.Array( [ ... this.original ] ); + } + toSet() + { + return this; + } + [ Symbol.iterator ]() + { + let container = this.original; + return container[ Symbol.iterator ](); + } + get length() + { + return this.original.size; + } +} +ContainerAdapterSet.Make = Make; +ContainerAdapterSet.MakeEmpty = MakeEmpty; +ContainerAdapterSet.prototype.make = make; +ContainerAdapterSet.prototype.MakeEmpty = makeEmpty; + +// -- +// meta +// -- + +function ExportTo( dstGlobal, srcGlobal ) +{ + debugger; + let _ = dstGlobal.wTools; + _.assert( _.containerAdapter === srcGlobal.wTools.containerAdapter ); + _.assert( _.mapIs( srcGlobal.wTools.containerAdapter ) ); + if( typeof module !== 'undefined' ) + module[ 'exports' ] = _.containerAdapter; +} + +// -- +// declare +// -- + +const Self = _.containerAdapter; + +// + +var Extension = +{ + + Set : ContainerAdapterSet, + +} + +// + +Object.assign( _.containerAdapter, Extension ); +_.assert( _.containerAdapter === Self ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +if( _global !== _realGlobal_ ) +return ExportTo( _realGlobal_, _global ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1/ContainerAdapterSet.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ContainerAdapterSet_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ContainerAdapterSet_s */ })(); + +/* */ /* begin of file NameTools_s */ ( function NameTools_s() { function NameTools_s_naked() { ( function _NameTools_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +const _ArraySlice = Array.prototype.slice; +const _FunctionBind = Function.prototype.bind; +const _ObjectToString = Object.prototype.toString; +const _ObjectHasOwnProperty = Object.hasOwnProperty; + +// -- +// name and symbol +// -- + +// /** +// * Produce fielded name from string. +// * @param {string} nameString - object coded name or string. +// * @return {object} nameKeyValue - name in key/value format. +// * @method nameFielded +// * @namespace Tools +// */ +// +// function nameFielded( nameString ) +// { +// +// if( _.object.isBasic( nameString ) ) +// { +// return nameString; +// } +// else if( _.strIs( nameString ) ) +// { +// var name = {}; +// name[ nameString ] = nameString; +// return name; +// } +// else _.assert( 0, 'nameFielded :', 'Expects string or ' ); +// +// } + +// + +/** + * Returns name splitted in coded/raw fields. + * @param {object} nameObject - fielded name or name as string. + * @return {object} name splitted in coded/raw fields. + * @method nameUnfielded + * @namespace Tools + */ + +function nameUnfielded( nameObject ) +{ + var name = {}; + + if( _.mapIs( nameObject ) ) + { + var keys = Object.keys( nameObject ); + _.assert( keys.length === 1 ); + name.coded = keys[ 0 ]; + name.raw = nameObject[ name.coded ]; + } + else if( _.strIs( nameObject ) ) + { + name.raw = nameObject; + name.coded = nameObject; + } + else if( _.symbol.is( nameObject ) ) + { + name.raw = nameObject; + name.coded = nameObject; + } + else _.assert( 0, 'nameUnfielded :', 'Unknown arguments' ); + + // _.assert( arguments.length === 1 ); + // _.assert( _.strIs( name.raw ) || _.symbol.is( name.raw ), 'nameUnfielded :', 'not a string, something wrong :', nameObject ); + // _.assert( _.strIs( name.coded ) || _.symbol.is( name.coded ), 'nameUnfielded :', 'not a string, something wrong :', nameObject ); + + return name; +} + +// // +// +// /** +// * Returns name splitted in coded/coded fields. Drops raw part replacing it by coded. +// * @param {object} namesMap - fielded names. +// * @return {object} expected map. +// * @method namesCoded +// * @namespace Tools +// */ +// +// function namesCoded( namesMap ) +// { +// var result = {} +// +// if( _.assert ) +// _.assert( arguments.length === 1 ); +// if( _.assert ) +// _.assert( _.object.isBasic( namesMap ) ); +// +// for( var n in namesMap ) +// result[ n ] = n; +// +// return result; +// } + +// -- +// id +// -- + +function idWithOnlyDate( prefix, postfix ) +{ + var date = new Date; + + _.assert( 0 <= arguments.length && arguments.length <= 2 ); + + prefix = prefix ? prefix : ''; + postfix = postfix ? postfix : ''; + + var d = + [ + date.getFullYear(), + date.getMonth()+1, + date.getDate(), + ].join( '-' ); + + return prefix + d + postfix +} + +// + +function idWithDateAndTime( prefix, postfix, fast ) +{ + var date = new Date; + + _.assert( 0 <= arguments.length && arguments.length <= 3 ); + + prefix = prefix ? prefix : ''; + postfix = postfix ? postfix : ''; + + if( fast ) + return prefix + date.valueOf() + postfix; + + var d = + [ + date.getFullYear(), + date.getMonth()+1, + date.getDate(), + date.getHours(), + date.getMinutes(), + date.getSeconds(), + date.getMilliseconds(), + Math.floor( Math.random()*0x10000 ).toString( 16 ), + ].join( '-' ); + + return prefix + d + postfix +} + +// + +function idWithTime( prefix, postfix ) +{ + var date = new Date; + + _.assert( 0 <= arguments.length && arguments.length <= 2 ); + + prefix = prefix ? prefix : ''; + postfix = postfix ? postfix : ''; + + var d = + [ + String( date.getHours() ) + String( date.getMinutes() ) + String( date.getSeconds() ), + String( date.getMilliseconds() ), + Math.floor( Math.random()*0x10000 ).toString( 16 ), + ].join( '-' ); + + return prefix + d + postfix +} + +// + +/* aaa : reimplement it more properly | Dmytro : new implementation is written below, it use futures of random RFC4122 GUIDs v4. Guids can be more complex for example https://www.npmjs.com/package/uuid */ + +function idWithGuid() +{ + + _.assert( arguments.length === 0 ); + + var result = + [ + s4() + s4(), + s4(), + s4(), + s4(), + s4() + s4() + s4(), + ].join( '-' ); + + return result; + + function s4() + { + return Math.floor( ( 1 + Math.random() ) * 0x10000 ) + .toString( 16 ) + .substring( 1 ); + } + +} + +// + +// function idWithGuid() +// { +// let guid = '$$$$$$$$-$$$$-4$$$-y$$$-$$$$$$$$$$$$'; +// +// return guid.replace( /[$y]/g, replaceSymbol ); +// +// /* */ +// +// function replaceSymbol( sym ) +// { +// let r = Math.random() * 16 | 0; +// return ( sym === '$' ? r : ( r & 0x3 | 0x8 ) ).toString( 16 ); +// } +// } + +// + +/** + * Routine idWithTimeGuid() returns random GUID of RFC4122 standard. + * GUID v4 is used. + * Routine does not accepts parameters. + * + * @example + * _.idWithTimeGuid() + * // returns '0d796bf0-dc89-4ccd-b751-01430f6ec71f' + * + * @return { String } - Returns GUID v4. + * @function idWithTimeGuid + * @namespace Tools + */ + +function idWithTimeGuid() +{ + let guid = '$$$$$$$$-$$$$-4$$$-y$$$-$$$$$$$$$$$$'; + let date = _.time.now(); + + _.assert( arguments.length === 0 ); + + return guid.replace( /[$y]/g, replaceSymbol ); + + /* */ + + function replaceSymbol( sym ) + { + let r = ( date + Math.random() * 16 ) % 16 | 0; + date = Math.floor( date / 16 ); + return ( sym === '$' ? r : ( r & 0x3 | 0x8 ) ).toString( 16 ); + } +} + +// + +var idWithInt = (function() +{ + + var counter = 0; + + return function() + { + _.assert( arguments.length === 0, 'Expects no arguments' ); + counter += 1; + return counter; + } + +})(); + +// -- +// declare +// -- + +const Proto = +{ + + // name and symbol + + // nameFielded, /* experimental */ + nameUnfielded, /* xxx : move */ + // namesCoded, /* experimental */ + + // id + + idWithOnlyDate, + idWithDateAndTime, + idWithTime, + idWithGuid, + idWithTimeGuid, + idWithInt, + +} + +_.props.extend( _, Proto ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1/NameTools.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, NameTools_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file NameTools_s */ })(); + +/* */ /* begin of file StrBasic_s */ ( function StrBasic_s() { function StrBasic_s_naked() { (function _StrBasic_s_() +{ + +'use strict'; + +/* + +qqq : write article "strIsolate* difference" + +*/ + +// + +const _global = _global_; +const _ = _global_.wTools; + +const _ArraySlice = Array.prototype.slice; +const _FunctionBind = Function.prototype.bind; +const _ObjectToString = Object.prototype.toString; +const _ObjectHasOwnProperty = Object.hasOwnProperty; + +const _longSlice = _.longSlice; +const strType = _.entity.strType; + +// -- +// dichotomy +// -- + +function strIsHex( src ) +{ + _.assert( _.strIs( src ) ); + _.assert( arguments.length === 1 ); + let parsed = parseInt( src, 16 ) + if( isNaN( parsed ) ) + return false; + return parsed.toString( 16 ).length === src.length; +} + +// + +function strIsMultilined( src ) +{ + if( !_.strIs( src ) ) + return false; + if( src.indexOf( '\n' ) !== -1 ) + return true; + return false; +} + +// + +function strHasAny( src, ins ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.arrayIs( ins ) ) + { + for( let i = 0 ; i < ins.length ; i++ ) + if( _.strHas( src, ins[ i ] ) ) + return true; + return false; + } + + return _.strHas( src, ins ); +} + +// + +function strHasAll( src, ins ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.arrayIs( ins ) ) + { + for( let i = 0 ; i < ins.length ; i++ ) + if( !_.strHas( src, ins[ i ] ) ) + return false; + return true; + } + + return _.strHas( src, ins ); +} + +// + +function strHasNone( src, ins ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.arrayIs( ins ) ) + { + for( let i = 0 ; i < ins.length ; i++ ) + if( _.strHas( src, ins[ i ] ) ) + return false; + return true; + } + + return !_.strHas( src, ins ); +} + +// + +function strHasSeveral( src, ins ) +{ + let result = 0; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.arrayIs( ins ) ) + { + for( let i = 0 ; i < ins.length ; i++ ) + if( _.strHas( src, ins[ i ] ) ) + result += 1; + return result; + } + + return _.strHas( src, ins ) ? 1 : 0; +} + +// + +function strsAnyHas( srcs, ins ) +{ + _.assert( _.strIs( srcs ) || _.strsAreAll( srcs ) ); + _.assert( _.strIs( ins ) ); + + if( _.strIs( srcs ) ) + return _.strHas( srcs, ins ); + + return srcs.some( ( src ) => _.strHas( src, ins ) ); +} + +// + +function strsAllHas( srcs, ins ) +{ + _.assert( _.strIs( srcs ) || _.strsAreAll( srcs ) ); + _.assert( _.strIs( ins ) ); + + if( _.strIs( srcs ) ) + return _.strHas( srcs, ins ); + + return srcs.every( ( src ) => _.strHas( src, ins ) ); +} + +// + +function strsNoneHas( srcs, ins ) +{ + _.assert( _.strIs( srcs ) || _.strsAreAll( srcs ) ); + _.assert( _.strIs( ins ) ); + + if( _.strIs( srcs ) ) + return !_.strHas( srcs, ins ); + + return srcs.every( ( src ) => !_.strHas( src, ins ) ); +} + +// -- +// evaluator +// -- + +/** + * Returns number of occurrences of a substring( ins ) in a string( src ), + * Expects two objects in order: source string, substring. + * Returns zero if one of arguments is empty string. + * + * @param {string} src - Source string. + * @param {string} ins - Substring. + * @returns {Number} Returns number of occurrences of a substring in a string. + * + * @example + * _.strCount( 'aabab', 'ab' ); + * // returns 2 + * + * @example + * _.strCount( 'aabab', '' ); + * // returns 0 + * + * @method strCount + * @throws { Exception } Throw an exception if( src ) is not a String. + * @throws { Exception } Throw an exception if( ins ) is not a String. + * @throws { Exception } Throw an exception if( arguments.length ) is not equal 2. + * @namespace Tools + * + */ + +function strCount( src, ins ) +{ + let result = 0; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ) ); + _.assert( _.regexpLike( ins ) ); + + let i = 0; + do + { + // let found = _.strLeft( src, ins, [ i, src.length ] ); + let found = _.strLeft_( src, ins, [ i, src.length-1 ] ); + if( found.entry === undefined ) + break; + i = found.index + found.entry.length; + if( !found.entry.length ) + i += 1; + result += 1; + _.assert( i !== -1, 'not tested' ); + } + while( i !== -1 && i < src.length ); + + return result; +} + +// + +function strStripCount( src, ins ) +{ + return _.strCount( _.str.lines.strip( src ), _.str.lines.strip( ins ) ); +} + +// + +function strsShortest( src ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.strIs( src ) || _.argumentsArray.like( src ) ); + if( _.strIs( src ) ) + return src; + return src.sort( ( a, b ) => a.length - b.length )[ 0 ]; +} + +// + +function strsLongest() +{ + _.assert( arguments.length === 1 ); + _.assert( _.strIs( src ) || _.argumentsArray.like( src ) ); + if( _.strIs( src ) ) + return src; + return src.sort( ( a, b ) => b.length - a.length )[ 0 ]; +} + +// -- +// replacer +// -- + +function _strRemoved( srcStr, insStr ) +{ + let result = srcStr; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( srcStr ), 'Expects string {-src-}' ); + + if( _.longIs( insStr ) ) + { + for( let i = 0; i < insStr.length; i++ ) + result = result.replace( insStr[ i ], '' ); + } + else + { + result = result.replace( insStr, '' ); + } + // if( !_.longIs( insStr ) ) + // { + // result = result.replace( insStr, '' ); + // } + // else + // { + // for( let i = 0; i < insStr.length; i++ ) + // { + // result = result.replace( insStr[ i ], '' ); + // } + // } + + return result; +} + +// + +/** +* Finds substring or regexp ( insStr ) first occurrence from the source string ( srcStr ) and removes it. +* Returns original string if source( src ) does not have occurrence of ( insStr ). +* +* @param { String } srcStr - Source string to parse. +* @param { String } insStr - String/RegExp that is to be dropped. +* @returns { String } Returns string with result of substring removement. +* +* @example +* _.strRemove( 'source string', 's' ); +* // returns ource tring +* +* @example +* _.strRemove( 'example', 's' ); +* // returns example +* +* @function strRemove +* @throws { Exception } Throws a exception if( srcStr ) is not a String. +* @throws { Exception } Throws a exception if( insStr ) is not a String or a RegExp. +* @throws { Exception } Throws a exception if( arguments.length ) is not equal 2. +* @namespace Tools +* +*/ + +/* +aaa : extend coverage of routines strRemove, strReplace, make sure tests cover regexp cases +Dmytro : coverage is extended +*/ + +function strRemove( srcStr, insStr ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.longIs( srcStr ) || _.regexpLike( srcStr ), () => 'Expects string or array of strings {-srcStr-}, but got ' + _.entity.strType( srcStr ) ); + + if( _.longIs( insStr ) ) + { + for( let i = 0 ; i < insStr.length ; i++ ) + _.assert( _.strIs( insStr[ i ] ) || _.regexpIs( insStr[ i ] ), () => 'Expects string/regexp or array of strings/regexps' ); + } + else + { + _.assert( _.strIs( insStr ) || _.regexpIs( insStr ), () => 'Expects string/regexp or array of strings/regexps' ); + } + //_.assert( _.longIs( insStr ) || _.regexpLike( insStr ), () => 'Expects string/regexp or array of strings/regexps {-begin-}' ); + + let result = []; + + if( _.strIs( srcStr ) && !_.longIs( srcStr ) ) + return _._strRemoved( srcStr, insStr ); + + srcStr = _.array.as( srcStr ); + + for( let s = 0; s < srcStr.length; s++ ) + { + let src = srcStr[ s ]; + result[ s ] = _._strRemoved( src, insStr ); + } + + if( !_.longIs( srcStr ) ) + return result[ 0 ]; + + return result; +} + +// // +// +// /** +// * Prepends string( begin ) to the source( src ) if prefix( begin ) is not match with first chars of string( src ), +// * otherwise returns original string. +// * @param { String } src - Source string to parse. +// * @param { String } begin - String to prepend. +// * +// * @example +// * _.strPrependOnce( 'test', 'test' ); +// * // returns 'test' +// * +// * @example +// * _.strPrependOnce( 'abc', 'x' ); +// * // returns 'xabc' +// * +// * @returns { String } Returns result of prepending string( begin ) to source( src ) or original string. +// * @function strPrependOnce +// * @namespace Tools +// */ +// +// function strPrependOnce( src, begin ) +// { +// _.assert( _.strIs( src ) && _.strIs( begin ), 'Expects {-src-} and {-begin-} as strings' ); +// if( src.lastIndexOf( begin, 0 ) === 0 ) +// return src; +// else +// return begin + src; +// } +// +// // +// +// /** +// * Appends string( end ) to the source( src ) if postfix( end ) is not match with last chars of string( src ), +// * otherwise returns original string. +// * @param {string} src - Source string to parse. +// * @param {string} end - String to append. +// * +// * @example +// * _.strAppendOnce( 'test', 'test' ); +// * // returns 'test' +// * +// * @example +// * _.strAppendOnce( 'abc', 'x' ); +// * // returns 'abcx' +// * +// * @returns {string} Returns result of appending string( end ) to source( src ) or original string. +// * @function strAppendOnce +// * @namespace Tools +// */ +// +// function strAppendOnce( src, end ) +// { +// _.assert( _.strIs( src ) && _.strIs( end ), 'Expects {-src-} and {-end-} as strings' ); +// if( src.indexOf( end, src.length - end.length ) === -1 ) +// return src + end; +// else +// return src; +// } + +// -- +// etc +// -- + +/** + * Replaces occurrence of each word from array( ins ) in string( src ) with word + * from array( sub ) considering it position. + * @param {string} src - Source string to parse. + * @param {array} ins - Array with strings to replace. + * @param {string} sub - Array with new strings. + * @returns {string} Returns string with result of replacements. + * + * @example + * _.strReplaceWords( ' my name is', [ 'my', 'name', 'is' ], [ 'your', 'cars', 'are' ] ) + * // returns ' your cars are' + * + * @method strReplaceWords + * @throws { Exception } Throws a exception if( ins ) is not a Array. + * @throws { Exception } Throws a exception if( sub ) is not a Array. + * @throws { TypeError } Throws a exception if( src ) is not a String. + * @throws { Exception } Throws a exception if( arguments.length ) is not equal 3. + * @namespace Tools + * + */ + +function strReplaceWords( src, ins, sub ) +{ + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + _.assert( _.strIs( src ) ); + _.assert( _.arrayIs( ins ) ); + _.assert( _.arrayIs( sub ) ); + _.assert( ins.length === sub.length ); + + let result = src; + for( let i = 0 ; i < ins.length ; i++ ) + { + _.assert( _.strIs( ins[ i ] ) ); + let r = new RegExp( '(\\W|^)' + ins[ i ] + '(?=\\W|$)', 'gm' ); + result = result.replace( r, function( original ) + { + if( original[ 0 ] === sub[ i ][ 0 ] ) + return sub[ i ]; + else + return original[ 0 ] + sub[ i ]; + // if( original[ 0 ] !== sub[ i ][ 0 ] ) + // return original[ 0 ] + sub[ i ]; + // else + // return sub[ i ]; + }); + } + + return result; +} + +// -- +// etc +// -- + +/** + * Routine strCommonLeft() finds common symbols from the begining of all strings passed to arguments list. + * Routine uses first argument {-ins-} as a pattern. If some string doesn`t have the same first symbols + * as the pattern {-ins-}, the function returns an empty string. + * Otherwise, it returns the symbol sequence that appears from the start of each string. + * + * @param { String } ins - Sequence of possible symbols. + * @param { String } ... - Another strings to search common sequence of symbols. + * + * @example + * _.strCommonLeft( 'abcd', 'ab', 'abc', 'abd' ); + * // returns 'ab' + * + * @example + * _.strCommonLeft( 'abcd', 'abc', 'abcd' ); + * // returns 'abc' + * + * @example + * _.strCommonLeft( 'abcd', 'abc', 'd' ) + * // returns '' + * + * @returns { String } - Returns found common symbols. + * @function strCommonLeft + * @throws { Error } If {-ins-} is not a String. + * @namespace Tools + * + */ + +function strCommonLeft( ins ) +{ + + if( arguments.length === 0 ) + return ''; + if( arguments.length === 1 ) + return ins; + + _.assert( _.strIs( ins ) ); + + let length = +Infinity; + + for( let a = 0 ; a < arguments.length ; a++ ) + { + let src = arguments[ a ]; + length = Math.min( length, src.length ); + } + + let i = 0; + for( ; i < length ; i++ ) + for( let a = 1 ; a < arguments.length ; a++ ) + { + let src = arguments[ a ]; + if( src[ i ] !== ins[ i ] ) + return ins.substring( 0, i ); + } + + return ins.substring( 0, i ); +} + +// + +/** + * Routine strCommonRight() finds common symbols from the end of all strings passed to arguments list. + * Routine uses first argument {-ins-} as a pattern. If some string doesn`t have the same end symbols + * as the pattern {-ins-}, the function returns an empty string. + * Otherwise, it returns the symbol sequence that appears from the end of each string. + * + * @param { String } ins - Sequence of possible symbols. + * @param { String } ... - Another strings to search common sequence of symbols. + * + * @example + * _.strCommonRight( 'same', 'came', 'me', 'code' ); + * // returns 'e' + * + * @example + * _.strCommonRight( 'add', 'dd'+'d', 'hdd' ); + * // returns 'dd' + * + * @example + * _.strCommonRight( 'abcd', 'abc', 'd' ) + * // returns '' + * + * @returns { String } - Returns found common symbols. + * @function strCommonRight + * @throws { Error } If {-ins-} is not a String. + * @namespace Tools + * + */ + +function strCommonRight( ins ) +{ + + if( arguments.length === 0 ) + return ''; + if( arguments.length === 1 ) + return ins; + + _.assert( _.strIs( ins ) ); + + let length = +Infinity; + + for( let a = 0 ; a < arguments.length ; a++ ) + { + let src = arguments[ a ]; + length = Math.min( length, src.length ); + } + + let i = 0; + for( ; i < length ; i++ ) + for( let a = 1 ; a < arguments.length ; a++ ) + { + let src = arguments[ a ]; + if( src[ src.length - i - 1 ] !== ins[ ins.length - i - 1 ] ) + return ins.substring( ins.length-i ); + } + + return ins.substring( ins.length-i ); +} + +// + +/** + * Routine strRandom() makes string with random length with random symbols defined + * by option {-o.alphabet-}. + * Routine accepts two types of parameter. First of them is options map {-o-}, the second + * is Number (Range) {-length-}. + * + * First set of parameters + * @param { Map } o - Options map. + * @param { Number|Range } o.length - The length of random string. + * The generated string may has fixed length if {-o.length-} defined by a number. If {-o.length-} + * defined by a Range, then length of generated string is variable. + * @param { String } o.alphabet - String with symbols for generated string. + * Default range of symbols is 'a' - 'z'. + * + * Second set of parameters + * @param { Number|Range } length - The length of random string. + * The generated string may has fixed length if {-o.length-} defined by a number. If {-o.length-} + * defined by a Range, then length of generated string is variable. + * @param { String } o.alphabet - String with symbols for generated string. + * + * @example + * _.strRandom( 0 ); + * // returns '' + * + * @example + * _.strRandom( 2 ); + * // returns 'vb' + * // string with 2 random symbols from 'a' to 'z' + * + * @example + * _.strRandom( [ 1, 5 ] ) + * // returns 'soyx' + * // string with length from 1 to 5 and random symbols from 'a' to 'z' + * + * @example + * _.strRandom( { length : 3, alphabet : 'a' } ) + * // returns 'aaa' + * // string with length 3 and symbol 'a' + * + * @example + * _.strRandom( { length : [ 1, 5 ], alphabet : 'ab' } ) + * // returns 'aabab' + * // string with length from 1 to 5 and random symbols 'a' and 'b' + * + * @returns { String } - Returns string with random length and symbols. + * @function strRandom + * @throws { Error } If arguments.length is less or more then one. + * @throws { Error } If options map {-o-} has unnacessary fields. + * @throws { Error } If parameter {-length-} or option {-o.length-} is not a Number and not a Range. + * @namespace Tools + * + */ + +function strRandom( o ) +{ + if( !_.mapIs( o ) ) + o = { length : o } + + o = _.routine.options( strRandom, o ); + + if( _.number.is( o.length ) ) + o.length = [ o.length, o.length+1 ]; + if( o.alphabet === null ) + o.alphabet = _.strAlphabetFromRange([ 'a', 'z' ]); + + _.assert( _.intervalIs( o.length ) ); + _.assert( arguments.length === 1 ); + + let length = o.length[ 0 ]; + if( o.length[ 0 ]+1 !== o.length[ 1 ] ) + { + length = _.intRandom( o.length ); + } + + let result = ''; + for( let i = 0 ; i < length ; i++ ) + { + result += o.alphabet[ _.intRandom( o.alphabet.length ) ]; + } + return result; +} + +strRandom.defaults = +{ + length : null, + alphabet : null, +} + +// + +/** + * Routine strAlphabetFromRange() generates a string with a sequence of symbols started from + * first element of {-range-} and ended on previous element before last. + * + * @param { Range } range - Range of symbols. It is two elements array. Elements of {-range-} + * should have a String or a Number type. + * + * @example + * _.strAlphabetFromRange( [ 97, 98 ] ); + * // returns 'a' + * + * @example + * _.strAlphabetFromRange( 97, 100 ); + * // returns 'abc' + * + * @example + * _.strAlphabetFromRange( [ 'a', 'b' ] ); + * // returns 'a' + * + * @example + * _.strAlphabetFromRange( 'a', 'd' ); + * // returns 'abc' + * + * @example + * _.strAlphabetFromRange( [ 'a', 98 ] ); + * // returns 'a' + * + * @example + * _.strAlphabetFromRange( 97, 'd' ); + * // returns 'abc' + * + * @returns { String } - Returns string with sequence of symbols. + * @function strAlphabetFromRange + * @throws { Error } If arguments.length is less then one. + * @throws { Error } If range.length is less or more then two. + * @throws { Error } If range[ 0 ] or range[ 1 ] is not a Number and not a String. + * @namespace Tools + * + */ + +function strAlphabetFromRange( range ) +{ + _.assert( _.arrayIs( range ) && range.length === 2 ) + _.assert( _.strIs( range[ 0 ] ) || _.number.is( range[ 0 ] ) ); + _.assert( _.strIs( range[ 1 ] ) || _.number.is( range[ 1 ] ) ); + if( _.strIs( range[ 0 ] ) ) + range[ 0 ] = range[ 0 ].charCodeAt( 0 ); + if( _.strIs( range[ 1 ] ) ) + range[ 1 ] = range[ 1 ].charCodeAt( 0 ); + let result = String.fromCharCode( ... _.longFromRange([ range[ 0 ], range[ 1 ] ]) ); + return result; +} + +// -- +// formatter +// -- + +function strForRange( range ) +{ + let result; + + _.assert( arguments.length === 1 ); + _.assert( _.arrayIs( range ) ); + + result = '[ ' + range[ 0 ] + '..' + range[ 1 ] + ' ]'; + + return result; +} + +// + +function strForCall() +{ + let nameOfRoutine = arguments[ 0 ]; + let args = arguments[ 1 ]; + let ret = arguments[ 2 ]; + let o = arguments[ 3 ]; + + let result = nameOfRoutine + '( '; + let first = true; + + _.assert( _.arrayIs( args ) || _.object.isBasic( args ) ); + _.assert( arguments.length <= 4 ); + + _.each( args, function( e, k ) + { + + if( first === false ) + result += ', '; + + if( _.object.isBasic( e ) ) + result += k + ' :' + _.entity.exportString( e, o ); + else + result += _.entity.exportString( e, o ); + + first = false; + + }); + + result += ' )'; + + if( arguments.length >= 3 ) + result += ' -> ' + _.entity.exportString( ret, o ); + + return result; +} + +// + +function strDifference( src1, src2 ) +{ + _.assert( _.strIs( src1 ) ); + _.assert( _.strIs( src2 ) ); + + if( src1 === src2 ) + return false; + + let l = Math.min( src1.length, src2.length ); + for( let i = 0 ; i < l ; i++ ) + if( src1[ i ] !== src2[ i ] ) + return src1.substr( 0, i ) + '*'; + + return src1.substr( 0, l ) + '*'; +} + +// -- +// transformer +// -- + +/** + * Returns string with first letter converted to upper case. + * Expects one object: the string to be formatted. + * + * @param {string} src - Source string. + * @returns {String} Returns a string with the first letter capitalized. + * + * @example + * _.strCapitalize( 'test string' ); + * // returns Test string + * + * @example + * _.strCapitalize( 'another_test_string' ); + * // returns Another_test_string + * + * @method strCapitalize + * @throws { Exception } Throw an exception if( src ) is not a String. + * @throws { Exception } Throw an exception if( arguments.length ) is not equal 1. + * @namespace Tools + * + */ + +function strCapitalize( src ) +{ + _.assert( _.strIs( src ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + /*_.assert( src.length > 0 );*/ + /*_.assert( src.match(/(^\W)/) === null );*/ + + if( src.length === 0 ) + return src; + + return src[ 0 ].toUpperCase() + src.substring( 1 ); +} + +// + +/** + * The routine `strDecapitalize` returns string with first letter converted to lower case. + * Expects one object: the string to be formatted. + * + * @param {string} src - Source string. + * @returns {String} Returns a string with the first letter lowercased. + * + * @example + * _.strCapitalize( 'Test string' ); + * // returns test string + * + * @example + * _.strCapitalize( 'Another_test_string' ); + * // returns another_test_string + * + * @method strDecapitalize + * @throws { Exception } Throw an exception if( src ) is not a String. + * @throws { Exception } Throw an exception if( arguments.length ) is not equal 1. + * @namespace Tools + * + */ + +function strDecapitalize( src ) +{ + _.assert( _.strIs( src ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( src.length === 0 ) + return src; + + return src[ 0 ].toLowerCase() + src.substring( 1 ); +} + +// + +/** + * The routine `strSign` adds {- prefix -} to a source string. + * @param { String } src - Source string. + * @param { String } prefix - String to be added. + * @returns { String } Returns string with added {- prefix -} character. + * + * @example + * _.strSign( 'a' ); + * // returns 'wA' + * + * @example + * _.strSign( 'Tools' ); + * // returns 'wTools' + * + * @example + * _.strSign( 'A', 'q' ); + * // returns 'qA' + * + * @method strSign + * @throws { Exception } If( src ) is not a String. + * @throws { Exception } If( arguments.length ) is not equal to 1. + * @throws { Exception } If( {- prefix -}.length ) is not equal to 1. + * @namespace Tools + * + */ + +function strSign( src, prefix ) +{ + _.assert( _.strIs( src ) && src.length > 0, '{- src -} must be non empty string'); + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects one or two arguments' ); + + if( prefix === undefined ) + prefix = 'w'; + + _.assert( prefix.length === 1 ); + _.assert( !_.strIsSigned( src, prefix ), 'Expects not signed string' ); + + return prefix + src[ 0 ].toUpperCase() + src.substring( 1 ); +} + +// + +/** + * The routine `strDesign` removes {- prefix -} character if it's placed before uppercase letter in a source string. + * @param { String } src - Source string. + * @param { String } prefix - String to be removed. + * @returns { String } Returns string with removed {- prefix -} character. + * + * @example + * _.strDesign( 'wA' ); + * // returns 'A' + * + * @example + * _.strDesign( 'wTools' ); + * // returns 'Tools' + * + * @example + * _.strDesign( 'qA', 'q' ); + * // returns 'A' + * + * @method strDesign + * @throws { Exception } If( src ) is not a String. + * @throws { Exception } If( arguments.length ) is not equal to 1. + * @throws { Exception } If( {- prefix -}.length ) is not equal to 1. + * @namespace Tools + * + */ + +function strDesign( src, prefix ) +{ + _.assert( _.strIs( src ) && src.length > 0, '{- src -} must be non empty string'); + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects one or two arguments' ); + + if( prefix === undefined ) + prefix = 'w'; + + _.assert( prefix.length === 1 ); + _.assert( _.strIsSigned( src, prefix ), 'Expects signed string' ); + + return src.substring( 1 ); +} + +// + +/** + * The routine `strIsSigned` checks a source string to be signed. + * @param { String } src - Source string. + * @param { String } prefix - string to be checked. + * @returns { String } Returns true if string has {- prefix -} as the first character and a capital letter as the second, otherwise - returns false + * + * @example + * _.strIsSigned( 'wa' ); + * // returns false + * + * @example + * _.strIsSigned( 'wTools' ); + * // returns true + * + * @example + * _.strIsSigned( 'w123' ); + * // returns false + * + * @example + * _.strIsSigned( 'qA', 'q' ); + * // returns true + * + * @method strIsSigned + * @throws { Exception } If( src ) is not a String. + * @throws { Exception } If( arguments.length ) is not equal to 1. + * @throws { Exception } If( {- prefix -}.length ) is not equal to 1. + * @namespace Tools + * + */ + +function strIsSigned( src, prefix ) +{ + _.assert( _.strIs( src ) && src.length > 0, '{- src -} must be non empty string'); + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects one or two arguments' ); + + if( !prefix ) + prefix = 'w'; + + _.assert( prefix.length === 1 ); + + return new RegExp( `^${prefix}[A-Z0-9]` ).test( src ); + +} + +// + +/** + * Disables escaped characters in source string( src ). + * Example: '\n' -> '\\n', '\u001b' -> '\\u001b' etc. + * Returns string with disabled escaped characters, source string if nothing changed or empty string if source is zero length. + * @param {string} src - Source string. + * @returns {string} Returns string with disabled escaped characters. + * + * @example + * _.strEscape( '\nhello\u001bworld\n' ); + * // returns '\nhello\u001bworld\n' + * + * @example + * _.strEscape( 'string' ); + * // returns 'string' + * + * @example + * _.strEscape( 'str\'' ); + * // returns 'str\'' + * + * @example + * _.strEscape( '' ); + * // returns '' + * + * @method strEscape + * @throw { Exception } If( src ) is not a String. + * @namespace Tools + * + */ + +function strEscape( o ) +{ + + // 007f : '' + // . . . + // 009f : 'Ÿ' + + // 00ad : '­' + + // \' single quote byte 0x27 in ASCII encoding + // \' double quote byte 0x22 in ASCII encoding + // \\ backslash byte 0x5c in ASCII encoding + // \b backspace byte 0x08 in ASCII encoding + // \f form feed - new page byte 0x0c in ASCII encoding + // \n line feed - new line byte 0x0a in ASCII encoding + // \r carriage return byte 0x0d in ASCII encoding + // \t horizontal tab byte 0x09 in ASCII encoding + // \v vertical tab byte 0x0b in ASCII encoding + // source : http://en.cppreference.com/w/cpp/language/escape + + if( _.strIs( o ) ) + o = { src : o } + + _.assert( _.strIs( o.src ), 'Expects string {-o.src-}, but got', _.entity.strType( o.src ) ); + _.routine.options( strEscape, o ); + + let result = ''; + let stringWrapperCode = o.stringWrapper.charCodeAt( 0 ); + for( let s = 0 ; s < o.src.length ; s++ ) + { + let code = o.src.charCodeAt( s ); + + if( o.stringWrapper === '`' && code === 0x24 /* $ */ ) + { + result += '\\$'; + } + else if( o.stringWrapper && code === stringWrapperCode ) + { + result += '\\' + o.stringWrapper; + } + else if( 0x007f <= code && code <= 0x009f || code === 0x00ad /*|| code >= 65533*/ ) + { + result += _.strCodeUnicodeEscape( code ); + } + else switch( code ) + { + + case 0x5c /* '\\' */ : + result += '\\\\'; + break; + + case 0x08 /* '\b' */ : + result += '\\b'; + break; + + case 0x0c /* '\f' */ : + result += '\\f'; + break; + + case 0x0a /* '\n' */ : + result += '\\n'; + break; + + case 0x0d /* '\r' */ : + result += '\\r'; + break; + + case 0x09 /* '\t' */ : + result += '\\t'; + break; + + // /* xxx : extend coverage of routine _.strEscape. don't forget this test case */ + // case 0x0b /* '\v' */ : + // result += '\\v'; + // break; + + default : + if( code < 32 ) + { + result += _.strCodeUnicodeEscape( code ); + } + else + { + result += String.fromCharCode( code ); + } + + } + + } + + return result; +} + +strEscape.defaults = +{ + src : null, + stringWrapper : '\'', + charsToEscape : null, /* xxx : qqq : implement */ +} + +// + +/** + * Converts number {-code-} into unicode representation. + * Returns result of conversion as new string. + * + * @param { Number } code - The code to convert into unicode representation. + * + * @example + * _.strCodeUnicodeEscape( 70 ); + * // returns '\\u0046' + * + * @example + * _.strCodeUnicodeEscape( 77 ); + * // returns '\\u004d' + * + * @returns { String } - Returns string with result of conversion. + * @function strCodeUnicodeEscape + * @throws { Exception } If arguments.length is less or more then one. + * @throws { Exception } If {-src-} is not a Number. + * @namespace Tools + * + */ + +function strCodeUnicodeEscape( code ) +{ + let result = ''; + + _.assert( _.number.is( code ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + let h = code.toString( 16 ); + let d = _.strDup( '0', 4-h.length ) + h; + + result += '\\u' + d; + + return result; +} + +// + +/** + * Converts source string {-str-} into unicode representation by replacing each symbol with its escaped unicode equivalent. + * Returns result of conversion as new string or empty string if source has zero length. + * + * @param { String } str - Source string to parse. + * + * @example + * _.strUnicodeEscape( 'abc' ); + * // returns \u0061\u0062\u0063; + * + * @example + * _.strUnicodeEscape( 'world' ); + * // returns \u0077\u006f\u0072\u006c\u0064 + * + * @example + * _.strUnicodeEscape( '//test//' ); + * // returns \u002f\u002f\u0074\u0065\u0073\u0074\u002f\u002f + * + * @returns { String } - Returns string with result of conversion. + * @function strUnicodeEscape + * @throws { Exception } If arguments.length is less or more then one. + * @throws { Exception } If {-src-} is not a String. + * @namespace Tools + * + */ + +function strUnicodeEscape( src ) +{ + let result = ''; + + _.assert( _.strIs( src ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + for( let i = 0 ; i < src.length ; i++ ) + { + let code = src.charCodeAt( i ); + result += _.strCodeUnicodeEscape( code ); + } + + return result; +} + +// + +function strReverse( srcStr ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + let result = ''; + for( let i = 0 ; i < srcStr.length ; i++ ) + result = srcStr[ i ] + result; + return result; +} + +// -- +// splitter +// -- + +/** + * Parses a source string( src ) and separates numbers and string values + * in to object with two properties: 'str' and 'number', example of result: ( { str: 'bd', number: 1 } ). + * + * @param {string} src - Source string. + * @returns {object} Returns the object with two properties:( str ) and ( number ), + * with values parsed from source string. If a string( src ) doesn't contain number( s ), + * function returns the object with value of string( src ). + * + * @example + * _.strSplitStrNumber( 'bd1' ); + * // returns { str: 'bd', number: 1 } + * + * @example + * _.strSplitStrNumber( 'bdxf' ); + * // returns { str: 'bdxf' } + * + * @method strSplitStrNumber + * @throws { Exception } Throw an exception if( src ) is not a String. + * @throws { Exception } Throw an exception if no argument provided. + * @namespace Tools + * + */ + +function strSplitStrNumber( src ) +{ + let result = Object.create( null ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ) ); + + let mnumber = src.match(/\d+/); + if( mnumber && mnumber.length ) + { + let mstr = src.match(/[^\d]*/); + result.str = mstr[ 0 ]; + result.number = _.number.from( mnumber[ 0 ] ); + } + else + { + result.str = src; + } + + return result; +} + +// + +function strSplitChunks( o ) +{ + let result = Object.create( null ); + result.chunks = []; + + if( arguments.length === 2 ) + { + o = arguments[ 1 ] || Object.create( null ); + o.src = arguments[ 0 ]; + } + else + { + _.assert( arguments.length === 1, 'Expects single argument' ); + if( _.strIs( arguments[ 0 ] ) ) + o = { src : arguments[ 0 ] }; + } + + _.routine.options( strSplitChunks, o ); + _.assert( _.strIs( o.src ), 'Expects string (-o.src-), but got', _.entity.strType( o.src ) ); + + if( !_.regexpIs( o.prefix ) ) + o.prefix = RegExp( _.regexpEscape( o.prefix ), 'm' ); + + if( !_.regexpIs( o.postfix ) ) + o.postfix = RegExp( _.regexpEscape( o.postfix ), 'm' ); + + let src = o.src; + + /* */ + + let line = 0; + let column = 0; + let chunkIndex = 0; + let begin = -1; + let end = -1; + do + { + + /* begin */ + + begin = src.search( o.prefix ); + if( begin === -1 ) begin = src.length; + + /* text chunk */ + + if( begin > 0 ) + makeChunkStatic( begin ); + + /* break */ + + if( !src ) + { + if( !result.chunks.length ) + makeChunkStatic( 0 ); + break; + } + + /* end */ + + end = src.search( o.postfix ); + if( end === -1 ) + { + result.lines = _.str.lines.split( src ).length; + result.error = _.err( 'Openning prefix', o.prefix, 'of chunk #' + result.chunks.length, 'at'+line, 'line does not have closing tag :', o.postfix ); + return result; + } + + /* code chunk */ + + let chunk = makeChunkDynamic(); + + /* wind */ + + chunkIndex += 1; + line += _.strLinesCount( chunk.prefix + chunk.code + chunk.postfix ) - 1; + + } + while( src ); + + return result; + + /* - */ + + function colAccount( text ) + { + let i = text.lastIndexOf( '\n' ); + + if( i === -1 ) + { + column += text.length; + } + else + { + column = text.length - i; + } + + _.assert( column >= 0 ); + } + + /* - */ + + function makeChunkStatic( begin ) + { + let chunk = Object.create( null ); + chunk.line = line; + chunk.text = src.substring( 0, begin ); + chunk.index = chunkIndex; + chunk.kind = 'static'; + result.chunks.push( chunk ); + + src = src.substring( begin ); + line += _.strLinesCount( chunk.text ) - 1; + chunkIndex += 1; + + colAccount( chunk.text ); + } + + /* - */ + + function makeChunkDynamic() + { + let chunk = Object.create( null ); + chunk.line = line; + chunk.column = column; + chunk.index = chunkIndex; + chunk.kind = 'dynamic'; + chunk.prefix = src.match( o.prefix )[ 0 ]; + chunk.code = src.substring( chunk.prefix.length, end ); + if( o.investigate ) + { + chunk.lines = _.str.lines.split( chunk.code ); + chunk.tab = /^\s*/.exec( chunk.lines[ chunk.lines.length-1 ] )[ 0 ]; + } + + /* postfix */ + + src = src.substring( chunk.prefix.length + chunk.code.length ); + chunk.postfix = src.match( o.postfix )[ 0 ]; + src = src.substring( chunk.postfix.length ); + + result.chunks.push( chunk ); + return chunk; + } + +} + +strSplitChunks.defaults = +{ + src : null, + investigate : 1, + prefix : '//>-' + '->//', + postfix : '//<-' + '-= 0 ; s-- ) + { + if( s % 2 === 1 ) + splits.splice( s, 2, splits[ s ].toLowerCase() + splits[ s + 1 ] ); + } + + return splits; +} + +// -- +// extractor +// -- + +/** + * Routine _strOnly() gets substring out of source string {-srcStr-} according to a given range {-range-}. + * The end value of the range is not included in the substring. + * + * @param { String } srcStr - Source string. + * @param { Range } range - Range to get substring. + * If range[ 0 ] or range[ 1 ] is less then 0, then reference point is length of source string {-srcStr-}. + * + * @example + * _._strOnly( '', [ 0, 2 ] ); + * // returns '' + * + * @example + * _._strOnly( 'first', [ 0, 7 ] ); + * // returns 'first' + * + * @example + * _._strOnly( 'first', [ 0, 2 ] ); + * // returns 'fi' + * + * @example + * _._strOnly( 'first', [ -2, 5 ] ); + * // returns 'st' + * + * @example + * _._strOnly( 'first', [ 2, 2 ] ); + * // returns '' + * + * @function _strOnly + * @returns { String } - Returns substring from source string. + * @throws { Error } If arguments.length is less or more then two. + * @throws { Error } If {-srcStr-} is not a String. + * @throws { Error } If {-range-} is not a Range. + * @namespace Tools + */ + +function _strOnly( srcStr, cinterval ) +{ + + /* + _.strOnly( 'abc', [ -2, -1 ] ) => 'b' + _.strOnly( 'abc', [ 1, 2 ] ) => 'b' + + 3-2 = 1 + 3-1 = 2 + */ + + if( _.number.is( cinterval ) ) + { + if( cinterval < 0 ) + cinterval = srcStr.length + cinterval; + cinterval = [ cinterval, cinterval ]; + } + else + { + cinterval = _.long.make( cinterval ); /* Dmytro : vectorized routine should not change original range */ + + if( cinterval[ 1 ] < -1 ) + cinterval[ 1 ] = srcStr.length + cinterval[ 1 ]; + if( cinterval[ 0 ] < 0 ) + cinterval[ 0 ] = srcStr.length + cinterval[ 0 ]; + } + + if( cinterval[ 0 ] > cinterval[ 1 ] ) + cinterval[ 1 ] = cinterval[ 0 ] - 1; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( srcStr ) ); + _.assert( _.cinterval.defined( cinterval ) ); + + return srcStr.substring( cinterval[ 0 ], cinterval[ 1 ] + 1 ); +} + +// + +/** + * Routine strOnly() gets substring out of each string in vector of strings {-srcStr-} according to a given range {-range-}. + * The end value of the range is not included in the substring. + * + * @param { String|Long } srcStr - Source string or array of strings. + * @param { Range } range - Range to get substring. + * If range[ 0 ] or range[ 1 ] is less then 0, then reference point is length of source string {-srcStr-}. + * + * @example + * _.strOnly( '', [ 0, 1 ] ); + * // returns '' + * + * @example + * _.strOnly( 'first', [ 0, 6 ] ); + * // returns 'first' + * + * @example + * _.strOnly( 'first', [ 0, 1 ] ); + * // returns 'fi' + * + * @example + * _.strOnly( 'first', [ -2, 4 ] ); + * // returns 'st' + * + * @example + * _.strOnly( 'first', [ 2, 1 ] ); + * // returns '' + * + * @example + * _.strOnly( [ '', 'a', 'ab', 'abcde' ], [ 0, 1 ] ); + * // returns [ '', 'a', 'ab', 'ab' ] + * + * @example + * _.strOnly( [ '', 'a', 'ab', 'abcde' ], [ 0, 6 ] ); + * // returns [ '', 'a', 'ab', 'abcde' ] + * + * @example + * _.strOnly( [ '', 'a', 'ab', 'abcde' ], [ -2, 4 ] ); + * // returns [ '', 'a', 'ab', 'de' ] + * + * @example + * _.strOnly( [ '', 'a', 'ab', 'abcde' ], [ 2, 1 ] ); + * // returns[ '', '', '', '' ] + * + * @function strOnly + * @returns { String|Long } - Returns substrings from source string or array of strings. + * @throws { Error } If arguments.length is less or more then two. + * @throws { Error } If {-srcStr-} is not a String, not a Long. + * @throws { Error } If {-srcStr-} is a Long and includes not a String value. + * @throws { Error } If {-range-} is not a Range. + * @namespace Tools + */ + +let strOnly = _.vectorize( _strOnly ); + +// + +// srcStr:str ins:str -> str +// srcStr:str ins:[ * str ] -> [ * str ] +// srcStr:[ * str ] ins:[ * str ] -> [ * str ] + +/** + * Routine _strBut() replaces substring from source string {-srcStr-} to new value {-ins-} + * The ranges of substring defines according to a given range {-cinterval-}. + * The end value of the range is included in the substring. + * + * @example + * _._strBut( '', [ 0, 2 ] ); + * // returns : '' + * + * @example + * _._strBut( 'first', [ 0, 7 ] ); + * // returns : '' + * + * @example + * _._strBut( 'first', [ 0, 1 ] ); + * // returns : 'rst' + * + * @example + * _._strBut( 'first', [ -2, 4 ] ); + * // returns : 'firt' + * + * @example + * _._strBut( 'first', [ 2, 1 ] ); + * // returns : 'first' + * + * @example + * _._strBut( 'first', [ 0, 1 ], 'abc' ); + * // returns : 'abcrst' + * + * @example + * _._strBut( 'first', [ 0, 1 ], [ 'a', 'b', 'c' ] ); + * // returns : [ 'arst', 'brst', 'crst' ] + * + * @example + * _._strBut( 'first', [ 2, 1 ], 'abc' ); + * // returns : [ 'fiarst', 'fibrst', 'ficrst' ] + * + * @param { String } srcStr - Source string. + * @param { Crange } cinterval - Closed range to get substring. + * If cinterval[ 0 ] or cinterval[ 1 ] is less then 0, then reference point is length of source string {-srcStr-}. + * @param { String|Long } ins - Inserted string or array with inserted elements. + * If {-ins-} is a Long, then routine concatenates string from elements of Long. The delimeter is single space. + * If {-ins-} is not provided or if it is undefined, then routine removes substring from source string to a given range. + * @function _strBut + * @returns { String } - Returns source string, part of which replaced to the new value. + * @throws { Error } If arguments.length is less then two or more then three. + * @throws { Error } If {-srcStr-} is not a String. + * @throws { Error } If {-range-} is not a Range. + * @throws { Error } If {-ins-} is not a String, not a Long, not undefined. + * @namespace Tools + */ + +function _strBut( srcStr, cinterval, ins ) +{ + + + /* + aaa : reference point of negative is length. implement and cover please + Dmytro : implemented a time ago + */ + + if( _.number.is( cinterval ) ) + { + if( cinterval < 0 ) + cinterval = srcStr.length + cinterval; + cinterval = [ cinterval, cinterval ]; + } + else + { + cinterval = _.long.make( cinterval ); /* Dmytro : vectorized routine should not change original range */ + + if( cinterval[ 1 ] < -1 ) + cinterval[ 1 ] = srcStr.length + cinterval[ 1 ]; + if( cinterval[ 0 ] < 0 ) + cinterval[ 0 ] = srcStr.length + cinterval[ 0 ]; + } + + if( cinterval[ 0 ] > cinterval[ 1 ] ) + cinterval[ 1 ] = cinterval[ 0 ] - 1; + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( _.strIs( srcStr ) ); + _.assert( _.cinterval.defined( cinterval ) ); + _.assert( ins === undefined || _.strIs( ins ) || _.longIs( ins ) ); + + /* + aaa : implement for case ins is long + Dmytro : implemented, elements of long joins by spaces + aaa for Dmytro : no really + Dmytro : fixed + */ + + let result; + if( _.longIs( ins ) ) + { + result = _.array.make( ins.length ); + for( let i = 0 ; i < ins.length ; i++ ) + result[ i ] = _strConcat( srcStr, cinterval, ins[ i ] ); + } + else + { + result = _strConcat( srcStr, cinterval, ins ? ins : '' ); + } + + return result; + + /* */ + + function _strConcat( src, range, insertion ) + { + return src.substring( 0, range[ 0 ] ) + insertion + src.substring( range[ 1 ] + 1, src.length ); + } +} + +// + +/** + * Routine strBut() gets substring out of each string in vector of strings {-srcStr-} according to a given range {-range-} + * and replaces it to new string {-ins-}. + * The end value of the range is not included in the substring. + * + * @param { String|Long } srcStr - Source string or array of strings. + * @param { Range } range - Range to get substring. + * If range[ 0 ] or range[ 1 ] is less then 0, then reference point is length of source string {-srcStr-}. + * @param { String|Long } ins - Inserted string or array with inserted elements. + * If {-ins-} is a Long, then routine concatenates string from elements of Long. The delimeter is single space. + * If {-ins-} is not provided or if it is undefined, then routine removes substring from source string to a given range. + * + * @example + * _.strBut( '', [ 0, 2 ] ); + * // returns '' + * + * @example + * _.strBut( 'first', [ 0, 7 ] ); + * // returns '' + * + * @example + * _.strBut( 'first', [ 0, 2 ], 'abc' ); + * // returns 'abcrst' + * + * @example + * _.strBut( 'first', [ -2, 5 ], [ 'a', 'b', 'c' ] ); + * // returns 'fira b c' + * + * @example + * _.strBut( [ '', 'a', 'ab', 'abcde' ], [ 0, 2 ], 'fg' ); + * // returns [ 'fg', 'fg', 'fg', 'fgcde' ] + * + * @example + * _.strBut( [ '', 'a', 'ab', 'abcde' ], [ 0, 7 ], [ 'f', 'g' ] ); + * // returns [ 'f g', 'f g', 'f g', 'f g' ] + * + * @example + * _.strBut( [ '', 'a', 'ab', 'abcde' ], [ -2, 5 ], 'fg' ); + * // returns [ 'fg', 'fg', 'fg', 'abcfg' ] + * + * @example + * _.strBut( [ '', 'a', 'ab', 'abcde' ], [ 2, 2 ], [ 'f', 'g' ] ); + * // returns [ 'f g', 'af g', 'abf g', 'abf gcde' ] + * + * @function strBut + * @returns { String|Long } - Returns source string or vector of strings, part of which replaced to the new value. + * @throws { Error } If arguments.length is less then two or more then three. + * @throws { Error } If {-srcStr-} is not a String or not a Long. + * @throws { Error } If {-srcStr-} is a Long and includes not a String value. + * @throws { Error } If {-range-} is not a Range. + * @throws { Error } If {-ins-} is not a String, not a Long, not undefined. + * @namespace Tools + */ + +let strBut = _.vectorize( _strBut ); + +// + +/** + * Routine strUnjoin() splits string {-srcStr-} into parts using array {-maskArray-} as mask and returns an array with splitted parts. + * Mask {-maskArray-} contains string(s) separated by marker ( strUnjoin.any ). Mask must starts/ends with first/last letter from source + * or can be replaced with marker ( strUnjoin.any ). Position of ( strUnjoin.any ) determines which part of source string will be splited: + * - If ( strUnjoin.any ) is provided before string, it marks everything before that string. Example: ( [ _.strUnjoin.any, 'postfix' ] ). + * - If ( strUnjoin.any ) is provided after string, it marks everything after that string. Example: ( [ 'prefix', _.strUnjoin.any ] ). + * - If ( strUnjoin.any ) is provided between two strings, it marks everything between them. Example: ( [ 'prefix', _.strUnjoin.any, 'postfix' ] ). + * - If ( strUnjoin.any ) is provided before and after string, it marks all except that string. Example: ( [ '_.strUnjoin.any', something, '_.strUnjoin.any' ] ). + * + * @param {string} srcStr - Source string. + * @param {array} maskArray - Contains mask for source string. + * + * @example + * _.strUnjoin( 'prefix_something_postfix', [ 'prefix', _.strUnjoin.any, 'postfix' ] ); + * // returns [ 'prefix', '_something_', 'postfix' ] + * + * @example + * _.strUnjoin( 'prefix_something_postfix', [ _.strUnjoin.any, 'something', _.strUnjoin.any, 'postfix' ] ); + * // returns [ 'prefix_', 'something', '_', 'postfix' ] + * + * @example + * _.strUnjoin( 'prefix_something_postfix', [ _.strUnjoin.any, 'postfix' ] ); + * // returns [ 'prefix_something_', 'postfix' ] + * + * @example + * _.strUnjoin( 'prefix_something_postfix', [ 'prefix', _.strUnjoin.any ] ); + * // returns [ 'prefix', '_something_postfix' ] + * + * @example + * _.strUnjoin( 'prefix_something_postfix', [ _.strUnjoin.any, 'x', _.strUnjoin.any, 'p', _.strUnjoin.any ] ); + * // returns [ 'prefi', 'x', '_something_', 'p', 'ostfix' ] + * + * @returns {array} Returns array with unjoined string part. + * @function strUnjoin + * @throws { Exception } If arguments.length is less or more then two. + * @throws { Exception } If {-srcStr-} is not a String. + * @throws { Exception } If {-maskArray-} is not an Array. + * @throws { Exception } If {-maskArray-} value is not String or strUnjoin.any. + * @namespace Tools + * + */ + +function strUnjoin( srcStr, maskArray ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( srcStr ) ); + _.assert( _.arrayIs( maskArray ) ); + + let result = []; + let index = 0; + let rindex = -1; + + /**/ + + for( let m = 0 ; m < maskArray.length ; m++ ) + { + + let mask = maskArray[ m ]; + + if( !checkMask( mask ) ) + return; + + } + + if( rindex !== -1 ) + { + index = srcStr.length; + if( !checkToken() ) + return; + } + + if( index !== srcStr.length ) + return; + + /**/ + + return result; + + /**/ + + function checkToken() + { + + if( rindex !== -1 ) + { + _.assert( rindex <= index ); + result.push( srcStr.substring( rindex, index ) ); + rindex = -1; + return true; + } + + return false; + } + + /**/ + + function checkMask( mask ) + { + + _.assert( _.strIs( mask ) || mask === strUnjoin.any, 'Expects string or strUnjoin.any, got', _.entity.strType( mask ) ); + + if( _.strIs( mask ) ) + { + index = srcStr.indexOf( mask, index ); + + if( index === -1 ) + return false; + + if( rindex === -1 && index !== 0 ) + return false; + + checkToken(); + + result.push( mask ); + index += mask.length; + + } + else if( mask === strUnjoin.any ) + { + rindex = index; + } + else _.assert( 0, 'unexpected mask' ); + + return true; + } + +} + +strUnjoin.any = _.any; +_.assert( _.routine.is( strUnjoin.any ) ); + +// -- +// joiner +// -- + +/** + * Routine _strDup() returns a string with the source string appended to itself n-times. + * Expects two parameter: source string {-s-} ( or array of strings ) and number of concatenations {-times-}. + * The string {-s-} and the number {-times-} remain unchanged. + * + * @param { Array/String } s - Source array of strings or source string. + * @param { Number } times - Number of concatenation cycles. + * + * @example + * _.strDup( 'Word', 5 ); + * // returns WordWordWordWordWord + * + * @example + * _.strDup( '1 '+'2', 2 ); + * // returns 1 21 2 + * + * @example + * _.strDup( [ 'ab', 'd', '3 4'], 2 ); + * // returns [ 'abab', 'dd', '3 43 4'] + * + * @returns { String|Array } - Returns a string or an array of string containing the src string concatenated n-times. + * @function strDup + * @throws { Exception } If arguments.length is less or more then two. + * @throws { Exception } If {-s-} is not a String or an array of strings. + * @throws { Exception } If {-times-} is not a Number. + * @namespace Tools + */ + +function _strDup( s, times ) +{ + let result = ''; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( s ) ); + _.assert( _.number.is( times ) ); + + for( let t = 0 ; t < times ; t++ ) + result += s; + + return result; +} + +// + +/** + * Joins objects inside the source array, by concatenating their values in order that they are specified. + * The source array can contain strings, numbers and arrays. If arrays are provided, they must have same length. + * Joins arrays by concatenating all elements with same index into one string and puts it into new array at same position. + * Joins array with other object by concatenating each array element with that object value. Examples: ( [ [ 1, 2 ], 3 ] ) -> ( [ '13', '23' ] ), + * ( [ [ 1, 2 ], [ 1, 2] ] ) -> ( [ '11', '22' ] ). + * An optional second string argument can be passed to the function. This argument ( joiner ) defines the string that joins the + * srcArray objects. Examples: ( [ [ 1, 2 ], 3 ], '*' ) -> ( [ '1*3', '2*3' ] ), + * ( [ [ 1, 2 ], [ 1, 2 ] ], ' to ' ) -> ( [ '1 to 1', '2 to 2' ] ). + * + * @param { Array-like } srcs - Source array with the provided objects. + * @param { String } joiner - Optional joiner parameter. + * @returns { Object } Returns concatenated objects as string or array. Return type depends from arguments type. + * + * @example + * _.strJoin([ 1, 2, 3 ]); + * // returns '123' + * + * @example + * _.strJoin([ [ 1, 2, 3 ], 2 ]); + * // returns [ '12', '22', '32' ] + * + * @example + * _.strJoin([ [ 1, 2 ], [ 1, 3 ] ]); + * // returns [ '11', '23' ] + * + * @example + * _.strJoin([ 1, 2, [ 3, 4, 5 ], [ 6, 7, 8 ] ]); + * // returns [ '1236', '1247', '1258' ] + * + * @example + * _.strJoin([ 1, 2, [ 3, 4, 5 ], [ 6, 7, 8 ] ], ' '); + * // returns [ '1 2 3 6', '1 2 4 7', '1 2 5 8' ] + * + * @method strJoin + * @throws { Exception } If ( arguments.length ) is not one or two. + * @throws { Exception } If some object from( srcs ) is not a Array, String or Number. + * @throws { Exception } If length of arrays in srcs is different. + * @throws { Exception } If ( joiner ) is not undefined or a string . + * @namespace Tools + * + */ + +function strJoin_head( routine, args ) +{ + + let o = args[ 0 ]; + if( args[ 1 ] !== undefined || _.argumentsArray.like( args[ 0 ] ) ) + o = { srcs : args[ 0 ], join : ( args.length > 1 ? args[ 1 ] : null ) }; + + _.routine.options( routine, o ); + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2, () => 'Expects an array of string and optional join, but got ' + args.length + ' arguments' ); + _.assert( _.argumentsArray.like( o.srcs ), () => 'Expects an array of strings, but got ' + _.entity.strType( o.srcs ) ); + _.assert( o.join === undefined || o.join === null || _.strIs( o.join ), () => 'Expects optional join, but got ' + _.entity.strType( o.join ) ); + + return o; +} + +// + +/* xxx : review */ +// function strJoin_body( srcs, delimeter ) +function strJoin_body( o ) +{ + // let result = [ '' ]; + // let arrayEncountered = 0; + let arrayLength; + + _.routine.assertOptions( strJoin_body, arguments ); + + let delimeter = o.join || ''; + if( o.join === null || o.join === undefined || _.strIs( o.join ) ) + o.join = join; + + // debugger; + + if( !o.srcs.length ) + return []; + + /* */ + + for( let a = 0 ; a < o.srcs.length ; a++ ) + { + let src = o.srcs[ a ]; + + if( _.arrayIs( src ) ) + { + _.assert( arrayLength === undefined || arrayLength === src.length, 'All arrays should have the same length' ); + arrayLength = src.length; + } + + } + + if( arrayLength === 0 ) + return []; + + /* */ + + if( arrayLength === undefined ) + { + let result = ''; + + for( let a = 0 ; a < o.srcs.length ; a++ ) + { + let src = o.srcs[ a ]; + let srcStr = o.str( src ); + _.assert( _.strIs( srcStr ), () => 'Expects primitive or array, but got ' + _.entity.strType( src ) ); + result = o.join( result, srcStr, a ); + } + + return result; + } + else + { + + let result = []; + for( let i = 0 ; i < arrayLength ; i++ ) + result[ i ] = ''; + + for( let a = 0 ; a < o.srcs.length ; a++ ) + { + let src = o.srcs[ a ]; + + // _.assert( _.strIs( srcStr ) || _.arrayIs( src ), () => 'Expects primitive or array, but got ' + _.entity.strType( src ) ); + // _.assert( _.strIs( src ) || _.number.is( src ) || _.arrayIs( src ) ); + + if( _.arrayIs( src ) ) + { + + // if( arrayEncountered === 0 ) + // for( let s = 1 ; s < src.length ; s++ ) + // result[ s ] = result[ 0 ]; + + // _.assert( arrayLength === undefined || arrayLength === src.length, 'All arrays should have the same length' ); + // arrayLength = src.length; + + // arrayEncountered = 1; + for( let s = 0 ; s < result.length ; s++ ) + result[ s ] = o.join( result[ s ], src[ s ], a ); + + } + else + { + + let srcStr = o.str( src ); + _.assert( _.strIs( srcStr ), () => 'Expects primitive or array, but got ' + _.entity.strType( src ) ); + for( let s = 0 ; s < result.length ; s++ ) + result[ s ] = o.join( result[ s ], srcStr, a ); + + } + + } + + return result; + } + + /* */ + + /* qqq : investigate */ + + if( arrayEncountered ) + return result; + else + return result[ 0 ]; + + /* */ + + function join( result, src, a ) + { + if( delimeter && a > 0 ) + return result + delimeter + src; + else + return result + src; + } + +} + +strJoin_body.defaults = +{ + srcs : null, + join : null, + str : _.entity.strPrimitive, +} + +let strJoin = _.routine.unite( strJoin_head, strJoin_body ); + +// + +/** + * Routine strJoinPath() joins objects inside the source array, by concatenating their values in order that they are specified. + * The source array can contain strings, numbers and arrays. If arrays are provided, they must have same length. + * Joins arrays by concatenating all elements with same index into one string and puts it into new array at same position. + * Joins array with other object by concatenating each array element with that object value. + * Examples: ( [ [ 1, 2 ], 3 ], '' ) -> ( [ '13', '23' ] ), ( [ [ 1, 2 ], [ 1, 2] ] ) -> ( [ '11', '22' ], '' ). + * Second argument should be string type. This argument ( joiner ) defines the string that joins the + * srcArray objects. Examples: ( [ [ 1, 2 ], 3 ], '*' ) -> ( [ '1*3', '2*3' ] ), + * ( [ [ 1, 2 ], [ 1, 2 ] ], ' to ' ) -> ( [ '1 to 1', '2 to 2' ] ). + * If the ( srcs ) objects has ( joiner ) at begin or end, ( joiner ) will be replaced. ( joiner ) replaced only between joined objects. + * Example: ( [ '/11/', '//22//', '/3//' ], '/' ) --> '/11//22//3//' + * + * @param { Array-like } srcs - Source array with the provided objects. + * @param { String } joiner - Joiner parameter. + * + * @example + * _.strJoinPath( [ 1, 2, 3 ], '' ); + * // returns '123' + * + * @example + * _.strJoinPath( [ [ '/a//', 'b', '//c//' ], 2 ], '/' ); + * // returns '/a//b//c//' + * + * @example + * _.strJoinPath( [ [ 1, 2 ], [ 1, 3 ] ], '.'); + * // returns [ '1.1', '2.3' ] + * + * @example + * _.strJoinPath( [ 1, 2, [ 3, 4, 5 ], [ 6, 7, 8 ] ], ','); + * // returns [ '1,2,3,6', '1,2,4,7', '1,2,5,8' ] + * + * @method strJoinPath + * @returns { String|Array-like } Returns concatenated objects as string or array. Return type depends from arguments type. + * @throws { Exception } If ( arguments.length ) is less or more than two. + * @throws { Exception } If some object from ( srcs ) is not a Array, String or Number. + * @throws { Exception } If length of arrays in ( srcs ) is different. + * @throws { Exception } If ( joiner ) is not a string. + * @namespace Tools + * + */ + +function strJoinPath( srcs, joiner ) +{ + let result = [ '' ]; + let arrayEncountered = 0; + let arrayLength; + + _.assert( arguments.length === 2, () => 'Expects an array of string and joiner, but got ' + arguments.length + ' arguments' ); + _.assert( _.argumentsArray.like( srcs ), () => 'Expects an array of strings, but got ' + _.entity.strType( srcs ) ); + _.assert( _.strIs( joiner ), () => 'Expects joiner, but got ' + _.entity.strType( joiner ) ); + + /* xxx : investigate */ + + for( let a = 0 ; a < srcs.length ; a++ ) + { + let src = srcs[ a ]; + + _.assert( _.strIs( src ) || _.number.is( src ) || _.arrayIs( src ) ); + + if( _.arrayIs( src ) ) + { + + if( arrayEncountered === 0 ) + { + for( let s = 1 ; s < src.length ; s++ ) + result[ s ] = result[ 0 ]; + } + + _.assert( arrayLength === undefined || arrayLength === src.length, 'All arrays should have the same length' ); + arrayLength = src.length; + + arrayEncountered = 1; + for( let s = 0 ; s < src.length ; s++ ) + join( src[ s ], s, a ); + + } + else + { + + for( let s = 0 ; s < result.length ; s++ ) + join( src, s, a ); + + } + + } + + if( arrayEncountered ) + return result; + else + return result[ 0 ]; + + /* */ + + function join( src, s, a ) + { + if( _.number.is( src ) ) + src = src.toString(); + + if( a > 0 && joiner ) + { + let ends = _.strEnds( result[ s ], joiner ); + let begins = _.strBegins( src, joiner ); + if( begins && ends ) + result[ s ] = _.strRemoveEnd( result[ s ], joiner ) + src; + else if( begins || ends ) + result[ s ] += src; + else + result[ s ] += joiner + src; + } + else + { + result[ s ] += src; + } + } +} + +// -- +// liner +// -- + +/** + * Adds indentation character(s) to passed string. + * If( src ) is a multiline string, function puts indentation character( tab ) before first + * and every next new line in a source string( src ). + * If( src ) represents single line, function puts indentation at the begining of the string. + * If( src ) is a Array, function prepends indentation character( tab ) to each line( element ) of passed array. + * + * @param { String/Array } src - Source string to parse or array of lines( not array of texts ). + * With line we mean it does not have eol. Otherwise please join the array to let the routine to resplit the text, + * like that: _.strLinesIndentation( array.join( '\n' ), '_' ). + * @param { String } tab - Indentation character. + * @returns { String } Returns indented string. + * + * @example + * _.strLinesIndentation( 'abc', '_' ) + * // returns '_abc' + * + * @example + * _.strLinesIndentation( 'a\nb\nc', '_' ) + * // returns + * // _a + * // _b + * // _c + * + * @example + * _.strLinesIndentation( [ 'a', 'b', 'c' ], '_' ) + * // returns + * // _a + * // _b + * // _c + * + * @example + * let array = [ 'a\nb', 'c\nd' ]; + * _.strLinesIndentation( array.join( '\n' ), '_' ) + * // returns + * // _a + * // _b + * // _c + * // _d + * + * @method strLinesIndentation + * @throws { Exception } Throw an exception if( src ) is not a String or Array. + * @throws { Exception } Throw an exception if( tab ) is not a String. + * @throws { Exception } Throw an exception if( arguments.length ) is not a equal 2. + * @namespace Tools + * + */ + +function strLinesIndentation( src, tab, every ) +{ + + if( every === undefined ) + every = true; + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( _.strIs( src ) || _.arrayIs( src ), 'Expects src as string or array' ); + _.assert( _.strIs( tab ) || _.number.is( tab ), 'Expects tab as string or number' ); + _.assert( every === undefined || _.bool.like( every ) ); + + if( _.number.is( tab ) ) + tab = _.strDup( ' ', tab ); + + if( _.strIs( src ) ) + { + if( src.indexOf( '\n' ) === -1 ) + return src; + src = _.str.lines.split( src ); + } + + /* + should be no tab in prolog + */ + + if( every === true ) + { + let result = src.join( '\n' + tab ); + return result; + } + else + { + let result = ''; + src.forEach( ( e, c ) => + { + if( c > 0 ) + result += '\n'; + result += e.length > 0 && c > 0 ? tab + e : e; + }); + return result; + } +} + +// + +/** + * Routine strLinesBut() replaces a range {-range-} of lines in source string {-src-} to new + * values in {-ins-} parameter. + * + * @param { String|Long } src - Source string or array of strings. + * If {-src-} is a String, then it split to parts using delimeter '\n'. + * @param { Range|Number } range - Range of lines to be replaced. + * If {-range-} is a Number, then routine replace only one line defined by value of {-range-}. + * @param { String|Long } ins - String or array of strings to be inserted in source string. + * If {-ins-} is a Long, then elements of Long concatenates using delimeter '\n'. + * If range[ 0 ] or range[ 1 ] is less than zero, then routine count lines from the end of {-src-}. + * + * @example + * _.strLinesBut( 'ab \n bc \n cd \n de', 1 ); + * // returns 'ab \n cd \n de' + * + * @example + * _.strLinesBut( 'ab \n bc \n cd \n de', -1 ); + * // returns 'ab \n bc \n cd ' + * + * @example + * _.strLinesBut( 'ab \n bc \n cd \n de', [ 1, 4 ], '' ); + * // returns 'ab ' + * + * @example + * _.strLinesBut( 'ab \n bc \n cd \n de', [ 1, -1 ], '' ); + * // returns 'ab \n de' + * + * @example + * _.strLinesBut( 'ab \n bc \n cd \n de', 1, ' some \n string ' ); + * // returns 'ab \n some \n string \n cd \n de' + * + * @example + * _.strLinesBut( 'ab \n bc \n cd \n de', -1, ' some \n string ' ); + * // returns 'ab \n bc \n cd \n some \n string ' + * + * @example + * _.strLinesBut( 'ab \n bc \n cd \n de', [ 1, 4 ], [ ' some ', ' string' ] ); + * // returns 'ab \n some \n string' + * + * @example + * _.strLinesBut( 'ab \n bc \n cd \n de', [ 1, -1 ], [ ' some ', ' string' ] ); + * // returns 'ab \n some \n string\n de' + * + * @example + * _.strLinesBut( [ 'ab ', ' bc ', ' cd ', ' de' ], 1, ' some \n string ' ); + * // returns 'ab \n some \n string \n cd \n de' + * + * @example + * _.strLinesBut( [ 'ab ', ' bc ', ' cd ', ' de' ], -1, ' some \n string ' ); + * // returns 'ab \n bc \n cd \n some \n string ' + * + * @example + * _.strLinesBut( [ 'ab ', ' bc ', ' cd ', ' de' ], [ 1, 4 ], [ ' some ', ' string' ] ); + * // returns 'ab \n some \n string' + * + * @example + * _.strLinesBut( [ 'ab ', ' bc ', ' cd ', ' de' ], [ 1, -1 ], [ ' some ', ' string' ] ); + * // returns 'ab \n some \n string\n de' + * + * @returns { String } - Returns string concatenated from original source string and inserted values. + * @function strLinesBut + * @throws { Exception } If arguments.length is less then two or more then three. + * @throws { Exception } If {-src-} is not a String or a Long. + * @throws { Exception } If {-ins-} is not a String, not a Long, not undefined. + * @namespace Tools + */ + +function strLinesBut( src, range, ins ) +{ + + if( _.strIs( src ) ) + src = _.str.lines.split( src ); + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( _.longIs( src ) ); + _.assert( ins === undefined || _.strIs( ins ) || _.longIs( ins ) ); + // _.assert( !_.longIs( ins ), 'not implemented' ); + + if( _.number.is( range ) ) + { + if( range < 0 ) + range = src.length + range; + range = [ range, range + 1 ]; + } + + if( range[ 1 ] < 0 ) + range[ 1 ] = src.length + range[ 1 ]; + + _.assert( _.intervalIs( range ) ); + + /* + aaa : should work + _.strLinesBut( _.strLinesBut( got1, 0 ), -1 ) + + Dmytro : works + */ + + /* + aaa : implement not implemented + Dmytro : implemented + */ + + let range2 = [ range[ 0 ], range[ 1 ] - 1 ] + /* qqq for Dmtro : check and improve code */ + + if( _.longIs( ins ) ) + return _.longBut_( null, src, range2, ins ).join( '\n' ); + else if( _.strIs( ins ) ) + return _.longBut_( null, src, range2, [ ins ] ).join( '\n' ); + else + return _.longBut_( null, src, range2 ).join( '\n' ); + + // if( _.longIs( ins ) ) + // return _.longBut( src, range, ins ).join( '\n' ); + // else if( _.strIs( ins ) ) + // return _.longBut( src, range, [ ins ] ).join( '\n' ); + // else + // return _.longBut( src, range ).join( '\n' ); + + // if( ins ) + // { + // _.assert( _.strIs( ins ) ); + // return _.longBut( src, range, [ ins ] ).join( '\n' ); + // } + // else + // { + // return _.longBut( src, range ).join( '\n' ); + // } + +} + +// + +/** + * Routine strLinesOnly() selects a range {-range-} of lines in source string {-src-} and returns + * new string joined from it. + * + * @param { String|Long } src - Source string or array of strings. + * If {-src-} is a String, then it split to parts using delimeter '\n'. + * @param { Range|Number } range - Range of lines to be selected. + * If {-range-} is a Number, then routine selects only one line defined by value of {-range-}. + * If range[ 0 ] or range[ 1 ] is less than zero, then routine count lines from the end of {-src-}. + * + * @example + * _.strLinesOnly( 'ab \n bc \n cd \n de', 1 ); + * // returns ' bc ' + * + * @example + * _.strLinesOnly( 'ab \n bc \n cd \n de', -1 ); + * // returns ' de' + * + * @example + * _.strLinesOnly( 'ab \n bc \n cd \n de', [ 1, 4 ] ); + * // returns ' bc \n cd \n de' + * + * @example + * _.strLinesOnly( 'ab \n bc \n cd \n de', [ 1, -1 ] ); + * // returns ' bc \n cd ' + * + * @example + * _.strLinesOnly( [ 'ab ', ' bc ', ' cd ', ' de' ], 1 ); + * // returns ' bc ' + * + * @example + * _.strLinesOnly( [ 'ab ', ' bc ', ' cd ', ' de' ], -1 ); + * // returns ' de' + * + * @example + * _.strLinesOnly( [ 'ab ', ' bc ', ' cd ', ' de' ], [ 1, 4 ] ); + * // returns ' bc \n cd \n de' + * + * @example + * _.strLinesOnly( [ 'ab ', ' bc ', ' cd ', ' de' ], [ 1, -1 ] ); + * // returns ' bc \n cd ' + * + * @returns { String } - Returns a range of lines from source string concatenated by new line symbol. + * @function strLinesOnly + * @throws { Exception } If arguments.length is less then two or more then three. + * @throws { Exception } If {-src-} is not a String or a Long. + * @namespace Tools + */ + +function strLinesOnly( src, range ) +{ + + if( _.strIs( src ) ) + src = _.str.lines.split( src ); + + _.assert( arguments.length === 2 ); + _.assert( _.longIs( src ) ); + + if( _.number.is( range ) ) + range = [ range, range + 1 ]; + if( range[ 0 ] < 0 ) + range[ 0 ] = src.length >= -range[ 0 ] ? src.length + range[ 0 ] : 0 + if( range[ 1 ] < 0 ) + range[ 1 ] = src.length + range[ 1 ]; + + _.assert( _.intervalIs( range ) ); + + let result = []; + for( let i = range[ 0 ]; i < range[ 1 ] && i < src.length; i++ ) + result[ i - range[ 0 ] ] = src[ i ]; + + return result.join( '\n' ); + +} + +// + +/** + * Puts line counter before each line/element of provided source( o.src ). + * If( o.src ) is a string, function splits it into array using new line as splitter, then puts line counter at the beginning of each line( element ). + * If( o.src ) is a array, function puts line counter at the beginning of each line( element ). + * Initial value of a counter can be changed by defining( o.first ) options( o ) property. + * Can be called in two ways: + * - First by passing all options in one object; + * - Second by passing source only and using default value of( first ). + * + * @param { Object } o - options. + * @param { String/Array } [ o.src=null ] - Source string or array of lines( not array of texts ). + * With line we mean it does not have EOF. Otherwise please join the array to let the routine to resplit the text, + * like that: _.strLinesNumber( array.join( '\n' ) ). + * @param { Number} [ o.first=1 ] - Sets initial value of a counter. + * @returns { String } Returns string with line enumeration. + * + * @example + * _.strLinesNumber( 'line' ); + * // returns '1 : line' + * + * @example + * _.strLinesNumber( 'line1\nline2\nline3' ); + * // returns + * // 1: line1 + * // 2: line2 + * // 3: line3 + * + * @example + * _.strLinesNumber( [ 'line', 'line', 'line' ] ); + * // returns + * // 1: line1 + * // 2: line2 + * // 3: line3 + * + * @example + * _.strLinesNumber( { src:'line1\nline2\nline3', zeroLine : 2 } ); + * // returns + * // 2: line1 + * // 3: line2 + * // 4: line3 + * + * @method strLinesNumber + * @throws { Exception } Throw an exception if no argument provided. + * @throws { Exception } Throw an exception if( o.src ) is not a String or Array. + * @namespace Tools + */ + +function strLinesNumber( o ) +{ + + if( !_.object.isBasic( o ) ) + o = { src : arguments[ 0 ], zeroLine : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + + _.routine.options( strLinesNumber, o ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( o.src ) || _.strsAreAll( o.src ), 'Expects string or strings {-o.src-}' ); + + /* */ + + if( o.zeroLine === null ) + { + if( o.zeroChar === null ) + { + o.zeroLine = 1; + } + else if( _.number.is( o.zeroChar ) ) + { + let src = _.arrayIs( o.src ) ? o.src.join( '\n' ) : o.src; + o.zeroLine = _.strLinesCount( src.substring( 0, o.zeroChar+1 ) ); + } + } + + /* */ + + let lines = _.strIs( o.src ) ? _.str.lines.split( o.src ) : o.src; + + /* */ + + let maxNumberLength = String( lines.length - 1 + o.zeroLine ).length; + let zeroLineLength = String( o.zeroLine ).length; + let maxNumLength = maxNumberLength > zeroLineLength ? maxNumberLength : zeroLineLength; + + if( o.onLine ) + for( let l = 0; l < lines.length; l += 1 ) + { + let numLength = String( l + o.zeroLine ).length; + + lines[ l ] = o.onLine( [ ' '.repeat( maxNumLength - numLength ), ( l + o.zeroLine ), ' : ', lines[ l ] ], o.zeroLine + l, o ); + if( lines[ l ] === undefined ) + { + lines.splice( l, 1 ); + l -= 1; + } + _.assert( _.strIs( lines[ l ] ) ); + } + else + for( let l = 0; l < lines.length; l += 1 ) + { + let numLength = String( l + o.zeroLine ).length; + lines[ l ] = ' '.repeat( maxNumLength - numLength ) + ( l + o.zeroLine ) + ' : ' + lines[ l ]; + } + if( o.highlightingToken && o.highlighting ) + { + let results; + + _.assert( o.highlighting === null || _.number.is( o.highlighting ) || _.longIs( o.highlighting ), 'Expects number or array of numbers {-o.highlighting-}' ); + + if( !_.arrayIs( o.highlighting ) ) + { + if( o.highlighting > o.zeroLine + lines.length - 1 || o.highlighting < o.zeroLine ) + return lines.join( '\n' ); + } + + results = lines.map( ( el ) => + { + if( _.arrayIs( o.highlighting ) ) + return o.highlighting.includes( parseInt( el, 10 ) ) ? '' + o.highlightingToken + ' ' + el : '' + ' '.repeat( o.highlightingToken.length + 1 ) + el; + else + return ( '' + o.highlighting ).includes( parseInt( el, 10 ) ) ? '' + o.highlightingToken + ' ' + el : '' + ' '.repeat( o.highlightingToken.length + 1 ) + el; + } ) + + if( JSON.stringify( lines ) === JSON.stringify( results.map( ( el ) => el.trim() ) ) ) + return lines.join( '\n' ); + + return results.join( '\n' ); + + } + + return lines.join( '\n' ); +} + +strLinesNumber.defaults = +{ + src : null, + zeroLine : null, + zeroChar : null, + onLine : null, + highlighting : null, + highlightingToken : '*', /* qqq : if null then highlighting is off */ +} + +/* qqq2 : implement and cover option o.highlighting + +_.strLinesNumber({ src, highlighting : 867 }); + +// 863 : 7 : Last one +// 864 : + replace 5 in ${ a.abs( 'before/File2.js' ) } +// 865 : Done 1 action(s). Thrown 0 error(s). +// 866 : ` +// * 867 : test.equivalent( op.output, exp ); + +_.strLinesNumber({ src, highlighting : 867, highlightingToken : '-->' }); + +// 863 : 7 : Last one +// 864 : + replace 5 in ${ a.abs( 'before/File2.js' ) } +// 865 : Done 1 action(s). Thrown 0 error(s). +// 866 : ` +// --> 867 : test.equivalent( op.output, exp ); + +_.strLinesNumber({ src, highlighting : [ 865, 867 ] }); + +// 863 : 7 : Last one +// 864 : + replace 5 in ${ a.abs( 'before/File2.js' ) } +// * 865 : Done 1 action(s). Thrown 0 error(s). +// 866 : ` +// * 867 : test.equivalent( op.output, exp ); + +*/ + +// + +/** + * Selects range( o.range ) of lines from source string( o.src ). + * If( o.range ) is not specified and ( o.line ) is provided function uses it with ( o.selectMode ) option to generate new range. + * If( o.range ) and ( o.line ) are both not provided function generates range by formula: [ 0, n + 1 ], where n: number of ( o.delimteter ) in source( o.src ). + * Returns selected lines range as string or empty string if nothing selected. + * Can be called in three ways: + * - First by passing all parameters in one options map( o ) ; + * - Second by passing source string( o.src ) and range( o.range ) as array or number; + * - Third by passing source string( o.src ), range start and end position. + * + * @param {Object} o - Options. + * @param {String} [ o.src=null ] - Source string. + * @param {Array|Number} [ o.range=null ] - Sets range of lines to select from( o.src ) or single line number. + * @param {Number} [ o.zero=1 ] - Sets base value for a line counter. + * @param {Number} [ o.number=0 ] - If true, puts line counter before each line by using o.range[ 0 ] as initial value of a counter. + * @param {String} [ o.delimteter='\n' ] - Sets new line character. + * @param {String} [ o.line=null ] - Sets line number from which to start selecting, is used only if ( o.range ) is null. + * @param {Number} [ o.nearestLines=3 ] - Sets maximal number of lines to select, is used only if ( o.range ) is null and ( o.line ) option is specified. + * @param {String} [ o.selectMode='center' ] - Determines in what way funtion must select lines, works only if ( o.range ) is null and ( o.line ) option is specified. + * Possible values: + * - 'center' - uses ( o.line ) index as center point and selects ( o.nearestLines ) lines in both directions. + * - 'begin' - selects ( o.nearestLines ) lines from start point ( o.line ) in forward direction; + * - 'end' - selects ( o.nearestLines ) lines from start point ( o.line ) in backward direction. + * @returns {string} Returns selected lines as new string or empty if nothing selected. + * + * @example + * // selecting single line + * _.strLinesSelect( 'a\nb\nc', 1 ); + * // returns 'a' + * + * @example + * // selecting first two lines + * _.strLinesSelect( 'a\nb\nc', [ 1, 3 ] ); + * // returns + * // 'a + * // b' + * + * @example + * // selecting first two lines, second way + * _.strLinesSelect( 'a\nb\nc', 1, 3 ); + * // returns + * // 'a + * // b' + * + * @example + * // custom new line character + * _.strLinesSelect({ src : 'a b c', range : [ 1, 3 ], delimteter : ' ' }); + * // returns 'a b' + * + * @example + * // setting preferred number of lines to select, line option must be specified + * _.strLinesSelect({ src : 'a\nb\nc', line : 2, nearestLines : 1 }); + * // returns 'b' + * + * @example + * // selecting 2 two next lines starting from second + * _.strLinesSelect({ src : 'a\nb\nc', line : 2, nearestLines : 2, selectMode : 'begin' }); + * // returns + * // 'b + * // c' + * + * @example + * // selecting 2 two lines starting from second in backward direction + * _.strLinesSelect({ src : 'a\nb\nc', line : 2, nearestLines : 2, selectMode : 'end' }); + * // returns + * // 'a + * // b' + * + * @method strLinesSelect + * @throws { Exception } Throw an exception if no argument provided. + * @throws { Exception } Throw an exception if( o.src ) is not a String. + * @throws { Exception } Throw an exception if( o.range ) is not a Array or Number. + * @throws { Exception } Throw an exception if( o ) is extended by unknown property. + * @namespace Tools + */ + +function strLinesSelect( o ) +{ + + if( arguments.length === 2 ) + { + + if( _.arrayIs( arguments[ 1 ] ) ) + o = { src : arguments[ 0 ], range : arguments[ 1 ] }; + else if( _.number.is( arguments[ 1 ] ) ) + o = { src : arguments[ 0 ], range : [ arguments[ 1 ], arguments[ 1 ]+1 ] }; + else _.assert( 0, 'unexpected argument', _.entity.strType( range ) ); + + } + else if( arguments.length === 3 ) + { + o = { src : arguments[ 0 ], range : [ arguments[ 1 ], arguments[ 2 ] ] }; + } + + _.routine.options( strLinesSelect, o ); + _.assert( arguments.length <= 3 ); + _.assert( _.strIs( o.src ) ); + _.assert( _.bool.like( o.highlighting ) || _.longHas( [ '*' ], o.highlighting ) ); + + if( _.bool.like( o.highlighting ) && o.highlighting ) + o.highlighting = '*'; + + /* range */ + + if( !o.range ) + { + if( o.line === null ) + { + o.range = [ 0, _.strCount( o.src, o.delimteter )+1 ]; + } + else + { + if( o.selectMode === 'center' ) + o.range = [ o.line - Math.ceil( ( o.nearestLines + 1 ) / 2 ) + 1, o.line + Math.floor( ( o.nearestLines - 1 ) / 2 ) + 1 ]; + else if( o.selectMode === 'begin' ) + o.range = [ o.line, o.line + o.nearestLines ]; + else if( o.selectMode === 'end' ) + o.range = [ o.line - o.nearestLines+1, o.line+1 ]; + } + // if( o.line !== null ) + // { + // if( o.selectMode === 'center' ) + // o.range = [ o.line - Math.ceil( ( o.nearestLines + 1 ) / 2 ) + 1, o.line + Math.floor( ( o.nearestLines - 1 ) / 2 ) + 1 ]; + // else if( o.selectMode === 'begin' ) + // o.range = [ o.line, o.line + o.nearestLines ]; + // else if( o.selectMode === 'end' ) + // o.range = [ o.line - o.nearestLines+1, o.line+1 ]; + // } + // else + // { + // o.range = [ 0, _.strCount( o.src, o.delimteter )+1 ]; + // } + } + + if( o.line === null ) + { + if( o.selectMode === 'center' ) + o.line = Math.floor( ( o.range[ 0 ] + o.range[ 1 ] ) / 2 ); + else if( o.selectMode === 'begin' ) + o.line = o.range[ 0 ]; + else if( o.selectMode === 'end' ) + o.line = o.range[ 1 ] - 1; + + o.line = o.line > 0 ? o.line : 1; + } + + _.assert( _.longIs( o.range ) ); + _.assert( _.intIs( o.line ) && o.line >= 0, 'Expects positive integer {-o.line-}.' ); + + /* */ + + let f = 0; + let counter = o.zeroLine; + while( counter < o.range[ 0 ] ) + { + f = o.src.indexOf( o.delimteter, f ); + if( f === -1 ) + return ''; + f += o.delimteter.length; + counter += 1; + } + + /* */ + + let l = f-1; + while( counter < o.range[ 1 ] ) + { + l += 1; + l = o.src.indexOf( o.delimteter, l ); + if( l === -1 ) + { + l = o.src.length; + break; + } + counter += 1; + } + + /* */ + + let result = f < l ? o.src.substring( f, l ) : ''; + + /* numbering */ + + let zeroLine = o.range[ 0 ] <= 0 ? o.zeroLine : o.range[ 0 ]; + + if( o.numbering && result.length ) + result = _.strLinesNumber + ({ + src : result, + zeroLine, + onLine : lineHighlight, + }); + + return result; + + /* */ + + function lineHighlight( line, l ) + { + if( !o.highlighting ) + return line.join( '' ); + if( l === o.line ) + line[ 0 ] = '* ' + line[ 0 ]; + else + line[ 0 ] = ' ' + line[ 0 ]; + // line[ 1 ] = _.strBut( line[ 1 ], 0, '*' ); + return line.join( '' ); + } + + /* */ + +} + +strLinesSelect.defaults = +{ + + src : null, + range : null, + + line : null, + nearestLines : 3, + selectMode : 'center', + highlighting : '*', + + numbering : 0, + zeroLine : 1, + delimteter : '\n', + +} + +/* aaa : +- cover option highlighting +Dmytro : covered +- cover option zeroLine +Dmytro : covered +*/ + +// + +/** + * + * Get the nearest ( o.nearestLines ) lines to the range ( o.charsRangeLeft ) from source string( o.src ). + * Returns object with two elements: . + * Can be called in two ways: + * - First by passing all parameters in one options map( o ) ; + * - Second by passing source string( o.src ) and range( o.range ) as array or number; + + * The routine strLinesNearest returns the nearest {-o.numberOfLines-} lines to the range {-o.charsRangeLeft-} from source string {-o.src-}. + * Returns object with two elements: splits - array with a substring & the nearest lines and spans - array of indexes of the nearest lines. + * Can be called in two ways: + * - First by passing all parameters in one options map {-o-} ; + * - Second by passing source string {-o.src-} and range {-o.range-} as array or number; + + * + * @example + * // selecting single line + * _.strLinesNearest + * ({ + * src : `\na\nbc\ndef\nghij\n\n`, + * charsRangeLeft : [ 2, 4 ], + * nearestLines : 1, + * }); + * // returns o.splits = [ 'a', '\nb', 'c' ]; + * // returns o.spans = [ 1, 2, 4, 5 ]; + * + * @example + * // selecting single line + * _.strLinesNearest + * ({ + * src : `\na\nbc\ndef\nghij\n\n`, + * charsRangeLeft : 3, + * nearestLines : 2, + * }); + * // returns o.splits = [ 'a\n', 'b', 'c' ]; + * // returns o.spans = [ 1, 3, 4, 5 ]; + * + * @returns { Aux } - Returns object with next fields: + * splits - Array with three entries: + * splits[ 0 ] and splits[ 2 ] contains a string with the nearest lines, + * and splits[ 1 ] contains the substring corresponding to the range. + * spans - Array with indexes of begin and end of nearest lines. + * @param { Aux } o - Options. + * @param { String } o.src - Source string. + * @param { Array|Number } o.range - Sets range of lines to select from {-o.src-} or single line number. + * @param { Number } o.numberOfLines - Sets number of lines to select. + * @throws { Exception } Throw an exception if no argument provided. + * @throws { Exception } Throw an exception if {-o.src-} is not a String. + * @throws { Exception } Throw an exception if {-o.charsRangeLeft-} is not a Array or Number. + * @throws { Exception } Throw an exception if {-o-} is extended by unknown property. + * @function strLinesNearest + * @namespace Tools + */ + +function strLinesNearest_head( routine, args ) +{ + + let o = args[ 0 ]; + if( args[ 1 ] !== undefined ) + o = { src : args[ 0 ], charsRangeLeft : args[ 1 ] }; + + _.routine.options( routine, o ); + + if( _.number.is( o.charsRangeLeft ) ) + o.charsRangeLeft = [ o.charsRangeLeft, o.charsRangeLeft+1 ]; + + _.assert( _.intervalIs( o.charsRangeLeft ) ); + _.assert( _.numberIs( o.nearestLines ) ); + + return o; +} + +// + +function strLinesNearest_body( o ) +{ + let result = Object.create( null ); + // let resultCharRange = []; + let i, nearestLines; + + result.splits = []; + result.spans = [ o.charsRangeLeft[ 0 ], o.charsRangeLeft[ 0 ], o.charsRangeLeft[ 1 ], o.charsRangeLeft[ 1 ] ]; + + // logger.log( 'Result', result ) + // logger.log( ) + // /* */ + + if( o.nearestLines === 0 ) + { + // result = []; + result.splits = []; + result.splits[ 0 ] = ''; + result.splits[ 1 ] = o.src.substring( o.charsRangeLeft[ 0 ], o.charsRangeLeft[ 1 ] ); + result.splits[ 2 ] = ''; + return result; + } + + /* */ + + let nearestLinesLeft = Math.ceil( ( o.nearestLines+1 ) / 2 ); + nearestLines = nearestLinesLeft; + if( nearestLines > 0 ) + { + for( i = o.charsRangeLeft[ 0 ]-1 ; i >= 0 ; i-- ) + { + if( o.src[ i ] === '\n' ) + nearestLines -= 1; + if( nearestLines <= 0 ) + break; + } + i = i+1; + } + result.spans[ 0 ] = i; + + /* + // 0 -> 0 + 0 = 0 + // 1 -> 1 + 1 = 2 + // 2 -> 2 + 1 = 3 + // 3 -> 2 + 2 = 4 + */ + + /* */ + + let nearestLinesRight = o.nearestLines + 1 - nearestLinesLeft; + nearestLines = nearestLinesRight; + if( nearestLines > 0 ) + { + for( i = o.charsRangeLeft[ 1 ] ; i < o.src.length ; i++ ) + { + if( o.src[ i ] === '\n' ) + nearestLines -= 1; + if( nearestLines <= 0 ) + break; + } + } + result.spans[ 3 ] = i; + + /* */ + + result.splits[ 0 ] = o.src.substring( result.spans[ 0 ], result.spans[ 1 ] ); + result.splits[ 1 ] = o.src.substring( result.spans[ 1 ], result.spans[ 2 ] ); + result.splits[ 2 ] = o.src.substring( result.spans[ 2 ], result.spans[ 3 ] ); + + // result.splits[ 0 ] = o.src.substring( resultCharRange[ 0 ], o.charsRangeLeft[ 0 ] ); + // result.splits[ 1 ] = o.src.substring( o.charsRangeLeft[ 0 ], o.charsRangeLeft[ 1 ] ); + // result.splits[ 2 ] = o.src.substring( o.charsRangeLeft[ 1 ], resultCharRange[ 1 ] ); + + return result; +} + +strLinesNearest_body.defaults = +{ + src : null, + charsRangeLeft : null, + nearestLines : 3, + // outputFormat : 'map', +} + +let strLinesNearest = _.routine.unite( strLinesNearest_head, strLinesNearest_body ); + +// + +/** + * The routine strLinesNearestLog returns a report about found string from the source string {-o.src-}. + * Returns object with 2 elements: nearest - array with a substring & the nearest lines around, report - string with the found substring & surrounding lines. + * + * @example + * // selecting first 5 letters, next 3 letters and rest letters + * _.strLinesNearestLog + * ({ + * src : 'function add( x,y ) { return x + y }', + * charsRangeLeft : [ 5, 8 ], + * gray : 1, + * numberOfLines : 1 + * }); + * // returns { + * // nearest : [ 'funct', 'ion', ' add( x,y ) { return x + y }' ], + * // report : '1 : function add( x,y ) { return x + y }' + * // } + * + * @returns { Aux } - Returns object with next fileds: + * nearest { Array } - 3 elements: 1 - lines to the left of charsRangeLeft if {-numberOfLines-} allows, 2 - chars in range {-o.charsRangeLeft-}, 3 - lines to the right of {-o.charsRangeLeft-} if {-numberOfLines-} allows. + * report { String } - report about found string along with surrounding lines {-numberOfLines-} + * @param { Aux } o - Options. + * @param { String } o.src - Source string. + * @param { Array|Number } o.charsRangeLeft - Sets range of lines to select from {-o.src-} or single line number. + * @param { Number } o.numberOfLines - Sets number of lines to select. + * @param { Number } o.gray - 0: Paints searched text in yellow, everything else in gray, 1: No highlighting + * @throws { Exception } Throw an exception if no argument provided. + * @throws { Exception } Throw an exception if {-o.src-} is not a String. + * @throws { Exception } Throw an exception if {-o.charsRangeLeft-} is not a Array or Number. + * @throws { Exception } Throw an exception if {-o-} is extended by unknown property. + * @function strLinesNearestLog + * @namespace Tools +*/ + +function strLinesNearestLog_body( o ) +{ + let result = o; + + _.assert( o.charsRangeLeft[ 0 ] >= 0 && o.charsRangeLeft[ 1 ] >= 0, 'Expects positive ranges' ); + _.assert + ( + o.charsRangeLeft[ 0 ] <= o.src.length && o.charsRangeLeft[ 1 ] <= o.src.length, + 'Expects valid range for source string {-o.src-}' + ); + _.assert( o.sub === null || _.strIs( o.sub ) ); + + if( o.charsRangeLeft[ 0 ] > o.charsRangeLeft[ 1 ] ) + o.charsRangeLeft[ 1 ] = o.charsRangeLeft[ 0 ]; + + if( !result.nearest ) + result.nearest = _.strLinesNearest.body( o ).splits; + + result.log = result.nearest.slice(); + if( o.gray ) + { + if( o.sub !== null ) + result.log[ 1 ] = `{- ${result.log[ 1 ]} -} -> {- ${o.sub} -}`; + } + else + { + let str; + if( o.sub === null ) + str = _.color.strFormat( result.log[ 1 ], { fg : 'yellow' } ); + else + str = _.color.strFormat( result.log[ 1 ], { fg : 'red' } ) + _.color.strFormat( o.sub, { fg : 'green' } ); + result.log[ 1 ] = _.color.strUnescape( str ); + } + result.log = result.log.join( '' ); + + result.log = _.strLinesSplit( result.log ); + if( !o.gray ) + result.log = _.color.strEscape( result.log ); + + let left = o.src.substring( 0, o.charsRangeLeft[ 0 ] ); + // ---- BUG + // let zeroLine = left ? _.strLinesCount( left ) : 1; + // ---- + + // ---- FIX (Yevhen S.) + let zeroLine; + if( left ) + { + let linesNum = _.strLinesCount( left ) + if( linesNum <= 1 ) + zeroLine = 1; + else + zeroLine = linesNum - ( Math.floor( o.nearestLines / 2 ) ) <= 0 ? 1 : linesNum - ( Math.floor( o.nearestLines / 2 ) ); + } + else + { + zeroLine = 1 + } + // ---- + + result.log = _.strLinesNumber + ({ + src : result.log, + zeroLine, + onLine : ( line ) => + { + if( !o.gray ) + { + line[ 0 ] = _.color.strFormat( line[ 0 ], { fg : 'bright black' } ); + line[ 1 ] = _.color.strFormat( line[ 1 ], { fg : 'bright black' } ); + } + return line.join( '' ); + } + }); + + return result; +} + +strLinesNearestLog_body.defaults = +{ + src : null, + sub : null, + nearest : null, /* qqq2 : cover the option */ + charsRangeLeft : null, + nearestLines : 3, + gray : 0, +} + +let strLinesNearestLog = _.routine.unite( strLinesNearest_head, strLinesNearestLog_body ); + +// + +/** + * Returns a count of lines in a string. + * Expects one object: the string( src ) to be processed. + * + * @param {string} src - Source string. + * @returns {number} Returns a number of lines in string. + * + * @example + * _.strLinesCount( 'first\nsecond' ); + * // returns 2 + * + * @example + * _.strLinesCount( 'first\nsecond\nthird\n' ); + * // returns 4 + * + * @method strLinesCount + * @throws { Exception } Throw an exception if( src ) is not a String. + * @throws { Exception } Throw an exception if no argument provided. + * @namespace Tools + * +*/ + +function strLinesCount( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ) ); + let result = src.indexOf( '\n' ) === -1 ? 1 : _.str.lines.split( src ).length; + return result; +} + +// + +function strLinesSize( o ) +{ + let lines; + + if( !_.mapIs( o ) ) + o = { src : arguments[ 0 ] } + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( o.src ) || _.argumentsArray.like( o.src ) ); + _.routine.options( strLinesSize, o ); + if( o.onLength === null ) + o.onLength = ( src ) => src.length; + + if( _.strIs( o.src ) ) + { + if( o.onLength( o.src ) === '' ) + return [ 0, 0 ]; + if( o.src.indexOf( '\n' ) === -1 ) + return [ 1, o.onLength( o.src ) ]; + lines = _.str.lines.split( o.src ); + } + else + { + lines = o.src; + if( lines.length === 0 ) + return [ 0, 0 ]; + else if( lines.length === 1 && lines[ 0 ] === '' ) + return [ 0, 0 ]; + } + + let w = lines.reduce( ( a, e ) => Math.max( a, o.onLength( e ) ), 0 ); + + return [ lines.length, w ]; +} + +strLinesSize.defaults = +{ + src : null, + onLength : null, +} + +// + +function strLinesRangeWithCharRange_head( routine, args ) +{ + + let o = args[ 0 ]; + if( args[ 1 ] !== undefined ) + o = { src : args[ 0 ], charsRangeLeft : args[ 1 ] } + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + _.assert( _.intervalIs( o.charsRangeLeft ) ); + _.assert( _.strIs( o.src ) ); + _.routine.options( routine, o ); + + return o; +} + +// + +function strLinesRangeWithCharRange_body( o ) +{ + + let head = o.src.substring( 0, o.charsRangeLeft[ 0 ] ); + let mid = o.src.substring( o.charsRangeLeft[ 0 ], o.charsRangeLeft[ 1 ] + 1 ); + let result = [] + + result[ 0 ] = _.strLinesCount( head )-1; + result[ 1 ] = result[ 0 ] + _.strLinesCount( mid ); + + return result; +} + +strLinesRangeWithCharRange_body.defaults = +{ + src : null, + charsRangeLeft : null, +} + +let strLinesRangeWithCharRange = _.routine.unite( strLinesRangeWithCharRange_head, strLinesRangeWithCharRange_body ); + +// -- +// declare +// -- + +let Proto = +{ + + // dichotomy + + strIsHex, + strIsMultilined, + + strHasAny, + strHasAll, + strHasNone, + strHasSeveral, + + strsAnyHas, + strsAllHas, + strsNoneHas, + + // evaluator + + strCount, + strStripCount, + strsShortest, + strsLongest, + + // replacer + + _strRemoved, + strRemove, + + // strPrependOnce, + // strAppendOnce, + + strReplaceWords, + + // etc + + strCommonLeft, + strCommonRight, + strRandom, + strAlphabetFromRange, + + // formatter + + strForRange, /* xxx : investigate */ + strForCall, /* xxx : investigate */ + strDifference, + + // transformer + + strCapitalize, + strDecapitalize, + strSign, + strDesign, + strIsSigned, + + strEscape, + strCodeUnicodeEscape, + strUnicodeEscape, + strReverse, + + // splitter + + strSplitStrNumber, /* experimental */ + strSplitChunks, /* experimental */ + + strSplitCamel, + + // extractor + + _strOnly, + strOnly, + _strBut, + strBut, + strUnjoin, + + // joiner + + _strDup, + strDup : _.vectorize( _strDup ), + strJoin, + strJoinPath, + + // liner + + strLinesIndentation, + strLinesBut, + strLinesOnly, + + // strLinesSplit, + // strLinesJoin, + // strLinesStrip, + + strLinesNumber, + strLinesSelect, + strLinesNearest, + strLinesNearestLog, + strLinesCount, + strLinesSize, /* qqq2 : cover */ + strLinesRangeWithCharRange, + +} + +_.props.extend( _, Proto ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1/StrBasic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, StrBasic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file StrBasic_s */ })(); + +/* */ /* begin of file TreeMap_s */ ( function TreeMap_s() { function TreeMap_s_naked() { ( function _TreeMap_s_() +{ + +'use strict'; + +/** + * Modest implementation of treeMap. + * @module Tools/base/TreeMap +*/ + +const _ = _global_.wTools; +_.treeMap = _.treeMap || Object.create( null ); + +// -- +// dichotomy +// -- + +function is( node ) +{ + if( !_.aux.is( node ) ) + return false; + if( !node.ups ) + return false; + return true; +} + +// + +function make() +{ + _.assert( arguments.length === 0 ); + let node = Object.create( null ); + node.vals = new Set(); + node.ups = Object.create( null ); + return node; +} + +// -- +// declare +// -- + +let NamespaceExtension = +{ + + // dichotomy + + is, + make, + +} + +// + +/* _.props.extend */Object.assign( _.treeMap, NamespaceExtension ); + +// _.class.declareBasic +// ({ +// constructor : fo.class, +// iterate, +// equalAre : equalAre_functor( fo ), +// exportString, +// cloneShallow, /* xxx : implement */ +// cloneDeep, /* xxx : implement */ +// }); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1/TreeMap.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, TreeMap_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file TreeMap_s */ })(); + +/* */ /* begin of file Trie_s */ ( function Trie_s() { function Trie_s_naked() { ( function _Trie_s_() +{ + +'use strict'; + +/** + * Modest implementation of trie. + * @module Tools/base/Trie +*/ + +const _ = _global_.wTools; +_.trie = _.trie || Object.create( null ); + +// -- +// dichotomy +// -- + +function is( node ) +{ + if( !_.aux.is( node ) ) + return false; + if( !node.ups ) + return false; + return true; +} + +// + +function make() +{ + _.assert( arguments.length === 0 ); + let node = Object.create( null ); + node.vals = new Set(); + node.ups = Object.create( null ); + return node; +} + +// -- +// writer +// -- + +function makeWithPath_head( routine, args ) +{ + let self = this; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + + let o = args[ 0 ] + if( args.length === 2 ) + { + o = { root : args[ 0 ], path : args[ 1 ] } + } + + _.routine.options( routine, o ); + _.assert( _.longIs( o.path ) ); + _.assert( o.root === null || self.is( o.root ), () => `Expects node of trie or null, but got ${_.strType( o.root )}` ); + + return o; +} + +// + +function makeWithPath_body( o ) +{ + let self = this; + + if( o.root === null ) + o.root = self.make(); + + let trace = o.trace = []; + + trace.push([ o.root, 0, o.path.length ]); + + for( let i = 0 ; i < trace.length ; i++ ) + act( ... trace[ i ] ); + + return o; + + function act( node, f, l ) + { + if( f === l ) + { + o.child = node; + return; + } + let node2 = node.ups[ o.path[ f ] ]; + if( !node2 ) + node2 = node.ups[ o.path[ f ] ] = self.make(); + trace.push([ node2, f+1, l ]); + } + +} + +makeWithPath_body.defaults = +{ + root : null, + path : null, +} + +let makeWithPath = _.routine.unite( makeWithPath_head, makeWithPath_body ); + +// + +function addSingle_head( routine, args ) +{ + let self = this; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 3 ); + + let o = args[ 0 ] + if( args.length === 3 ) + { + if( args.length === 3 ) + o = { root : args[ 0 ], path : args[ 1 ], val : args[ 2 ] } + else + o = { root : args[ 0 ] }; + } + + _.routine.options( routine, o ); + _.assert( _.longIs( o.path ) ); + _.assert( o.root === null || self.is( o.root ), () => `Expects node of trie or null, but got ${_.strType( o.root )}` ); + + return o; +} + +// + +function addSingle_body( o ) +{ + let self = this; + self.makeWithPath.body.call( self, o ); + o.child.vals.add( o.val ); + return o; +} + +addSingle_body.defaults = +{ + root : null, + path : null, + val : null, +} + +let addSingle = _.routine.unite( addSingle_head, addSingle_body ); + +// + +function addMultiple_head( routine, args ) +{ + let self = this; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 3 ); + + let o = args[ 0 ] + if( args.length === 3 ) + { + if( args.length === 3 ) + o = { root : args[ 0 ], path : args[ 1 ], vals : args[ 2 ] } + else + o = { root : args[ 0 ] }; + } + + _.routine.options( routine, o ); + _.assert( _.longIs( o.path ) ); + _.assert( o.root === null || self.is( o.root ), () => `Expects node of trie or null, but got ${_.strType( o.root )}` ); + _.assert( _.countable.is( o.vals ) ); + + return o; +} + +// + +function addMultiple_body( o ) +{ + let self = this; + self.makeWithPath.body.call( self, o ); + if( o.onVal ) + { + for( let val of o.vals ) + o.child.vals.add( o.onVal( val, o ) ); + } + else + { + for( let val of o.vals ) + o.child.vals.add( val ); + } + return o; +} + +addMultiple_body.defaults = +{ + root : null, + path : null, + vals : null, + onVal : null, +} + +let addMultiple = _.routine.unite( addMultiple_head, addMultiple_body ); + +// + +function addDeep_body( o ) +{ + let self = this; + let path = o.path; + let l = o.path.length; + + for( let i = 0 ; i <= l ; i++ ) + { + o.path = path.slice( i, l ); + self.addMultiple.body.call( self, o ); + } + + o.path = path; + return o; +} + +addDeep_body.defaults = +{ + ... addMultiple.defaults, +} + +let addDeep = _.routine.unite( addMultiple_head, addDeep_body ); + +// + +function delete_head( routine, args ) +{ + let self = this; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + + let o = args[ 0 ]; + + _.routine.options( routine, o ); + _.assert( self.is( o.root ), () => `Expects node of trie, but got ${_.strType( o.root )}` ); + _.assert( self.is( o.node ), () => `Expects node of trie, but got ${_.strType( o.node )}` ); + _.assert + ( + o.vals === null || _.countableIs( o.vals ), () => `Vals should countable if specified, but it is ${_.strType( o.vals )}` + ); + + return o; +} + +// + +function delete_body( o ) +{ + let self = this; + + if( o.vals === null ) + for( let val of o.node.vals ) + { + o.node.vals.delete( val ); + } + else + for( let val of o.vals ) + { + o.node.vals.delete( val ); + } + + return o; +} + +delete_body.defaults = +{ + node : null, + vals : null, +} + +let _delete = _.routine.unite( delete_head, delete_body ); + +// + +function deleteWithPath_head( routine, args ) +{ + let self = this; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + + let o = args[ 0 ] + if( args.length == 2 ) + { + o = { root : args[ 0 ], path : args[ 1 ] } + } + else if( args.length == 3 ) + { + if( args.length === 3 ) + o = { root : args[ 0 ], path : args[ 1 ], vals : args[ 2 ] } + else + o = { root : args[ 0 ] }; + } + + _.routine.options( routine, o ); + _.assert( self.is( o.root ), () => `Expects node of trie, but got ${_.strType( o.root )}` ); + _.assert( _.longIs( o.path ) ); + _.assert + ( + o.vals === null || _.countableIs( o.vals ), () => `Vals should countable if specified, but it is ${_.strType( o.vals )}` + ); + + return o; +} + +// + +function deleteWithPath_body( o ) +{ + let self = this; + + self.withPath.body.call( self, o ); + if( !o.child ) + return o; + + o.node = o.child; + self.delete.body.call( self, o ); + + if( o.child.vals.size === 0 && Object.keys( o.child.ups ).length === 0 && o.shrinking ) + self.shrinkWithPath.body.call( self, o ); + + return o; +} + +deleteWithPath_body.defaults = +{ + root : null, + path : null, + vals : null, + shrinking : true, +} + +let deleteWithPath = _.routine.unite( deleteWithPath_head, deleteWithPath_body ); + +// + +function shrinkWithPath_head( routine, args ) +{ + let self = this; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + + let o = args[ 0 ] + if( args.length == 2 ) + { + o = { root : args[ 0 ], path : args[ 1 ] } + } + else if( args.length == 3 ) + { + if( args.length === 3 ) + o = { root : args[ 0 ], path : args[ 1 ], vals : args[ 2 ] } + else + o = { root : args[ 0 ] }; + } + + _.routine.options( routine, o ); + _.assert( self.is( o.root ), () => `Expects node of trie, but got ${_.strType( o.root )}` ); + _.assert( o.path === null || _.longIs( o.path ) ); + _.assert( o.trace === null || _.longIs( o.trace ) ); + + return o; +} + +// + +function shrinkWithPath_body( o ) +{ + let self = this; + + if( !o.trace ) + { + self.withPath.body.call( self, o ); + if( !o.child ) + return o; + } + + let node = o.trace[ o.trace.length - 1 ][ 0 ]; + if( node.vals.size !== 0 || Object.keys( node.ups ).length !== 0 ) + { + o.child = undefined; + return o; + } + + for( let i = o.trace.length - 1 ; i >= 0 ; i-- ) + if( o.trace[ i ][ 0 ].vals.size > 0 ) + { + o.childLevel = i + 1; + o.child = o.trace[ o.childLevel ]; + if( !o.child ) + return; + o.child = o.child[ 0 ]; + o.parent = o.trace[ i ][ 0 ]; + _.assert( o.parent.ups[ o.path[ i ] ] === o.child ); + delete o.parent.ups[ o.path[ i ] ]; + return o; + } + o.child = o.root; + + return o; +} + +shrinkWithPath_body.defaults = +{ + root : null, + path : null, + trace : null, +} + +let shrinkWithPath = _.routine.unite( shrinkWithPath_head, shrinkWithPath_body ); + +// + +function shrink_head( routine, args ) +{ + let self = this; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 ); + + let o = args[ 0 ] + if( self.is( o ) ) + o = { root : o } + + _.routine.options( routine, o ); + _.assert( self.is( o.root ), () => `Expects node of trie, but got ${_.strType( o.root )}` ); + + return o; +} + +// + +function shrink_body( o ) +{ + let self = this; + + let stack = []; + stack.push([ o.root, null, null ]); + + debugger; + + for( let i = 0 ; i < stack.length ; i++ ) + actUp( ... stack[ i ] ); + + for( let i = stack.length - 1 ; i >= 0 ; i-- ) + actDown( ... stack[ i ] ); + + debugger; + + return o; + + function actUp( node ) + { + for( let k in node.ups ) + { + let node2 = node.ups[ k ]; + stack.push([ node2, k, node ]); + } + } + + function actDown( child, key, parent ) + { + debugger; + if( parent !== null ) + if( child.vals.size === 0 && Object.keys( child.ups ).length === 0 ) + { + debugger; + _.assert( parent.ups[ key ] === child ); + delete parent.ups[ key ]; + o.counter += 1; + } + + } + +} + +shrink_body.defaults = +{ + counter : 0, + root : null, +} + +let shrink = _.routine.unite( shrink_head, shrink_body ); + +// -- +// reader +// -- + +function withPath_head( routine, args ) +{ + let self = this; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + + let o = args[ 0 ] + if( args.length === 2 ) + { + o = { root : args[ 0 ], path : args[ 1 ] } + } + + _.routine.options( routine, o ); + _.assert( _.longIs( o.path ) ); + _.assert( self.is( o.root ), () => `Expects node of trie, but got ${_.strType( o.root )}` ); + + return o; +} + +// + +function withPath_body( o ) +{ + let self = this; + let trace = o.trace = []; + + trace.push([ o.root, 0, o.path.length ]); /* xxx : remove 3rd argument */ + + for( let i = 0 ; i < trace.length ; i++ ) + act( ... trace[ i ] ); + + return o; + + function act( node, f, l ) + { + if( f === l ) + { + o.child = node; + return; + } + let node2 = node.ups[ o.path[ f ] ]; + if( !node2 ) + return; + trace.push([ node2, f+1, l ]); + } + +} + +withPath_body.defaults = +{ + root : null, + path : null, +} + +let withPath = _.routine.unite( withPath_head, withPath_body ); + +// + +function valEach_head( routine, args ) +{ + let self = this; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 ); + + let o = args[ 0 ] + if( self.is( o ) ) + { + o = { root : args[ 0 ] } + } + + _.routine.options( routine, o ); + _.assert( self.is( o.root ), () => `Expects node of trie, but got ${_.strType( o.root )}` ); + + return o; +} + +// + +function valEach_body( o ) +{ + let self = this; + + o.vals = o.vals || new Set; + + let stack = []; + stack.push([ o.root ]); + + if( _.setIs( o.vals ) ) + { + while( stack.length ) + actSet( ... stack.pop() ); + } + else + { + while( stack.length ) + actArray( ... stack.pop() ); + } + + return o; + + function actSet( node ) + { + for( let k in node.ups ) + { + let node2 = node.ups[ k ]; + stack.push([ node2 ]); + } + for( let val of node.vals ) + { + o.vals.add( val ); + } + } + + function actArray( node ) + { + for( let k in node.ups ) + { + let node2 = node.ups[ k ]; + stack.push([ node2 ]); + } + for( let val of node.vals ) + { + _.arrayAppendOnce( o.vals, val ); + } + } + +} + +valEach_body.defaults = +{ + root : null, + vals : null, +} + +let valEach = _.routine.unite( valEach_head, valEach_body ); + +// + +function valEachAbove_head( routine, args ) +{ + let self = this; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + + let o = args[ 0 ] + if( args.length === 2 ) + { + o = { root : args[ 0 ], path : args[ 1 ] } + } + + _.routine.options( routine, o ); + _.assert( self.is( o.root ), () => `Expects node of trie, but got ${_.strType( o.root )}` ); + + return o; +} + +// + +function valEachAbove_body( o ) +{ + let self = this; + + o.vals = o.vals || []; + + self.withPath.body.call( self, o ); + if( !o.child ) + return o; + + o.root = o.child; + self.valEach.body.call( self, o ); + + return o; +} + +valEachAbove_body.defaults = +{ + root : null, + path : null, + vals : null, +} + +let valEachAbove = _.routine.unite( withPath_head, valEachAbove_body ); + +// -- +// declare +// -- + +let Proto = +{ + + // dichotomy + + is, + make, + + // writer + + makeWithPath, + addSingle, + addMultiple, + add : addMultiple, + addDeep, + delete : _delete, + deleteWithPath, + shrinkWithPath, + shrink, + + // reader + + withPath, + valEach, + valEachAbove, + +} + +// + +/* _.props.extend */Object.assign( _.trie, Proto ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1/Trie.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wTools/proto/wtools/abase/l1/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Trie_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Trie_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/warraysorted/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/warraysorted/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file warraysorted */ ( function warraysorted() { function warraysorted_naked() { +module.exports = require( '../wtools/abase/l4/ArraySorted.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wArraySorted', 'warraysorted' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/warraysorted/proto/node_modules/warraysorted' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/warraysorted/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, warraysorted_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file warraysorted */ })(); + +/* */ /* begin of file ArraySorted_s */ ( function ArraySorted_s() { function ArraySorted_s_naked() { ( function _ArraySorted_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to operate effectively sorted arrays. For that ArraySorted provides customizable quicksort algorithm and a dozen functions to optimally find/add/remove single/multiple elements into a sorted array, add/remove sorted array to/from another sorted array. Use it to increase the performance of your algorithms. + @module Tools/base/ArraySorted +*/ + +/** + * */ + +/** + * Collection of cross-platform routines to operate effectively sorted arrays. + @namespace wTools.sorted + @extends Tools + @module Tools/base/ArraySorted +*/ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + +} + +// + +const _global = _global_; +const _ = _global_.wTools; +_.sorted = _.sorted || Object.create( null ); + +// -- +// array sorted +// -- + +/** + * Bin search of element ( ins ) in array ( arr ). Find element with closest value. + * If array does not have such element then return index of smallest possible greater element. + * If array does not have such element then element previous to returned is smaller. + * Could return index of the next ( non-existent ) after the last one element. + * Zero is the least possible returned index. + * Could return index of any element if there are several elements with such value. + * + * @param { longIs } arr - Entity to check. + * @param { Number } ins - Element to locate in the array. + * @param { Function } comparator - A callback function. + * @param { Number } left - The index to start the search at. + * @param { Number } right - The index to end the search at. + * + * @example + * // returns 4 + * _lookUpAct( [ 1, 2, 3, 4, 5 ], 5, function( a, b ) { return a - b }, 0, 5 ); + * + * @example + * // returns 5 + * _lookUpAct( [ 1, 2, 3, 4, 5 ], 55, function( a, b ) { return a - b }, 0, 5 ); + * + * @returns { Number } Returns the first index at which a given element (ins) + * can be found in the array (arr). + * Otherwise, if (ins) was not found, it returns the length of the array (arr) or the index from which it ended search at. + * @function _lookUpAct + * @namespace Tools.sorted + */ + +function _lookUpAct( /* arr, ins, comparator, left, right */ ) +{ + let arr = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let comparator = arguments[ 2 ]; + let left = arguments[ 3 ]; + let right = arguments[ 4 ]; + + _.assert( right >= 0 ); + _.assert( left <= arr.length ); + + let oleft = left; + let oright = right; + + let d = 0; + let current = ( left + right ) >> 1; + + /* */ + + while( left < right ) + { + + let d = comparator( arr[ current ], ins ); + + if( d < 0 ) + { + left = current + 1; + current = ( left + right ) >> 1; + } + else if( d > 0 ) + { + right = current; + current = ( left + right ) >> 1; + } + else return current; + + } + + /* */ + + if( current < arr.length ) + { + let d = comparator( arr[ current ], ins ); + if( d === 0 ) + return current; + if( d < 0 ) + current += 1; + } + + /* */ + + if( Config.debug ) + { + + /* current element is greater */ + if( _.numberIs( ins ) && current > oleft ) + if( current < oright ) + _.assert( comparator( arr[ current ], ins ) > 0 ); + + /* next element is greater */ + if( _.numberIs( ins ) ) + if( current+1 < oright ) + _.assert( comparator( arr[ current+1 ], ins ) > 0 ); + + /* prev element is smaller */ + if( _.numberIs( ins ) ) + if( current-1 >= oleft ) + _.assert( comparator( arr[ current-1 ], ins ) < 0 ); + + } + + return current; +} + +// + +/** + * @summary Binary search of element( ins ) in array( arr ). + * @description + * Returns index if element exists, otherwise returns `-1`. + * Accepts comparator routine as third argument. + * + * @param {Array} src - Source array + * @param {*} ins - Element to find + * @param {Function} [comparator] Routine comparator + * @returns {Number} Returns index of found element or `-1` + * + * @example + * _.sorted.lookUpIndex( [ 2, 3, 4 ], 4 )// 2 + * + * @example + * _.sorted.lookUpIndex( [ 2, 3, 4 ], 0 )// -1 + * + * @function lookUpIndex + * @namespace Tools.sorted + * + */ + +function lookUpIndex( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + comparator = _._comparatorFromEvaluator( comparator ); + let index = this._lookUpAct( arr, ins, comparator, 0, arr.length ); + + if( index === arr.length ) + return -1; + + if( comparator( ins, arr[ index ] ) !== 0 ) + return -1; + + return index; +} + +// + +/** + * @summary Binary search of element( ins ) in array( arr ). + * @description + * Returns found element or undefined. + * Accepts comparator routine as third argument. + * + * @param {Array} src - Source array + * @param {*} ins - Element to find + * @param {Function} [comparator] Routine comparator + * @returns {} Returns found element or undefined. + * @example + * _.sorted.lookUpValue( [ 2, 3, 4 ], 4 )// 4 + * + * @example + * _.sorted.lookUpValue( [ 2, 3, 4 ], 0 )// undefined + * + * @function lookUpValue + * @namespace Tools.sorted + * + */ + +function lookUpValue( arr, ins, comparator ) +{ + let index = this.lookUpIndex.apply( this, arguments ); + return arr[ index ]; +} + +// + +/** + * The wTools.sorted.lookUp() method returns a new object containing the properties, (value, index), + * corresponding to the found value (ins) from array (arr). + * + * @see {@link wTools._lookUpAct} - See for more information. + * + * @param { longIs } arr - Entity to check. + * @param { Number } ins - Element to locate in the array. + * @param { wTools~compareCallback } [comparator=function( a, b ) { return a - b }] comparator - A callback function. + * + * @example + * // returns { value : 5, index : 4 } + * _.sorted.lookUp( [ 1, 2, 3, 4, 5 ], 5, function( a, b ) { return a - b } ); + * + * @example + * // returns undefined + * _.sorted.lookUp( [ 1, 2, 3, 4, 5 ], 55, function( a, b ) { return a - b } ); + * + * @returns { Object } Returns a new object containing the properties, (value, index), + * corresponding to the found value (ins) from the array (arr). + * Otherwise, it returns 'undefined'. + * @function lookUp + * @throws { Error } Will throw an Error if (arguments.length) is less than two or more than three. + * @throws { Error } Will throw an Error if (arr) is not an array-like. + * @namespace Tools.sorted + */ + +function lookUp( arr, ins, comparator ) +{ + let index = this.lookUpIndex.apply( this, arguments ); + return { value : arr[ index ], index }; +} + +// + +/** + * @summary Binary search of element( ins ) in array( arr ). + * @description + * Finds element equal to passed value( ins ) or element with smallest possible difference. + * Returns index of found element or `-1`. + * Accepts comparator routine as third argument. + * + * @param {Array} src - Source array + * @param {*} ins - Element to find + * @param {Function} [comparator] Routine comparator + * @returns {Number} Returns index of found element or `-1` + * + * @example + * _.sorted.lookUpClosestIndex( [ 2, 3, 4 ], 4 )// 2 + * + * @example + * _.sorted.lookUpClosestIndex( [ 2, 3, 4 ], 1 )// 0 + * + * @example + * _.sorted.lookUpClosestIndex( [ 2, 3, 4 ], 10 )// -1 + * + * @function lookUpClosestIndex + * @namespace Tools.sorted + * + */ + +function lookUpClosestIndex( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + comparator = _._comparatorFromEvaluator( comparator ); + let index = this._lookUpAct( arr, ins, comparator, 0, arr.length ); + + return index; +} + +// + +/** + * @summary Binary search of element( ins ) in array( arr ). + * @description + * Finds element equal to passed value( ins ) or element with smallest possible difference. + * Returns value of found element or undefined. + * Accepts comparator routine as third argument. + * + * @param {Array} src - Source array + * @param {*} ins - Element to find + * @param {Function} [comparator] Routine comparator + * @returns {Number} Returns value of found element or undefined + * + * @example + * _.sorted.lookUpClosestValue( [ 2, 3, 4 ], 4 )// 4 + * + * @example + * _.sorted.lookUpClosestValue( [ 2, 3, 4 ], 1 )// 2 + * + * @example + * _.sorted.lookUpClosestValue( [ 2, 3, 4 ], 10 )// undefined + * + * @function lookUpClosestValue + * @namespace Tools.sorted + * + */ + +function lookUpClosestValue( arr, ins, comparator ) +{ + let index = this.lookUpClosestIndex.apply( this, arguments ); + return arr[ index ]; +} + +// + +/** + * @summary Binary search of element( ins ) in array( arr ). + * @description + * Finds element equal to passed value( ins ) or element with smallest possible difference. + * Returns map with two properties: `value` and `index`. If element is not found, `value` is `undefined`, index : `-1`. + * Accepts comparator routine as third argument. + * + * @param {Array} src - Source array + * @param {*} ins - Element to find + * @param {Function} [comparator] Routine comparator + * @returns {Object} Returns results of search as map with two properties: `value` and `index`. + * + * @example + * _.sorted.lookUpClosest( [ 2, 3, 4 ], 4 )// { value : 4, index : 2 } + * + * @example + * _.sorted.lookUpClosest( [ 2, 3, 4 ], 1 )// { value : 2, index : 0 } + * + * @example + * _.sorted.lookUpClosest( [ 2, 3, 4 ], 10 )// { value : undefined, index : -1 } + * + * @function lookUpClosest + * @namespace Tools.sorted + * + */ + +function lookUpClosest( arr, ins, comparator ) +{ + let index = this.lookUpClosestIndex.apply( this, arguments ); + return { value : arr[ index ], index }; +} + +// + +/** + * @summary Looks for elements from provived interval( range ) in source array( arr ). + * + * @description + * Returns range of indecies where found elements are located. + * Accepts comparator routine as third argument. + * + * @param {Array} src - Source array + * @param {*} ins - Element to find + * @param {Function} [comparator] Routine comparator + * @returns {Object} Returns range of indecies where found elements are located. + * + * @example + * _.sorted.lookUpInterval( [ 2, 3, 4 ], [ 0, 10 ] )// [0, 3] + * + * @example + * _.sorted.lookUpInterval( [ 2, 3, 4 ], [ -1, 1 ] )// [0, 0] + * + * @example + * _.sorted.lookUpInterval( [ 2, 3, 4 ], [ 5, 10 ] )// [3, 3] + * + * @function lookUpInterval + * @namespace Tools.sorted + * + */ + +function lookUpInterval( arr, range, comparator ) +{ + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + comparator = _._comparatorFromEvaluator( comparator ); + let length = arr.length; + let b = _.sorted._leftMostAtLeastIndex( arr, range[ 0 ], comparator, 0, length ); + + if( b === length || comparator( arr[ b ], range[ 1 ] ) > 0 ) + return [ b, b ]; + + let e = _.sorted._rightMostAtLeastIndex( arr, range[ 1 ], comparator, b+1, length ); + + if( comparator( arr[ e ], range[ 1 ] ) <= 0 ) + e += 1; + + if( Config.debug ) + { + + if( b < length ) + _.assert( arr[ b ] >= range[ 0 ] ); + + if( b > 0 ) + _.assert( arr[ b-1 ] < range[ 0 ] ); + + if( e < length ) + _.assert( arr[ e ] > range[ 1 ] ); + + if( e > 0 ) + _.assert( arr[ e-1 ] <= range[ 1 ] ); + + } + + return [ b, e ] +} + +// + +function lookUpIntervalNarrowest( arr, range, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + comparator = _._comparatorFromEvaluator( comparator ); + + let length = arr.length; + let b = _.sorted._rightMostAtLeastIndex( arr, range[ 0 ], comparator, 0, length ); + + let e = _.sorted._leftMostAtMostIndex( arr, range[ 1 ], comparator, b, length ); + + e += 1; + + if( Config.debug ) + { + + if( b < length ) + _.assert( comparator( arr[ b ], range[ 0 ] ) >= 0 ); + + if( b > 0 ) + _.assert( comparator( arr[ b-1 ], range[ 0 ] ) <= 0 ); + + if( e < length ) + _.assert( comparator( arr[ e ], range[ 1 ] ) >= 0 ); + + if( e > 0 ) + _.assert( comparator( arr[ e-1 ], range[ 1 ] ) <= 0 ); + + } + + return [ b, e ] +} + +// + +function lookUpIntervalNarrowestOld( arr, range, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + comparator = _._comparatorFromEvaluator( comparator ); + let length = arr.length; + let b = _.sorted._rightMostAtLeastIndex( arr, range[ 0 ], comparator, 0, length ); + + if( b === length ) + if( comparator( arr[ b - 1 ], range[ 0 ] ) < 0 ) + return [ b, b ]; + + if( b === 0 ) + if( comparator( arr[ b ], range[ 1 ] ) > 0 ) + return [ b, b ]; + + let e = _.sorted._leftMostAtLeastIndex( arr, range[ 1 ], comparator, b+1, length ); + + if( comparator( arr[ e - 1 ], range[ 1 ] ) > 0 ) + e -= 1; + + if( comparator( arr[ e ], range[ 1 ] ) <= 0 ) + e += 1; + + if( Config.debug ) + { + + if( b < length ) + _.assert( arr[ b ] >= range[ 0 ] ); + + if( b > 0 ) + _.assert( arr[ b-1 ] <= range[ 0 ] ); + + if( e < length ) + _.assert( arr[ e ] >= range[ 1 ] ); + + if( e > 0 ) + _.assert( arr[ e-1 ] <= range[ 1 ] ); + + } + + return [ b, e ] +} + +// + +function lookUpIntervalHaving( arr, range, comparator ) +{ + comparator = _._comparatorFromEvaluator( comparator ); + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + let length = arr.length; + let b = _.sorted._leftMostAtMostIndex( arr, range[ 0 ], comparator, 0, length ); + let e = _.sorted._rightMostAtMostIndex( arr, range[ 1 ]-1, comparator, Math.max( 0, b ), length )+1; + + if( e === 0 && b === -1 ) + e -= 1; + + if( Config.debug ) + { + _.assert( b === -1 || b === length || comparator( arr[ b ], range[ 0 ] ) <= 0 ); + _.assert( e === -1 || e === length || comparator( arr[ e ], range[ 1 ] ) >= 0 ); + _.assert( e <= length ) + } + + return [ b, e ] +} + +// + +function lookUpIntervalEmbracingAtLeast( arr, range, comparator ) +{ + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + comparator = _._comparatorFromEvaluator( comparator ); + + let length = arr.length; + let b = _.sorted._rightMostAtMostIndex( arr, range[ 0 ], comparator, 0, length ); + if( b < 0 ) + b = 0 + + let e0 = length; + if( b+1 <= length ) + e0 = _.sorted._rightMostAtLeastIndex( arr, range[ 1 ], comparator, b+1, length ); + let e = e0; + while( e < arr.length-1 ) + { + if( comparator( arr[ e0 ], arr[ e+1 ] ) !== 0 ) + break; + e += 1; + } + + if( Config.debug ) + { + + if( b > 0 ) + _.assert( arr[ b-1 ] <= range[ 0 ] ); + + if( e < length ) + _.assert( arr[ e ] >= range[ 1 ] ); + + } + + return [ b, e ] +} + +// + +function lookUpIntervalEmbracingAtLeastOld( arr, range, comparator ) +{ + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + comparator = _._comparatorFromEvaluator( comparator ); + let length = arr.length; + let b = _.sorted._rightMostAtLeastIndex( arr, range[ 0 ], comparator, 0, length ); + + if( 0 < b && b < length ) + if( comparator( arr[ b ], range[ 0 ] ) > 0 ) + b -= 1; + + if( b === length || comparator( arr[ b ], range[ 1 ] ) > 0 ) + return [ b, b ]; + + let e = _.sorted._leftMostAtLeastIndex( arr, range[ 1 ], comparator, b+1, length ); + + if( e > 0 ) + { + if( e < length ) + if( comparator( arr[ e-1 ], range[ 1 ] ) < 0 ) + e += 1; + } + else + { + _.assert( length > 0 ); + if( comparator( arr[ e ], range[ 1 ] ) <= 0 ) + e += 1; + } + + if( Config.debug ) + { + + // if( b < length ) + // _.assert( arr[ b ] >= range[ 0 ] ); + + if( b > 0 ) + _.assert( arr[ b-1 ] <= range[ 0 ] ); + + if( e < length ) + _.assert( arr[ e ] >= range[ 1 ] ); + + // if( e > 0 ) + // _.assert( arr[ e-1 ] <= range[ 1 ] ); + + } + + return [ b, e ] +} + +// -- +// left-most at-least +// -- + +function _leftMostAtLeastIndex( /* arr, ins, comparator, left, right */ ) +{ + let arr = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let comparator = arguments[ 2 ]; + let left = arguments[ 3 ]; + let right = arguments[ 4 ]; + + let index = _.sorted._lookUpAct( arr, ins, comparator, left, right ); + + _.assert( arguments.length === 5 ); + + if( index === right ) + return right; + + let c = comparator( arr[ index ], ins ); + + if( c !== 0 ) + return index; + + let i = index-1; + while( i >= left ) + { + if( comparator( arr[ i ], ins ) < 0 ) + break; + i -= 1; + } + + index = i + 1; + + return index; +} + +// + +function leftMostAtLeastIndex( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + if( !arr.length ) + return 0; + + let l = arr.length; + comparator = _._comparatorFromEvaluator( comparator ); + let index = _.sorted._leftMostAtLeastIndex( arr, ins, comparator, 0, l ); + + return index; +} + +// + +function leftMostAtLeastValue( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + let index = this.leftMostAtLeastIndex( arr, ins, comparator ); + let result = arr[ index ]; + + return result; +} + +// + +function leftMostAtLeast( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + let index = this.leftMostAtLeastIndex( arr, ins, comparator ); + let result = { value : arr[ index ], index }; + + return result; +} + +// -- +// left-most at-most +// -- + +function _leftMostAtMostIndex( /* arr, ins, comparator, left, right */ ) +{ + let arr = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let comparator = arguments[ 2 ]; + let left = arguments[ 3 ]; + let right = arguments[ 4 ]; + + let index = _.sorted._lookUpAct( arr, ins, comparator, left, right ); + + _.assert( arguments.length === 5 ); + _.assert( index >= 0, 'expectation' ); + + if( index === right ) + return right-1; + + let i = index; + while( i >= left ) + { + let c = comparator( arr[ i ], ins ); + if( c < 0 ) + { + return index; + } + else if( c === 0 ) + { + index = i; + } + else + { + index -= 1; + } + i -= 1; + } + + return index; +} + +// + +function leftMostAtMostIndex( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + if( !arr.length ) + return 0; + + let l = arr.length; + comparator = _._comparatorFromEvaluator( comparator ); + let index = _.sorted._leftMostAtMostIndex( arr, ins, comparator, 0, l ); + + return index; +} + +// + +function leftMostAtMostValue( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + let index = this.leftMostAtMostIndex( arr, ins, comparator ); + let result = arr[ index ]; + + return result; +} + +// + +function leftMostAtMost( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + let index = this.leftMostAtMostIndex( arr, ins, comparator ); + let result = { value : arr[ index ], index }; + + return result; +} + +// -- +// right-most at-least +// -- + +function _rightMostAtLeastIndex( /* arr, ins, comparator, left, right */ ) +{ + let arr = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let comparator = arguments[ 2 ]; + let left = arguments[ 3 ]; + let right = arguments[ 4 ]; + + let index = _.sorted._lookUpAct( arr, ins, comparator, left, right ); + + _.assert( arguments.length === 5 ); + + if( index === right ) + return right; + + let c = comparator( arr[ index ], ins ); + if( c !== 0 ) + return index; + + let i = index+1; + while( i < right ) + { + if( comparator( arr[ i ], ins ) > 0 ) + break; + i += 1; + } + + index = i - 1; + return index; +} + +// + +function rightMostAtLeastIndex( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + if( !arr.length ) + return 0; + + let l = arr.length; + comparator = _._comparatorFromEvaluator( comparator ); + let index = _.sorted._rightMostAtLeastIndex( arr, ins, comparator, 0, l ); + + return index; +} + +// + +function rightMostAtLeastValue( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + let index = this.rightMostAtLeastIndex( arr, ins, comparator ); + let result = arr[ index ]; + + return result; +} + +// + +function rightMostAtLeast( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + let index = this.rightMostAtLeastIndex( arr, ins, comparator ); + let result = { value : arr[ index ], index }; + + return result; +} + +// -- +// right-most at-most +// -- + +function _rightMostAtMostIndex( /* arr, ins, comparator, left, right */ ) +{ + let arr = arguments[ 0 ]; + let ins = arguments[ 1 ]; + let comparator = arguments[ 2 ]; + let left = arguments[ 3 ]; + let right = arguments[ 4 ]; + + let index = _.sorted._lookUpAct( arr, ins, comparator, left, right ); + + _.assert( arguments.length === 5 ); + + if( index === right ) + return right-1; + + let i = index; + while( i < right ) + { + let c = comparator( arr[ i ], ins ); + if( c > 0 ) + { + index = i - 1; + return index; + } + else if( c === 0 ) + { + index = i; + } + i += 1; + } + + return index; +} + +// + +function rightMostAtMostIndex( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + if( !arr.length ) + return 0; + + let l = arr.length; + comparator = _._comparatorFromEvaluator( comparator ); + let index = _.sorted._rightMostAtMostIndex( arr, ins, comparator, 0, l ); + + return index; +} + +// + +function rightMostAtMostValue( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + let index = this.rightMostAtMostIndex( arr, ins, comparator ); + let result = arr[ index ]; + + return result; +} + +// + +function rightMostAtMost( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + let index = this.rightMostAtMostIndex( arr, ins, comparator ); + let result = { value : arr[ index ], index }; + + return result; +} + +// -- +// +// -- + +/** + * The wTools.sorted.remove() method returns true, if a value (ins) was removed from an array (arr). + * Otherwise, it returns false. + * + * @see {@link wTools._lookUpAct} - See for more information. + * + * @param { longIs } arr - Entity to check. + * @param { Number } ins - Element to locate in the array. + * @param { wTools~compareCallback } [ comparator = function( a, b ) { return a - b } ] comparator - A callback function. + * + * @example + * // returns true + * this.sorted.remove( [ 1, 2, 3, 4, 5 ], 5, function( a, b ) { return a - b } ); // => [ 1, 2, 3, 4 ] + * + * @example + * // returns false + * this.sorted.remove( [ 1, 2, 3, 4, 5 ], 55, function( a, b ) { return a - b } ); // => [ 1, 2, 3, 4, 5 ] + * + * @returns { Boolean } Returns true, if a value (ins) was removed from an array (arr). + * Otherwise, it returns false. + * @function remove + * @throws { Error } Will throw an Error if (arguments.length) is less than two or more than three. + * @throws { Error } Will throw an Error if (arr) is not an array-like. + * @namespace Tools.sorted + */ + +function remove( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + comparator = _._comparatorFromEvaluator( comparator ); + let l = arr.length; + let index = _.sorted._lookUpAct( arr, ins, comparator, 0, l ); + + let remove = index !== l && comparator( ins, arr[ index ] ) === 0; + + if( remove ) arr.splice( index, 1 ); + + return remove; +} + +// + +/** + * The wTools.sorted.addOnce() method returns true, if a value (ins) was added to an array (arr). + * Otherwise, it returns false. + * + * It calls the method (_.sorted._lookUpAct( arr, ins, comparator, 0, arr.length - 1 )), + * that returns the index of the value (ins) in the array (arr). + * [wTools._lookUpAct() ]{@link wTools._lookUpAct}. + * If (index) is equal to the one, and call callback function(comparator( ins, arr[ index ]) + * returns a value that is not equal to the zero (i.e the array (arr) doesn't contain the value (ins)), it adds the value (ins) to the array (arr), and returns true. + * Otherwise, it returns false. + * + * @see {@link wTools._lookUpAct} - See for more information. + * + * @param { longIs } arr - Entity to check. + * @param { Number } ins - Element to locate in the array. + * @param { wTools~compareCallback } [ comparator = function( a, b ) { return a - b } ] comparator - A callback function. + * + * @example + * // returns false + * wTools.sorted.addOnce( [ 1, 2, 3, 4, 5 ], 5, function( a, b ) { return a - b } ); // => [ 1, 2, 3, 4, 5 ] + * + * @example + * // returns true + * wTools.sorted.addOnce( [ 1, 2, 3, 4, 5 ], 55, function( a, b ) { return a - b } ); // => [ 1, 2, 3, 4, 5, 55 ] + * + * @returns { Boolean } Returns true, if a value (ins) was added to an array (arr). + * Otherwise, it returns false. + * @function addOnce + * @throws { Error } Will throw an Error if (arguments.length) is less than two or more than three. + * @throws { Error } Will throw an Error if (arr) is not an array-like. + * @namespace Tools.sorted + */ + +function addOnce( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + comparator = _._comparatorFromEvaluator( comparator ); + let l = arr.length; + let index = _.sorted._lookUpAct( arr, ins, comparator, 0, l ); + + let add = index === l || comparator( ins, arr[ index ] ) !== 0; + + if( add ) + arr.splice( index, 0, ins ); + + return add; +} + +// + +/** + * The wTools.sorted.add() method adds the value (ins) to the array (arr), no matter whether it has there or hasn't, + * and returns the new added or the updated index. + * + * It calls the method (_.sorted._lookUpAct( arr, ins, comparator, 0, arr.length - 1 )), + * that returns the index of the value (ins) in the array (arr). + * [wTools._lookUpAct() ]{@link wTools._lookUpAct}. + * If value (ins) has in the array (arr), it adds (ins) to that found index and offsets the old values in the (arr). + * Otherwise, it adds the new index. + * + * @see {@link wTools._lookUpAct} - See for more information. + * + * @param { longIs } arr - Entity to check. + * @param { Number } ins - Element to locate in the array. + * @param { wTools~compareCallback } [ comparator = function( a, b ) { return a - b } ] comparator - A callback function. + * + * @example + * // returns 5 + * wTools.sorted.add( [ 1, 2, 3, 4, 5 ], 5, function( a, b ) { return a - b } ); // => [ 1, 2, 3, 4, 5, 5 ] + * + * @example + * // returns 4 + * wTools.sorted.add( [ 1, 2, 3, 4 ], 2, function( a, b ) { return a - b } ); // => [ 1, 2, 2, 3, 4 ] + * + * @returns { Number } Returns the new added or the updated index. + * @function add + * @throws { Error } Will throw an Error if (arguments.length) is less than two or more than three. + * @throws { Error } Will throw an Error if (arr) is not an array-like. + * @namespace Tools.sorted + */ + +function add( arr, ins, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + + comparator = _._comparatorFromEvaluator( comparator ); + let l = arr.length; + let index = _.sorted._lookUpAct( arr, ins, comparator, 0, l ); + + arr.splice( index, 0, ins ); + + return index; +} + +// + +function addLeft( arr, ins, comparator ) +{ + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + comparator = _._comparatorFromEvaluator( comparator ); + let index = _.sorted.leftMostAtLeastIndex( arr, ins, comparator ); + arr.splice( index, 0, ins ); + return index; +} + +// + +function addRight( arr, ins, comparator ) +{ + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( arr ), 'Expect a Long' ); + comparator = _._comparatorFromEvaluator( comparator ); + let index = _.sorted.rightMostAtMostIndex( arr, ins, comparator ); + arr.splice( index+1, 0, ins ); + return index; +} + +// + +/** + * The wTools.sorted.addArray() method returns the sum of the added indexes from an array (src) to an array (dst). + * + * It creates variable (result = 0), iterates over an array (src), + * adds to the (result +=) each call the function( _.sorted.add( dst, src[ s ], comparator ) ) + * that returns the new added or the updated index. + * + * @see {@link wTools_.sorted.add} - See for more information. + * + * @param { longIs } dst - Entity to check. + * @param { longIs } src - Entity to check. + * @param { wTools~compareCallback } [ comparator = function( a, b ) { return a - b } ] comparator - A callback function. + * + * @example + * // returns 19 + * _.sorted.addArray( [ 1, 2, 3, 4, 5 ], [ 6, 7, 8, 2 ], function( a, b ) { return a - b } ); // => [ 1, 2, 2, 3, 4, 5, 6, 7, 8 ] + * + * @example + * // returns 3 + * _.sorted.addArray( [ ], [ 1, 2, 3 ], function( a, b ) { return a - b } ); // => [ 1, 2, 3 ] + * + * @returns { Number } Returns the sum of the added indexes from an array (src) to an array (dst). + * @function addArray + * @throws { Error } Will throw an Error if (arguments.length) is less than two or more than three. + * @throws { Error } Will throw an Error if (dst and src) are not an array-like. + * @namespace Tools.sorted + */ + +function addArray( dst, src, comparator ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + _.assert( _.longIs( dst ) && _.longIs( src ) ); + + let result = 0; + comparator = _._comparatorFromEvaluator( comparator ); + + for( let s = 0 ; s < src.length ; s++ ) + result += this.add( dst, src[ s ], comparator ); + + return result; +} + +// -- +// declare +// -- + +let Proto = +{ + + // array sorted + + _lookUpAct, + + lookUpIndex, + lookUpValue, + lookUp, + + lookUpClosestIndex, + lookUpClosestValue, + lookUpClosest, + + lookUpInterval, + lookUpIntervalNarrowest, /* experimental */ + lookUpIntervalNarrowestOld, /* experimental */ + lookUpIntervalHaving, + lookUpIntervalEmbracingAtLeast, /* experimental */ + lookUpIntervalEmbracingAtLeastOld, /* experimental */ + + _leftMostAtLeastIndex, + leftMostAtLeastIndex, + leftMostAtLeastValue, + leftMostAtLeast, + + _leftMostAtMostIndex, + leftMostAtMostIndex, + leftMostAtMostValue, + leftMostAtMost, + + _rightMostAtLeastIndex, + rightMostAtLeastIndex, + rightMostAtLeastValue, + rightMostAtLeast, + + _rightMostAtMostIndex, + rightMostAtMostIndex, + rightMostAtMostValue, + rightMostAtMost, + + // closestIndex, + // closestValue, + // closest, + + remove, + add, + addLeft, + addRight, + addOnce, + addArray, + +} + +/* _.props.extend */Object.assign( _.sorted, Proto ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _.sorted; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/warraysorted/proto/wtools/abase/l4/ArraySorted.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/warraysorted/proto/wtools/abase/l4' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ArraySorted_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ArraySorted_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/warraysparse/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/warraysparse/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file warraysparse */ ( function warraysparse() { function warraysparse_naked() { +module.exports = require( '../wtools/abase/l4/ArraySparse.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wArraySparse', 'warraysparse' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/warraysparse/proto/node_modules/warraysparse' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/warraysparse/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, warraysparse_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file warraysparse */ })(); + +/* */ /* begin of file ArraySparse_s */ ( function ArraySparse_s() { function ArraySparse_s_naked() { ( function _ArraySparse_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to operate effectively sparse array. A sparse array is an vector of intervals which split number space into two subsets, internal and external. ArraySparse leverage iterating, inverting, minimizing and other operations on a sparse array. Use the module to increase memory efficiency of your algorithms. + @module Tools/base/ArraySparse +*/ + +/** + * */ + +/** + * Collection of cross-platform routines to operate effectively sparse array. + @namespace wTools.sparse + @extends Tools + @module Tools/base/ArraySparse +*/ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + +} + +// + +const _ = _global_.wTools; +const _global = _global_; +_.sparse = _.sparse || Object.create( null ); + +const _ArraySlice = Array.prototype.slice; +const _FunctionBind = Function.prototype.bind; +const _ObjectToString = Object.prototype.toString; +const _ObjectHasOwnProperty = Object.hasOwnProperty; + +const _longSlice = _.longSlice; + +// -- +// sparse +// -- + +/** + * @summary Checks if current entity is a sparse array. + * + * @param {*} sparse Entity to check + * + * @example + * _.sparse.is( {} ) // false + * + * @example + * _.sparse.is( [ 1, 2, 3, 4, 5 ] ) // false + * + * @example + * _.sparse.is( [ 1, 2, 3, 4 ] ) // true + * + * @returns { Number } Returns true if entity( sparse ) is a sparse array, otherwise false. + * @function is + * @namespace Tools.sparse + */ + +function is( sparse ) +{ + _.assert( arguments.length === 1 ); + + if( !_.longIs( sparse ) ) + return false; + + if( sparse.length % 2 !== 0 ) + return false; + + return true; +} + +// + +/** + * @summary Calls onEach routine for each range + * @description + * Arguments list of onEach routine: + * * range - current range + * * s - index of current range + * * sparse - source sparse array + * @param {Array} sparse Source sparse array + * @param {Function} onEach Routine to call for each range + * + * @example + * _.sparse.eachRange( [ 1, 2, 3, 4 ], ( range ) => + * { + * console.log( range ) + * }) + * //[ 1, 2 ] + * //[ 3, 4 ] + * + * @function eachRange + * @throws {Error} If ( sparse ) is not a sparse array. + * @namespace Tools.sparse + */ + +function eachRange( sparse, onEach ) +{ + + _.assert( arguments.length === 2 ); + _.assert( _.sparse.is( sparse ) ); + + let index = 0; + for( let s = 0, sl = sparse.length / 2 ; s < sl ; s++ ) + { + let range = [ sparse[ s*2 + 0 ], sparse[ s*2 + 1 ] ]; + onEach( range, s, sparse ); + } + +} + +// + +/** + * @summary Calls onEach routine for all elements of each range + * @description + * Arguments list of onEach routine: + * * value - current element from range + * * index - global index of current element + * * range current range + * + * @param {Array} sparse Source sparse array + * @param {Function} onEach Routine to call for each range + * + * @example + * _.sparse.eachElement( [ 1, 3, 3, 5 ], ( value, index ) => + * { + * console.log( value, index ) + * }) + * // 1 0 + * // 2 1 + * // 3 2 + * // 4 3 + * + * @function eachElement + * @throws {Error} If ( sparse ) is not a sparse array. + * @namespace Tools.sparse + */ + +function eachElement( sparse, onEach ) +{ + + _.assert( arguments.length === 2 ); + _.assert( _.sparse.is( sparse ) ); + + let index = 0; + for( let s = 0, sl = sparse.length / 2 ; s < sl ; s++ ) + { + let range = [ sparse[ s*2 + 0 ], sparse[ s*2 + 1 ] ]; + for( let key = range[ 0 ], kl = range[ 1 ] ; key < kl ; key++ ) + { + onEach.call( this, key, index, range, 1 ); + index += 1; + } + } + +} + +// + +/** + * @summary Calls onEach routine for all elements inside and outside of each range + * @description + * Arguments list of onEach routine: + * * value - current element from range + * * index - global index of current element + * * range current range + * + * @param {Array} sparse Source sparse array + * @param {Number} length + * @param {Function} onEach Routine to call for each range + * + * @example + * _.sparse.eachElementEvenOutside( [ 2, 3, 3, 6 ], 1, ( value, index, range ) => + * { + * console.log( value, range ) + * }) + * // 0 0 [2, 3] + * // 1 1 [2, 3] + * // 2 2 [2, 3] + * // 3 3 [3, 6] + * // 4 4 [3, 6] + * // 5 5 [3, 6] + * + * @function eachElementEvenOutside + * @throws {Error} If ( sparse ) is not a sparse array. + * @namespace Tools.sparse + */ + +function eachElementEvenOutside( sparse, length, onEach ) +{ + + _.assert( arguments.length === 3 ); + _.assert( _.sparse.is( sparse ) ); + _.assert( _.numberIs( length ) ); + _.assert( _.routineIs( onEach ) ); + + let index = 0; + let was = 0; + for( let s = 0, sl = sparse.length / 2 ; s < sl ; s++ ) + { + let range = [ sparse[ s*2 + 0 ], sparse[ s*2 + 1 ] ]; + + for( let key = was ; key < range[ 0 ] ; key++ ) + { + onEach.call( this, key, index, range, 0 ); + index += 1; + } + + for( let key = range[ 0 ], kl = range[ 1 ] ; key < kl ; key++ ) + { + onEach.call( this, key, index, range, 1 ); + index += 1; + } + + was = range[ 1 ]; + } + + for( let key = was ; key < length ; key++ ) + { + onEach.call( this, key, index, range, 0 ); + index += 1; + } + +} + +// + +/** + * @summary Returns total number of elements from all ranges + * @param {Array} sparse Source sparse array + * + * @example + * _.sparse.elementsTotal( [ 2, 3, 3, 6 ] )//4 + * + * @function elementsTotal + * @throws {Error} If ( sparse ) is not a sparse array. + * @namespace Tools.sparse + */ + +function elementsTotal( sparse ) +{ + let result = 0; + + _.assert( arguments.length === 1 ); + _.assert( _.sparse.is( sparse ) ); + + for( let s = 0, sl = sparse.length / 2 ; s < sl ; s++ ) + { + let range = [ sparse[ s*2 + 0 ], sparse[ s*2 + 1 ] ]; + result += range[ 1 ] - range[ 0 ]; + } + + return result; +} + +// + +/** + * @summary Minimizes provided sparse array into a single range. + * @param {Array} sparse Source sparse array + * + * @example + * _.sparse.minimize( [ 2, 3, 3, 6 ] )//[ 2, 6 ] + * + * @function minimize + * @throws {Error} If ( sparse ) is not a sparse array. + * @namespace Tools.sparse + */ + +function minimize( sparse ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.sparse.is( sparse ) ) + + if( sparse.length === 0 ) + { + // return _.entity.cloneShallow( sparse, 0 ); + return _.long.make( sparse, 0 ); + } + + let l = 0; + + for( let i = 2 ; i < sparse.length ; i += 2 ) + { + + let e1 = sparse[ i-1 ]; + let b2 = sparse[ i+0 ]; + + if( e1 !== b2 ) + l += 2; + + } + + l += 2; + + // let result = _.entity.cloneShallow( sparse, l ); + let result = _.long.make( sparse, l ); + let b = sparse[ 0 ]; + let e = sparse[ 1 ]; + let r = 0; + + /* */ + + for( let i = 2 ; i < sparse.length ; i += 2 ) + { + + let e1 = sparse[ i-1 ]; + let b2 = sparse[ i+0 ]; + + if( e1 === b2 ) + { + e = sparse[ i+1 ]; + } + else + { + result[ r+0 ] = b; + result[ r+1 ] = e; + b = b2; + e = sparse[ i+1 ]; + r += 2; + } + // if( e1 !== b2 ) + // { + // result[ r+0 ] = b; + // result[ r+1 ] = e; + // b = b2; + // e = sparse[ i+1 ]; + // r += 2; + // } + // else + // { + // e = sparse[ i+1 ]; + // } + + } + + /* */ + + result[ r+0 ] = b; + result[ r+1 ] = e; + r += 2; + + _.assert( r === l ); + + return result; +} + +// + +/** + * @function invertFinite + * @throws {Error} If ( sparse ) is not a sparse array. + * @namespace Tools.sparse + */ + +function invertFinite( sparse ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.sparse.is( sparse ) ) + + if( !sparse.length ) + // return _.entity.cloneShallow( sparse, 0 ); + return _.long.make( sparse, 0 ); + + if( sparse.length === 2 && sparse[ 0 ] === sparse[ 1 ] ) + return _.entity.make( sparse ); + + let needPre = 0; + let needPost = 0; + + if( sparse.length >= 2 ) + { + needPre = sparse[ 0 ] === sparse[ 1 ] ? 0 : 1; + needPost = sparse[ sparse.length-2 ] === sparse[ sparse.length-1 ] ? 0 : 1; + } + + let l = sparse.length + needPre*2 + needPost*2 - 2; + // let result = _.entity.cloneShallow( sparse, l ); + let result = _.long.make( sparse, l ); + let r = 0; + + _.assert( l % 2 === 0 ); + + if( needPre ) + { + result[ r+0 ] = sparse[ 0 ]; + result[ r+1 ] = sparse[ 0 ]; + r += 2; + } + + if( needPost ) + { + result[ result.length-2 ] = sparse[ sparse.length-1 ]; + result[ result.length-1 ] = sparse[ sparse.length-1 ]; + } + + for( let i = 2 ; i < sparse.length ; i += 2 ) + { + let e1 = sparse[ i-1 ]; + let b2 = sparse[ i+0 ]; + + result[ r+0 ] = e1; + result[ r+1 ] = b2; + r += 2; + } + + return result; +} + +// -- +// declare +// -- + +let Proto = +{ + + // sparse + + is, + + eachRange, + eachElement, + eachElementEvenOutside, + elementsTotal, + + minimize, + invertFinite, + +} + +/* _.props.extend */Object.assign( _.sparse, Proto ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _.sparse; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/warraysparse/proto/wtools/abase/l4/ArraySparse.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/warraysparse/proto/wtools/abase/l4' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ArraySparse_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ArraySparse_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wblueprint */ ( function wblueprint() { function wblueprint_naked() { +module.exports = require( '../wtools/abase/l2_blueprint/Include.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wBlueprint', 'wblueprint' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/node_modules/wblueprint' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wblueprint_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wblueprint */ })(); + +/* */ /* begin of file Include_s */ ( function Include_s() { function Include_s_naked() { ( function _Include_s_( ) +{ + +'use strict'; + +/** + * Classes defining tool on steroids. make possible multiple inheritances, removing fields in descendants, defining the schema of structure, typeless objects, generating optimal code for definition, and many cool things alternatives cant do. + @module Tools/base/Blueprint +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../node_modules/Tools' ); + + require( './l1/Class.s' ); + require( './l1/Property.s' ); + require( './l1/PropertyTransformers.s' ); + require( './l1/Proto.s' ); + + require( './l2/Accessor.s' ); + require( './l2/Definition.s' ); + require( './l2/Types.s' ); + + require( './l3/Blueprint.s' ); + require( './l3/Construction.s' ); + require( './l3/Definitions.s' ); + require( './l3/Traits.s' ); + + module[ 'exports' ] = wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/Include.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Include_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Include_s */ })(); + +/* */ /* begin of file Class_s */ ( function Class_s() { function Class_s_naked() { ( function _Class_s_() +{ + +'use strict'; + +const Self = _global_.wTools; +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +/** + * @namespace Tools.class + * @module Tools/base/Proto + */ + +// + +function isSubClassOf( subCls, cls ) +{ + + _.assert( _.routineIs( cls ) ); + _.assert( _.routineIs( subCls ) ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( cls === subCls ) + return true; + + return Object.isPrototypeOf.call( cls.prototype, subCls.prototype ); +} + +// -- +// define +// -- + +let ClassExtension = +{ + + isSubClassOf, + +} + +_.class = _.class || Object.create( null ); +/* _.props.extend */Object.assign( _.class, ClassExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l1/Class.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Class_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Class_s */ })(); + +/* */ /* begin of file Property_s */ ( function Property_s() { function Property_s_naked() { ( function _Property_s_() +{ + +'use strict'; + +const Self = _global_.wTools; +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +/** + * @summary Defines hidden property with name( name ) and value( value ) on target object( dstPrototype ). + * + * @description + * Property is defined as not enumarable. + * Also accepts second argument as map of properties. + * If second argument( name ) is a map and third argument( value ) is also defined, then all properties will have value of last arg. + * + * @param {Object} dstPrototype - target object + * @param {String|Object} name - name of property or map of names + * @param {*} value - destination object + * + * @throws {Exception} If number of arguments is not supported. + * @throws {Exception} If dstPrototype is not an Object + * @function conceal + * + * @namespace Tools.property + * @module Tools/base/Proto + */ + +function conceal( dstPrototype, name, value ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( !_.primitiveIs( dstPrototype ), () => 'dstPrototype is needed, but got ' + _.entity.exportStringDiagnosticShallow( dstPrototype ) ); + + if( _.containerIs( name ) ) + { + if( !_.object.isBasic( name ) ) + name = _.indexExtending( name, ( e ) => { return { [ e ] : undefined } } ); + _.each( name, ( v, n ) => + { + if( value === undefined ) + _.props.conceal( dstPrototype, n, v ); + else + _.props.conceal( dstPrototype, n, value ); + }); + return; + } + + if( value === undefined ) + value = dstPrototype[ name ]; + + _.assert( _.strIs( name ), 'name is needed, but got', name ); + + Object.defineProperty( dstPrototype, name, + { + value, + enumerable : false, + writable : true, + configurable : true, + }); + +} + +// + +/** + * Makes constants properties on object by creating new or replacing existing properties. + * @param {object} dstPrototype - prototype of class which will get new constant property. + * @param {object} namesObject - name/value map of constants. + * + * @example + * const Self = ClassName; +function ClassName( o ) { }; + * let Constants = { num : 100 }; + * _.props.constant( Self.prototype, Constants ); + * console.log( Self.prototype ); // returns { num: 100 } + * Self.prototype.num = 1;// error assign to read only property + * + * @function constant + * @throws {exception} If no argument provided. + * @throws {exception} If( dstPrototype ) is not a Object. + * @throws {exception} If( name ) is not a Map. + * @namespace Tools.property + * @module Tools/base/Proto + */ + +function _constant( dstPrototype, name, value ) +{ + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( !_.primitiveIs( dstPrototype ), () => 'dstPrototype is needed, but got ' + _.entity.exportStringDiagnosticShallow( dstPrototype ) ); + + if( _.containerIs( name ) ) + { + if( !_.object.isBasic( name ) ) + name = _.indexExtending( name, ( e ) => { return { [ e ] : undefined } } ); + _.each( name, ( v, n ) => + { + if( value === undefined ) + _.props.constant( dstPrototype, n, v ); + else + _.props.constant( dstPrototype, n, value ); + }); + return; + } + + if( value === undefined ) + value = dstPrototype[ name ]; + + _.assert( _.strIs( name ), 'name is needed, but got', name ); + + Object.defineProperty( dstPrototype, name, + { + value, + enumerable : true, + writable : false, + configurable : false, + }); + +} + +// + +function declare_head( routine, args ) +{ + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + + let o; + + if( args.length === 2 ) + { + o = args[ 1 ]; + _.assert( !o.object ); + o.object = args[ 0 ]; + } + else + { + o = args[ 0 ]; + } + + _.routine.options_( routine, o ); + + if( o.writable === null ) + o.writable = !( o.set === false ); + + _.assert( !_.primitiveIs( o.object ), 'Expects object as argument but got', o.object ); + _.assert( _.strIs( o.name ) || _.symbolIs( o.name ) ); + + return o; +} + +// + +function declare_body( o ) /* xxx : move back to accessor? */ +{ + + _.assert( o.get === false || o.get === null || _.routineIs( o.get ) ); + _.assert( o.set === false || o.set === null || _.routineIs( o.set ) ); + _.assert( _.boolIs( o.enumerable ) ); + _.assert( _.boolIs( o.configurable ) ); + _.assert( _.boolIs( o.writable ) ); + + let o2 = + { + enumerable : !!o.enumerable, + configurable : !!o.configurable, + } + + // if( o.name === 'f1' ) + // debugger; + + if( o.get === false ) + { + if( o.set ) + o2.set = o.set; + o2.get = noGet; + _.assert( o.val === _.nothing ); + } + else if( _.routineIs( o.get ) ) + { + if( o.set ) + o2.set = o.set; + o2.get = o.get; + _.assert( o.val === _.nothing ); + } + else if( o.get === null ) + { + _.assert( o.set === false || o.set === null ); + o2.value = o.val; + o2.writable = !!o.writable; + } + else _.assert( 0 ); + + _.assert( !o.writable || o.set !== false ); + _.assert( o.writable || !o.set ); + + Object.defineProperty( o.object, o.name, o2 ); + + return o2; + + function noGet() + { + throw _.err( 'No getter defined' ); + } + +} + +declare_body.defaults = +{ + object : null, + name : null, + enumerable : true, + configurable : true, + writable : null, + get : null, + set : null, + val : _.nothing, +} + +let declare = _.routine.uniteCloning_replaceByUnite( declare_head, declare_body ); +_.routine.er( declare ); + +// -- +// define +// -- + +let PropertyExtension = +{ + + conceal, + constant : _constant, + declare, /* qqq : cover */ + +} + +_.props = _.props || Object.create( null ); +/* _.props.extend */Object.assign( _.props, PropertyExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l1/Property.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Property_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Property_s */ })(); + +/* */ /* begin of file PropertyTransformers_s */ ( function PropertyTransformers_s() { function PropertyTransformers_s_naked() { ( function _PropertyTransformer_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.props = _.props || Object.create( null ); + +// -- +// +// -- + +function dstNotOwnFromDefinition() +{ + let routine = dstNotOwnFromDefinition; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function dstNotOwnFromDefinition( dstContainer, srcContainer, key ) + { + + if( Object.hasOwnProperty.call( dstContainer, key ) ) + return; + + if( Object.hasOwnProperty.call( dstContainer, Symbol.for( key ) ) ) + return; + + let srcElement = srcContainer[ key ]; + if( _.definitionIs( srcElement ) ) + dstContainer[ key ] = srcElement.toVal( srcElement.val ); + else + dstContainer[ key ] = srcElement; + + } + +} + +dstNotOwnFromDefinition.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// + +function dstNotOwnFromDefinitionStrictlyPrimitive() +{ + let routine = dstNotOwnFromDefinitionStrictlyPrimitive; + routine.identity = { propertyMapper : true, propertyTransformer : true }; + return routine; + + function dstNotOwnFromDefinitionStrictlyPrimitive( dstContainer, srcContainer, key ) + { + + if( Object.hasOwnProperty.call( dstContainer, key ) ) + return; + + if( Object.hasOwnProperty.call( dstContainer, Symbol.for( key ) ) ) + return; + + let srcElement = srcContainer[ key ]; + if( _.definitionIs( srcElement ) ) + { + dstContainer[ key ] = srcElement.toVal( srcElement.val ); + } + else + { + _.assert + ( + !_.consequenceIs( srcElement ) && ( _.primitiveIs( srcElement ) || _.routineIs( srcElement ) ), + () => `${ _.entity.exportStringDiagnosticShallow( dstContainer ) } has non-primitive element "${ key }",` + + ` use _.define.own instead` + ); + dstContainer[ key ] = srcElement; + } + + } + +} + +dstNotOwnFromDefinitionStrictlyPrimitive.identity = { propertyMapper : true, propertyTransformer : true, functor : true }; + +// -- +// tools +// -- + +function mapSupplementOwnFromDefinition( dstMap, srcMap ) +{ + return _.mapExtendConditional( _.props.mapper.dstNotOwnFromDefinition(), ... arguments ); +} + +// + +function mapSupplementOwnFromDefinitionStrictlyPrimitives( dstMap, srcMap ) +{ + return _.mapExtendConditional( _.props.mapper.dstNotOwnFromDefinitionStrictlyPrimitive(), ... arguments ); +} + +// -- +// extension +// -- + +let Transformers = +{ + + dstNotOwnFromDefinition, + dstNotOwnFromDefinitionStrictlyPrimitive, + +} + +_.props.transformersRegister( Transformers ); + +// + +let Extension = +{ + + mapSupplementOwnFromDefinition, + mapSupplementOwnFromDefinitionStrictlyPrimitives, + +} + +_.props.extend( _, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l1/PropertyTransformers.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, PropertyTransformers_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file PropertyTransformers_s */ })(); + +/* */ /* begin of file Proto_s */ ( function Proto_s() { function Proto_s_naked() { ( function _Proto_s_() +{ + +'use strict'; + +const Self = _global_.wTools; +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// /** +// * @namespace Tools.prototype +// * @module Tools/base/Proto +// */ +// +// function _of( object ) +// { +// return Object.getPrototypeOf( object ); +// } +// +// // +// +// /** +// * Iterate through prototypes. +// * @param {object} proto - prototype +// * @function each +// * @namespace Tools.prototype +// */ +// +// function each( proto, onEach ) +// { +// let result = []; +// +// _.assert( _.routineIs( onEach ) || !onEach ); +// _.assert( !_.primitiveIs( proto ) || proto === null ); +// _.assert( arguments.length === 1 || arguments.length === 2 ); +// +// while( proto ) +// { +// if( onEach ) +// onEach.call( this, proto ); +// result.push( proto ); +// proto = Object.getPrototypeOf( proto ); +// } +// +// return result; +// } + +// // +// +// /** +// * Does srcProto has insProto as prototype. +// * @param {object} srcProto - proto stack to investigate. +// * @param {object} insProto - proto to look for. +// * @function hasPrototype +// * @namespace Tools.prototype +// */ +// +// function hasPrototype( srcProto, insProto ) +// { +// +// while( srcProto !== null ) +// { +// if( srcProto === insProto ) +// return true; +// srcProto = Object.getPrototypeOf( srcProto ); +// } +// +// return false; +// } +// +// // +// +// /** +// * Return proto owning names. +// * @param {object} srcPrototype - src object to investigate proto stack. +// * @function havingProperty +// * @namespace Tools.prototype +// */ +// +// function havingProperty( srcPrototype, name ) /* yyy qqq : names could be only string */ +// { +// +// _.assert( !_.primitiveIs( srcPrototype ) ); +// _.assert( _.strIs( name ) ); +// +// do +// { +// let has = true; +// if( !Object.hasOwnProperty.call( srcPrototype, name ) ) +// has = false; +// if( has ) +// return srcPrototype; +// +// srcPrototype = Object.getPrototypeOf( srcPrototype ); +// } +// while( srcPrototype !== Object.prototype && srcPrototype ); +// +// return null; +// } + +// { +// names = _nameFielded( names ); +// _.assert( _.object.isBasic( srcPrototype ) ); +// +// do +// { +// let has = true; +// for( let n in names ) +// if( !Object.hasOwnProperty.call( srcPrototype, n ) ) +// { +// has = false; +// break; +// } +// if( has ) +// return srcPrototype; +// +// srcPrototype = Object.getPrototypeOf( srcPrototype ); +// } +// while( srcPrototype !== Object.prototype && srcPrototype ); +// +// return null; +// } + +// + +function isSubPrototypeOf( sub, parent ) +{ + + _.assert( !!parent ); + _.assert( !!sub ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( parent === sub ) + return true; + + return Object.isPrototypeOf.call( parent, sub ); +} + +// + +function _ofStandardEntity( src ) +{ + if( src === Object.prototype ) + return true; + return false; +} + +// // +// +// function propertyDescriptorActiveGet( object, name ) +// { +// let result = Object.create( null ); +// // yyy +// // result.object = null; +// // result.descriptor = null; +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// _.assert( !!object, 'No object' ); +// +// do +// { +// let descriptor = Object.getOwnPropertyDescriptor( object, name ); +// if( descriptor && !( 'value' in descriptor ) ) +// { +// result.descriptor = descriptor; +// result.object = object; +// return result; +// } +// object = Object.getPrototypeOf( object ); +// } +// while( object ); +// +// return result; +// } +// +// // +// +// function propertyDescriptorGet( object, name ) +// { +// let result = Object.create( null ); +// // yyy +// // result.object = null; +// // result.descriptor = null; +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// +// do +// { +// let descriptor = Object.getOwnPropertyDescriptor( object, name ); +// if( descriptor ) +// { +// result.descriptor = descriptor; +// result.object = object; +// return result; +// } +// object = Object.getPrototypeOf( object ); +// } +// while( object ); +// +// return result; +// } + +// -- +// define +// -- + +let PrototypeExtension = +{ + + // of : _of, + // each, + + // havingProperty, + // hasPrototype, + + isSubPrototypeOf, /* xxx : remove? */ + _ofStandardEntity, + + // propertyDescriptorActiveGet, /* qqq : cover please */ + // propertyDescriptorGet, /* qqq : cover please */ + +} + +_.prototype = _.prototype || Object.create( null ); +/* _.props.extend */Object.assign( _.prototype, PrototypeExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l1/Proto.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Proto_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Proto_s */ })(); + +/* */ /* begin of file Accessor_s */ ( function Accessor_s() { function Accessor_s_naked() { ( function _Accessor_s_() +{ + +'use strict'; + +const Self = _global_.wTools; +const _global = _global_; +const _ = _global_.wTools; + +/** + * @summary Collection of routines for declaring accessors + * @namespace wTools.accessor + * @extends Tools + * @module Tools/base/Proto + */ + +// -- +// fields +// -- + +/** + * Accessor defaults + * @typedef {Object} DeclarationOptions + * @property {Boolean} [ strict=1 ] + * @property {Boolean} [ preservingValue=1 ] + * @property {Boolean} [ prime=1 ] + * @property {String} [ combining=null ] + * @property {Boolean} [ writable=true ] + * @property {Boolean} [ readOnlyProduct=0 ] + * @property {Boolean} [ enumerable=1 ] + * @property {Boolean} [ configurable=0 ] + * @property {Function} [ getter=null ] + * @property {Function} [ graber=null ] + * @property {Function} [ setter=null ] + * @property {Function} [ suite=null ] + * @namespace Tools.accessor + **/ + +let Combining = [ 'rewrite', 'supplement', 'apppend', 'prepend' ]; +let StoringStrategy = [ 'symbol', 'underscore' ]; +let AmethodTypes = [ 'grab', 'get', 'put', 'set', 'move' ]; + +let AmethodTypesMap = +{ + grab : null, + get : null, + put : null, + set : null, + move : null, +} + +let DeclarationSpecialDefaults = +{ + // name : null, + object : null, + methods : null, + needed : null, + normalizedAsuite : null, +} + +let DeclarationOptions = +{ + + name : null, + val : _.nothing, + suite : null, + + preservingValue : null, + prime : null, + combining : null, + addingMethods : null, + enumerable : null, + configurable : null, + writable : null, + storingStrategy : null, + storageIniting : null, + valueGetting : null, + valueSetting : null, + + strict : true, /* zzz : deprecate */ + +} + +let DeclarationDefaults = +{ + + name : null, + val : _.nothing, + suite : null, + + preservingValue : true, + prime : null, + combining : null, + addingMethods : false, + enumerable : true, + configurable : true, + writable : null, + storingStrategy : 'symbol', + storageIniting : true, + valueGetting : true, + valueSetting : true, + + strict : true, + +} + +let DeclarationMultipleToSingleOptions = +{ + ... AmethodTypesMap, + ... DeclarationOptions, + methods : null, +} + +// -- +// getter / setter generator +// -- + +function _propertyGetterSetterNames( propertyName ) +{ + let result = Object.create( null ); + + _.assert( arguments.length === 1 ); + _.assert( _.strIs( propertyName ) ); + + result.grab = '_' + propertyName + 'Grab'; + result.get = '_' + propertyName + 'Get'; + result.put = '_' + propertyName + 'Put'; + result.set = '_' + propertyName + 'Set'; + result.move = '_' + propertyName + 'Move'; + + /* zzz : use it? */ + + return result; +} + +// + +function _normalizedAsuiteForm_head( routine, args ) +{ + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 ); + let o = _.routine.options_( routine, args ); + return o; +} + +function _normalizedAsuiteForm_body( o ) +{ + + _.assert( arguments.length === 1 ); + _.assert( o.methods === null || !_.primitiveIs( o.methods ) ); + _.assert( _.strIs( o.name ) || _.symbolIs( o.name ) ); + _.assert( _.mapIs( o.normalizedAsuite ) ); + _.assert( o.writable === null || _.boolIs( o.writable ) ); + _.map.assertHasOnly( o.normalizedAsuite, _.accessor.AmethodTypesMap ); + _.routine.assertOptions( _normalizedAsuiteForm_body, o ); + + let propName; + if( _.symbolIs( o.name ) ) + { + propName = Symbol.keyFor( o.name ); + } + else + { + propName = o.name; + } + + if( o.suite ) + _.map.assertHasOnly( o.suite, _.accessor.AmethodTypes ); + + // for( let k in o.normalizedAsuite, _.accessor.AmethodTypesMap ) + for( let k in _.accessor.AmethodTypesMap ) + methodNormalize( k ); + + _.assert( o.writable !== false || !o.normalizedAsuite.set ); + + /* grab */ + + if( o.normalizedAsuite.grab === null || o.normalizedAsuite.grab === true ) + { + if( o.normalizedAsuite.move ) + o.normalizedAsuite.grab = _.accessor._amethodFromMove( propName, 'grab', o.normalizedAsuite.move ); + else if( _.routineIs( o.normalizedAsuite.get ) ) + o.normalizedAsuite.grab = o.normalizedAsuite.get; + else + o.normalizedAsuite.grab = _.accessor._amethodFunctor( propName, 'grab', o.storingStrategy ); + } + + /* get */ + + if( o.normalizedAsuite.get === null || o.normalizedAsuite.get === true ) + { + if( o.normalizedAsuite.move ) + o.normalizedAsuite.get = _.accessor._amethodFromMove( propName, 'get', o.normalizedAsuite.move ); + else if( _.routineIs( o.normalizedAsuite.grab ) ) + o.normalizedAsuite.get = o.normalizedAsuite.grab; + else + o.normalizedAsuite.get = _.accessor._amethodFunctor( propName, 'get', o.storingStrategy ); + } + + /* put */ + + if( o.normalizedAsuite.put === null || o.normalizedAsuite.put === true ) + { + if( o.normalizedAsuite.move ) + o.normalizedAsuite.put = _.accessor._amethodFromMove( propName, 'put', o.normalizedAsuite.move ); + else if( _.routineIs( o.normalizedAsuite.set ) ) + o.normalizedAsuite.put = o.normalizedAsuite.set; + else + o.normalizedAsuite.put = _.accessor._amethodFunctor( propName, 'put', o.storingStrategy ); + } + + /* set */ + + if( o.normalizedAsuite.set === null || o.normalizedAsuite.set === true ) + { + if( o.writable === false ) + { + _.assert( o.normalizedAsuite.set === null ); + o.normalizedAsuite.set = false; + } + else if( o.normalizedAsuite.move ) + o.normalizedAsuite.set = _.accessor._amethodFromMove( propName, 'set', o.normalizedAsuite.move ); + else if( _.routineIs( o.normalizedAsuite.put ) ) + o.normalizedAsuite.set = o.normalizedAsuite.put; + else if( o.normalizedAsuite.put !== false || o.normalizedAsuite.set ) + o.normalizedAsuite.set = _.accessor._amethodFunctor( propName, 'set', o.storingStrategy ); + else + o.normalizedAsuite.set = false; + } + + /* move */ + + if( o.normalizedAsuite.move === true ) + { + o.normalizedAsuite.move = function move( it ) + { + _.assert( 0, 'not tested' ); /* zzz */ + return it.src; + } + } + else if( !o.normalizedAsuite.move ) + { + o.normalizedAsuite.move = false; + _.assert( o.normalizedAsuite.move === false ); + } + + // /* readOnlyProduct */ + // + // if( o.readOnlyProduct && o.normalizedAsuite.get ) + // { + // let get = o.normalizedAsuite.get; + // o.normalizedAsuite.get = function get() + // { + // debugger; + // let o.normalizedAsuite = get.apply( this, arguments ); + // if( !_.primitiveIs( o.normalizedAsuite ) ) + // o.normalizedAsuite = _.proxyReadOnly( o.normalizedAsuite ); + // return o.normalizedAsuite; + // } + // } + + /* validation */ + + if( Config.debug ) + { + for( let k in AmethodTypesMap ) + _.assert + ( + _.definitionIs( o.normalizedAsuite[ k ] ) || _.routineIs( o.normalizedAsuite[ k ] ) || o.normalizedAsuite[ k ] === false, + () => `Field "${propName}" is not read only, but setter not found ${_.entity.exportStringDiagnosticShallow( o.methods )}` + ); + } + + return o.normalizedAsuite; + + /* */ + + function methodNormalize( name ) + { + let capitalName = _.strCapitalize( name ); + _.assert + ( + o.normalizedAsuite[ name ] === null + || _.boolLike( o.normalizedAsuite[ name ] ) + || _.routineIs( o.normalizedAsuite[ name ] ) + || _.definitionIs( o.normalizedAsuite[ name ] ) + ); + + if( o.suite && _.boolLikeFalse( o.suite[ name ] ) ) + { + _.assert( !o.normalizedAsuite[ name ] ); + o.normalizedAsuite[ name ] = false; + o.suite[ name ] = false; + } + else if( _.boolLikeFalse( o.normalizedAsuite[ name ] ) ) + { + o.normalizedAsuite[ name ] = false; + } + else if( _.boolLikeTrue( o.normalizedAsuite[ name ] ) ) + { + o.normalizedAsuite[ name ] = true; + } + + if( o.normalizedAsuite[ name ] === null || o.normalizedAsuite[ name ] === true ) + { + if( _.routineIs( o.normalizedAsuite[ name ] ) || _.definitionIs( o.normalizedAsuite[ name ] ) ) + o.normalizedAsuite[ name ] = o.normalizedAsuite[ name ]; + else if( o.suite && ( _.routineIs( o.suite[ name ] ) || _.definitionIs( o.suite[ name ] ) ) ) + o.normalizedAsuite[ name ] = o.suite[ name ]; + else if( o.methods && o.methods[ '' + propName + capitalName ] ) + o.normalizedAsuite[ name ] = o.methods[ propName + capitalName ]; + else if( o.methods && o.methods[ '_' + propName + capitalName ] ) + o.normalizedAsuite[ name ] = o.methods[ '_' + propName + capitalName ]; + } + } + + /* */ + +} + +_normalizedAsuiteForm_body.defaults = +{ + suite : null, + normalizedAsuite : null, + methods : null, + writable : null, + storingStrategy : 'symbol', + name : null, +} + +let _normalizedAsuiteForm = _.routine.uniteCloning_replaceByUnite( _normalizedAsuiteForm_head, _normalizedAsuiteForm_body ); + +// + +function _normalizedAsuiteUnfunct( o ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.mapIs( o.normalizedAsuite ) ); + _.routine.assertOptions( _normalizedAsuiteUnfunct, arguments ); + + for( let mname in _.accessor.AmethodTypesMap ) + resultUnfunct( mname ); + + return o.normalizedAsuite; + + /* */ + + function resultUnfunct( kind ) + { + _.assert( _.primitiveIs( kind ) ); + if( !o.normalizedAsuite[ kind ] ) + return; + let amethod = o.normalizedAsuite[ kind ]; + let r = _.accessor._amethodUnfunct + ({ + amethod, + kind, + accessor : o.accessor, + withDefinition : o.withDefinition, + withFunctor : o.withFunctor, + }); + o.normalizedAsuite[ kind ] = r; + return r; + } + +} + +var defaults = _normalizedAsuiteUnfunct.defaults = +{ + accessor : null, + normalizedAsuite : null, + withDefinition : false, + withFunctor : true, +} + +// + +function _amethodUnfunct( o ) +{ + + _.assert( arguments.length === 1 ); + if( !o.amethod ) + return o.amethod; + + _.assert( !_.routineIs( o.amethod ) || !o.amethod.identity || _.mapIs( o.amethod.identity ) ); + + if( o.withFunctor && o.amethod.identity && o.amethod.identity.functor ) + { + functorUnfunct(); + if( o.kind === 'suite' && o.withDefinition && _.definitionIs( o.amethod ) ) + definitionUnfunct(); + } + else if( o.kind === 'suite' && o.withDefinition && _.definitionIs( o.amethod ) ) + { + definitionUnfunct(); + if( o.withFunctor && o.amethod.identity && o.amethod.identity.functor ) + functorUnfunct(); + } + + _.assert( o.amethod !== undefined ); + return o.amethod; + + function functorUnfunct() + { + let o2 = Object.create( null ); + if( o.amethod.defaults ) + { + if( o.amethod.defaults.propName !== undefined ) + o2.propName = o.accessor.name; + if( o.amethod.defaults.accessor !== undefined ) + o2.accessor = o.accessor; + if( o.amethod.defaults.accessorKind !== undefined ) + o2.accessorKind = o.kind; + } + o.amethod = o.amethod( o2 ); + } + + function definitionUnfunct() + { + _.assert( _.routineIs( o.amethod.asAccessorSuite ) ); + o.amethod = o.amethod.asAccessorSuite( o ); + _.assert( o.amethod !== undefined ); + } + +} + +_amethodUnfunct.defaults = +{ + amethod : null, + accessor : null, + kind : null, + withDefinition : false, + withFunctor : true, +} + +// + +function _objectMethodsNamesGet( o ) +{ + + _.routine.options_( _objectMethodsNamesGet, o ); + + if( o.anames === null ) + o.anames = Object.create( null ); + + _.assert( arguments.length === 1 ); + _.assert( _.mapIs( o.normalizedAsuite ) ); + _.assert( _.strIs( o.name ) ); + _.assert( !!o.object ); + + for( let t = 0 ; t < _.accessor.AmethodTypes.length ; t++ ) + { + let type = _.accessor.AmethodTypes[ t ]; + if( o.normalizedAsuite[ type ] && !o.anames[ type ] ) + { + let type2 = _.strCapitalize( type ); + if( o.object[ o.name + type2 ] === o.normalizedAsuite[ type ] ) + o.anames[ type ] = o.name + type2; + else if( o.object[ '_' + o.name + type2 ] === o.normalizedAsuite[ type ] ) + o.anames[ type ] = '_' + o.name + type2; + else + o.anames[ type ] = o.name + type2; + } + } + + return o.anames; +} + +_objectMethodsNamesGet.defaults = +{ + object : null, + normalizedAsuite : null, + anames : null, + name : null, +} + +// + +function _objectMethodsGet( object, propertyName ) +{ + let result = Object.create( null ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.object.isBasic( object ) ); + _.assert( _.strIs( propertyName ) ); + + result.grabName = object[ propertyName + 'Grab' ] ? propertyName + 'Grab' : '_' + propertyName + 'Grab'; + result.getName = object[ propertyName + 'Get' ] ? propertyName + 'Get' : '_' + propertyName + 'Get'; + result.putName = object[ propertyName + 'Put' ] ? propertyName + 'Put' : '_' + propertyName + 'Put'; + result.setName = object[ propertyName + 'Set' ] ? propertyName + 'Set' : '_' + propertyName + 'Set'; + result.moveName = object[ propertyName + 'Move' ] ? propertyName + 'Move' : '_' + propertyName + 'Move'; + + result.grab = object[ result.grabName ]; + result.get = object[ result.getName ]; + result.set = object[ result.setName ]; + result.put = object[ result.putName ]; + result.move = object[ result.moveName ]; + + return result; +} + +// + +function _objectMethodsValidate( o ) +{ + + if( !Config.debug ) + return true; + + _.assert( _.strIs( o.name ) || _.symbolIs( o.name ) ); + _.assert( !!o.object ); + _.routine.options_( _objectMethodsValidate, o ); + + let name = _.symbolIs( o.name ) ? Symbol.keyFor( o.name ) : o.name; + let AmethodTypes = _.accessor.AmethodTypes; + + for( let t = 0 ; t < AmethodTypes.length ; t++ ) + { + let type = AmethodTypes[ t ]; + if( !o.normalizedAsuite[ type ] ) + { + let name1 = name + _.strCapitalize( type ); + let name2 = '_' + name + _.strCapitalize( type ); + _.assert( !( name1 in o.object ), `Object should not have method ${name1}, if accessor has it disabled` ); + _.assert( !( name2 in o.object ), `Object should not have method ${name2}, if accessor has it disabled` ); + } + } + + return true; +} + +_objectMethodsValidate.defaults = +{ + object : null, + normalizedAsuite : null, + name : null, +} + +// + +function _objectMethodMoveGet( srcInstance, name ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.strIs( name ) ); + + if( !_.instanceIs( srcInstance ) ) + return null; + + if( srcInstance[ name + 'Move' ] ) + return srcInstance[ name + 'Move' ]; + else if( srcInstance[ '_' + name + 'Move' ] ) + return srcInstance[ '_' + name + 'Move' ]; + + return null; +} + +// + +function _declaringIsNeeded( o ) +{ + let prop = _.props.descriptorActiveOf( o.object, o.name ); + if( prop.descriptor ) + { + + _.assert + ( + o.combining === null || _.longHas( _.accessor.Combining, o.combining ) + , () => `Option::combining of property ${o.name}` + + ` supposed to be either any of ${_.accessor.Combining} or null` + + ` but it is ${o.combining}` + ); + _.assert + ( + !!o.combining + , 'Overriding of accessor is not allowed, to allow it set option::combining to rewrite' + ); + _.assert( o.combining === 'rewrite' || o.combining === 'append' || o.combining === 'supplement', 'not implemented' ); + + if( o.combining === 'supplement' ) + return false; + + _.assert + ( + prop.object !== o.object, + () => `Attempt to redefine own accessor "${o.name}" of ${_.entity.exportStringDiagnosticShallow( o.object )}` + ); + + } + return true; +} + +_declaringIsNeeded.defaults = +{ + object : null, + name : null, + combining : null, +} + +// + +function _defaultsApply( o ) +{ + + if( o.prime === null ) + o.prime = !!_.workpiece && _.workpiece.prototypeIsStandard( o.object ); + + for( let k in o ) + { + if( o[ k ] === null && _.accessor.DeclarationDefaults[ k ] !== undefined ) + o[ k ] = _.accessor.DeclarationDefaults[ k ]; + } + + _.assert( _.boolLike( o.prime ) ); + _.assert( _.boolLike( o.configurable ) ); + _.assert( _.boolLike( o.enumerable ) ); + _.assert( _.boolLike( o.addingMethods ) ); + _.assert( _.boolLike( o.preservingValue ) ); + +} + +_defaultsApply.defaults = +{ + ... DeclarationDefaults, +} + +// + +function _methodsNormalize( o ) +{ + + _.assert( arguments.length === 1 ); + + for( let mname in _.accessor.AmethodTypesMap ) + methodNormalize( o, mname ); + + function methodNormalize( o, n1 ) + { + if( _.boolLike( o[ n1 ] ) ) + o[ n1 ] = !!o[ n1 ]; + } + +} + +// + +function _objectInitStorageUnderscore( object ) +{ + _.assert( arguments.length === 1 ); + if( !Object.hasOwnProperty.call( object, '_' ) ) + Object.defineProperty( object, '_', + { + value : Object.create( _.object.isBasic( object._ ) ? object._ : null ), + enumerable : false, + writable : false, + configurable : false, + }); +} + +// + +function methodWithStoringStrategyUnderscore( routine ) +{ + routine.objectInitStorage = _objectInitStorageUnderscore; + return routine; +} + +// + +function _amethodFunctor( propName, amethodType, storingStrategy ) +{ + let fieldSymbol; + + if( storingStrategy === 'symbol' ) + { + fieldSymbol = Symbol.for( propName ); + if( amethodType === 'grab' ) + return grabWithSymbol; + else if( amethodType === 'get' ) + return getWithSymbol; + else if( amethodType === 'put' ) + return putWithSymbol; + else if( amethodType === 'set' ) + return setWithSymbol; + else _.assert( 0 ); + } + else if( storingStrategy === 'underscore' ) + { + if( amethodType === 'grab' ) + return methodWithStoringStrategyUnderscore( grabWithUnderscore ); + else if( amethodType === 'get' ) + return methodWithStoringStrategyUnderscore( getWithUnderscore ); + else if( amethodType === 'put' ) + return methodWithStoringStrategyUnderscore( putWithUnderscore ); + else if( amethodType === 'set' ) + return methodWithStoringStrategyUnderscore( setWithUnderscore ); + else _.assert( 0 ); + } + else _.assert( 0 ); + + /* */ + + function grabWithSymbol() + { + return this[ fieldSymbol ]; + } + + function getWithSymbol() + { + return this[ fieldSymbol ]; + } + + function putWithSymbol( src ) + { + this[ fieldSymbol ] = src; + return src; + } + + function setWithSymbol( src ) + { + this[ fieldSymbol ] = src; + return src; + } + + /* */ + + function grabWithUnderscore() + { + return this._[ propName ]; + } + + function getWithUnderscore() + { + return this._[ propName ]; + } + + function putWithUnderscore( src ) + { + this._[ propName ] = src; + return src; + } + + function setWithUnderscore( src ) + { + this._[ propName ] = src; + return src; + } + + /* */ + +} + +// + +function _amethodFromMove( propName, amethodType, move ) +{ + + if( amethodType === 'grab' ) + return grab; + else if( amethodType === 'get' ) + return get; + else if( amethodType === 'put' ) + return put; + else if( amethodType === 'set' ) + return set; + else _.assert( 0 ); + + /* */ + + function grab() + { + let it = _.accessor._moveItMake + ({ + srcInstance : this, + instanceKey : propName, + accessorKind : 'grab', + }); + move.call( this, it ); + return it.value; + } + + function get() + { + let it = _.accessor._moveItMake + ({ + srcInstance : this, + instanceKey : propName, + accessorKind : 'get', + }); + move.call( this, it ); + return it.value; + } + + function put( src ) + { + let it = _.accessor._moveItMake + ({ + dstInstance : this, + instanceKey : propName, + value : src, + accessorKind : 'put', + }); + move.call( this, it ); + return it.value; + } + + function set( src ) + { + let it = _.accessor._moveItMake + ({ + dstInstance : this, + instanceKey : propName, + value : src, + accessorKind : 'set', + }); + move.call( this, it ); + return it.value; + } + +} + +// + +function _moveItMake( o ) +{ + return _.routine.options_( _moveItMake, arguments ); +} + +_moveItMake.defaults = +{ + dstInstance : null, + srcInstance : null, + instanceKey : null, + srcContainer : null, + dstContainer : null, + containerKey : null, + accessorKind : null, + value : null, +} + +// + +function _objectSetValue( o ) +{ + + _.map.assertHasAll( o, _objectSetValue.defaults ); + + let descriptor = Object.getOwnPropertyDescriptor( o.object, o.name ); + // if( descriptor && descriptor.configurable && descriptor.get == undefined && descriptor.set === undefined ) /* yyy */ + if( descriptor && descriptor.configurable && descriptor.get === undefined && descriptor.set === undefined ) + delete o.object[ o.name ]; + + let val2 = _.escape.right( o.val ); + + if( o.normalizedAsuite.put ) + { + o.normalizedAsuite.put.call( o.object, val2 ); + } + else if( o.normalizedAsuite.set ) + { + o.normalizedAsuite.set.call( o.object, val2 ); + } + else + { + let put = _.accessor._amethodFunctor( o.name, 'put', o.storingStrategy ); + put.call( o.object, val2 ); + } + +} + +_objectSetValue.defaults = +{ + object : null, + normalizedAsuite : null, + storingStrategy : null, + name : null, + val : null, +} + +// + +function _objectAddMethods( o ) +{ + + _.routine.assertOptions( _objectAddMethods, o ); + + for( let n in o.normalizedAsuite ) + { + if( !o.normalizedAsuite[ n ] ) + continue; + let currentVal = o.object[ o.anames[ n ] ]; + _.assert + ( + !Object.hasOwnProperty.call( o.object, o.anames[ n ] ) + || currentVal === o.normalizedAsuite[ n ] + || ( _.routineIs( currentVal ) && currentVal.identity && currentVal.identity.functor ) + || _.definitionIs( currentVal ) + , () => `Object already own property ${o.anames[ n ]}` + ); + Object.defineProperty( o.object, o.anames[ n ], + { + value : o.normalizedAsuite[ n ], + enumerable : false, + writable : true, + configurable : true, + }); + } + +} + +_objectAddMethods.defaults = +{ + object : null, + normalizedAsuite : null, + anames : null, +} + +// + +function _objectInitStorage( object, normalizedAsuite ) +{ + let initers = new Set(); + + _.assert( arguments.length === 2 ); + _.assert( _.mapIs( normalizedAsuite ) ); + + for( let k in normalizedAsuite ) + { + let method = normalizedAsuite[ k ]; + if( !method.objectInitStorage ) + continue; + initers.add( method.objectInitStorage ); + } + + // if( initers.size > 1 ) + // debugger; + + for( let initer of initers ) + { + initer( object ); + } + +} + +// + +/** + * Registers provided accessor. + * Writes accessor's descriptor into accessors map of the prototype ( o.proto ). + * Supports several combining methods: `rewrite`, `supplement`, `append`. + * * Adds diagnostic information to descriptor if running in debug mode. + * @param {Object} o - options map + * @param {String} o.name - accessor's name + * @param {Object} o.proto - target prototype object + * @param {String} o.declaratorName + * @param {Array} o.declaratorArgs + * @param {String} o.declaratorKind + * @param {String} o.combining - combining method + * @private + * @function _register + * @namespace Tools.accessor + */ + +function _register( o ) +{ + + _.routine.options_( _register, arguments ); + _.assert( _.strDefined( o.declaratorName ) ); + _.assert( _.arrayIs( o.declaratorArgs ) ); + + return descriptor; +} + +_register.defaults = +{ + name : null, + proto : null, + declaratorName : null, + declaratorArgs : null, + declaratorKind : null, + combining : 0, +} + +// -- +// declare +// -- + +function suiteMove( dst, src ) +{ + let hasAccessor = dst !== undefined && dst !== null && dst !== false; + + for( let k in _.accessor.AmethodTypesMap ) + if( src[ k ] !== undefined && src[ k ] !== null ) + { + hasAccessor = true + break; + } + + if( hasAccessor ) + { + if( _.mapIs( dst ) ) + { + dst = Object.assign( Object.create( null ), dst ); + } + else + { + _.assert( !_.boolLikeFalse( dst ) ); + dst = Object.create( null ); + } + for( let k in _.accessor.AmethodTypesMap ) + if( src[ k ] !== undefined && src[ k ] !== null ) + dst[ k ] = src[ k ]; + } + + for( let k in _.accessor.AmethodTypesMap ) + if( src[ k ] !== undefined && src[ k ] !== null ) + delete src[ k ]; + + return dst; +} + +// + +function suiteSupplement( dst, src ) +{ + + _.assert( dst === null || _.mapIs( dst ) ); + _.assert( _.mapIs( src ) ); + + dst = dst || Object.create( null ); + + for( let m in _.accessor.AmethodTypesMap ) + { + if( dst[ m ] === null || dst[ m ] === undefined || _.boolLikeTrue( dst[ m ] ) ) + if( _.routineIs( src[ m ] ) || _.boolLikeFalse( src[ m ] ) ) + dst[ m ] = src[ m ]; + } + + return dst; +} + +// + +function suiteNormalize_body( o ) +{ + + _.map.assertHasAll( o, suiteNormalize_body.defaults ); + + /* */ + + _.debugger; + + if( !o.normalizedAsuite ) + { + + o.suite = _.accessor._amethodUnfunct + ({ + amethod : o.suite, + accessor : o, + kind : 'suite', + withDefinition : true, + withFunctor : true, + }); + + o.normalizedAsuite = _.accessor._normalizedAsuiteForm.body + ({ + name : o.name, + methods : o.methods, + suite : o.suite, + writable : o.writable, + storingStrategy : o.storingStrategy, + normalizedAsuite : + { + grab : o.grab, + get : o.get, + put : o.put, + set : o.set, + move : o.move, + }, + }); + + _.accessor._normalizedAsuiteUnfunct + ({ + accessor : o, + normalizedAsuite : o.normalizedAsuite, + withDefinition : false, + withFunctor : true, + }); + + } + + return o; +} + +var defaults = suiteNormalize_body.defaults = +{ + ... AmethodTypesMap, + ... DeclarationSpecialDefaults, + ... DeclarationOptions, +} + +let suiteNormalize = _.routine.uniteCloning_replaceByUnite( declareSingle_head, suiteNormalize_body ); + +// + +function declareSingle_head( routine, args ) +{ + + let o = args[ 0 ]; + if( o.val === null ) + o.val = _.null; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 ); + _.routine.options_( routine, o ); + _.assert( !_.primitiveIs( o.object ), 'Expects object as argument but got', o.object ); + _.assert( _.strIs( o.name ) || _.symbolIs( o.name ) ); + _.assert( _.longHas( [ null, 0, false, 1, true, 'rewrite', 'supplement' ], o.combining ), 'not tested' ); + + if( _.boolLikeTrue( o.combining ) ) + o.combining = 'rewrite'; + + if( _.boolLike( o.writable ) ) + o.writable = !!o.writable; + + if( _.boolLikeTrue( o.suite ) ) + o.suite = Object.create( null ); + + _.map.assertHasAll( o, routine.defaults ); + + _.accessor._methodsNormalize( o ); + _.accessor._defaultsApply( o ); + + _.assert( _.boolIs( o.writable ) || o.writable === null ); + + return o; +} + +function declareSingle_body( o ) +{ + + _.map.assertHasAll( o, declareSingle_body.defaults ); + _.assert( _.boolIs( o.writable ) || o.writable === null ); + _.assert( o.object !== Object, 'Attempt to polute _global_.Object' ); + _.assert( !_.prototype._ofStandardEntity( o.object ), 'Attempt to pollute _global_.Object.prototype' ); + + /* */ + + _.debugger; + o.needed = _.accessor._declaringIsNeeded( o ); + if( !o.needed ) + return false; + + /* */ + + if( !o.normalizedAsuite ) + _.accessor.suiteNormalize( o ); + + if( o.writable === null ) + o.writable = !!o.normalizedAsuite.set; + _.assert( _.boolLike( o.writable ) ); + + let anames; + if( o.prime || o.addingMethods ) + anames = _.accessor._objectMethodsNamesGet + ({ + object : o.object, + normalizedAsuite : o.normalizedAsuite, + name : o.name, + }) + + /* */ + + if( o.prime ) + register(); + + /* addingMethods */ + + if( o.addingMethods ) + _.accessor._objectAddMethods + ({ + object : o.object, + normalizedAsuite : o.normalizedAsuite, + anames, + }); + + /* init storage */ + + if( o.storageIniting ) + _.accessor._objectInitStorage( o.object, o.normalizedAsuite ); + + /* cache value */ + + _.debugger; + if( o.storageIniting && o.valueGetting) + { + + if( _.definitionIs( o.normalizedAsuite.get ) ) + { + if( o.val === _.nothing ) + o.val = _.definition.toVal( o.normalizedAsuite.get ); + o.normalizedAsuite.get = null; + } + + if( o.val === _.nothing ) + if( o.preservingValue && Object.hasOwnProperty.call( o.object, o.name ) ) + o.val = o.object[ o.name ]; + + } + + /* define accessor */ + + let descriptor = _.props.declare.body + ({ + object : o.object, + name : o.name, + enumerable : !!o.enumerable, + configurable : !!o.configurable, + writable : !!o.writable, + get : o.normalizedAsuite.get, + set : o.normalizedAsuite.set, + val : o.normalizedAsuite.get === null ? o.val : _.nothing, + }); + + /* set value */ + + _.debugger; + if( o.storageIniting && o.valueSetting ) + if( o.val !== _.nothing && descriptor.get ) + { + _.accessor._objectSetValue + ({ + object : o.object, + normalizedAsuite : o.normalizedAsuite, + storingStrategy : o.storingStrategy, + name : o.name, + val : o.val, + }); + } + + /* validate */ + + if( Config.debug ) + validate(); + + return o; + + /* - */ + + function validate() + { + _.accessor._objectMethodsValidate({ object : o.object, name : o.name, normalizedAsuite : o.normalizedAsuite }); + } + + /* */ + + function register() + { + + let o2 = _.props.extend( null, o ); + o2.names = o.name; + o2.methods = Object.create( null ); + o2.object = null; + delete o2.name; + delete o2.normalizedAsuite; + + for( let k in o.normalizedAsuite ) + if( o.normalizedAsuite[ k ] ) + o2.methods[ anames[ k ] ] = o.normalizedAsuite[ k ]; + + _.accessor._register + ({ + proto : o.object, + name : o.name, + declaratorName : 'accessor', + declaratorArgs : [ o2 ], + combining : o.combining, + }); + + } + + /* */ + +} + +var defaults = declareSingle_body.defaults = +{ + ... AmethodTypesMap, + ... DeclarationSpecialDefaults, + ... DeclarationOptions, +} + +let declareSingle = _.routine.uniteCloning_replaceByUnite( declareSingle_head, declareSingle_body ); + +// + +/** + * Accessor options + * @typedef {Object} AccessorOptions + * @property {Object} [ object=null ] - source object wich properties will get getter/setter defined. + * @property {Object} [ names=null ] - map that that contains names of fields for wich function defines setter/getter. + * Function uses values( rawName ) of object( o.names ) properties to check if fields of( o.object ) have setter/getter. + * Example : if( rawName ) is 'a', function searchs for '_aSet' or 'aSet' and same for getter. + * @property {Object} [ methods=null ] - object where function searchs for existing setter/getter of property. + * @property {Array} [ message=null ] - setter/getter prints this message when called. + * @property {Boolean} [ strict=true ] - makes object field private if no getter defined but object must have own constructor. + * @property {Boolean} [ enumerable=true ] - sets property descriptor enumerable option. + * @property {Boolean} [ preservingValue=true ] - saves values of existing object properties. + * @property {Boolean} [ prime=true ] + * @property {String} [ combining=null ] + * @property {Boolean} [ writable=true ] - if false function doesn't define setter to property. + * @property {Boolean} [ configurable=false ] + * @property {Function} [ get=null ] + * @property {Function} [ set=null ] + * @property {Function} [ suite=null ] + * + * @namespace Tools.accessor + **/ + +/** + * Defines set/get functions on source object( o.object ) properties if they dont have them. + * If property specified by( o.names ) doesn't exist on source( o.object ) function creates it. + * If ( o.object.constructor.prototype ) has property with getter defined function forbids set/get access + * to object( o.object ) property. Field can be accessed by use of Symbol.for( rawName ) function, + * where( rawName ) is value of property from( o.names ) object. + * + * Can be called in three ways: + * - First by passing all options in one object( o ); + * - Second by passing ( object ) and ( names ) options; + * - Third by passing ( object ), ( names ) and ( message ) option as third parameter. + * + * @param {Object} o - options {@link module:Tools/base/Proto.wTools.accessor~AccessorOptions}. + * + * @example + * const Self = ClassName; +function ClassName( o ) { }; + * _.accessor.declare( Self, { a : 'a' }, 'set/get call' ) + * Self.a = 1; // set/get call + * Self.a; + * // returns + * // set/get call + * // 1 + * + * @throws {exception} If( o.object ) is not a Object. + * @throws {exception} If( o.names ) is not a Object. + * @throws {exception} If( o.methods ) is not a Object. + * @throws {exception} If( o.message ) is not a Array. + * @throws {exception} If( o ) is extented by unknown property. + * @throws {exception} If( o.strict ) is true and object doesn't have own constructor. + * @throws {exception} If( o.writable ) is false and property has own setter. + * @function declare + * @namespace Tools.accessor + */ + +function declareMultiple_head( routine, args ) +{ + let o; + + _.assert( arguments.length === 2 ); + + if( args.length === 1 ) + { + o = args[ 0 ]; + } + else + { + o = Object.create( null ); + o.object = args[ 0 ]; + o.names = args[ 1 ]; + _.assert( args.length >= 2 ); + } + + if( args.length > 2 ) + { + _.assert( o.messages === null || o.messages === undefined ); + o.message = _.longSlice( args, 2 ); + } + + if( _.strIs( o.names ) ) + o.names = { [ o.names ] : o.names } + + _.routine.options_( routine, o ); + + if( _.boolLike( o.writable ) ) + o.writable = !!o.writable; + + _.assert( !_.primitiveIs( o.object ), 'Expects object as argument but got', o.object ); + _.assert( _.object.isBasic( o.names ) || _.arrayIs( o.names ), 'Expects object names as argument but got', o.names ); + + return o; +} + +function declareMultiple_body( o ) +{ + + _.routine.assertOptions( declareMultiple_body, arguments ); + + if( _.argumentsArray.like( o.object ) ) + { + _.each( o.object, ( object ) => + { + let o2 = _.props.extend( null, o ); + o2.object = object; + declareMultiple_body( o2 ); + }); + return o.object; + } + + if( !o.methods ) + o.methods = o.object; + + /* verification */ + + _.assert( !_.primitiveIs( o.methods ) ); + _.assert( !_.primitiveIs( o.object ), () => 'Expects object {-object-}, but got ' + _.entity.exportStringDiagnosticShallow( o.object ) ); + _.assert( _.object.isBasic( o.names ), () => 'Expects object {-names-}, but got ' + _.entity.exportStringDiagnosticShallow( o.names ) ); + + /* */ + + let result = Object.create( null ); + for( let name in o.names ) + result[ name ] = declare( name, o.names[ name ] ); + + let names2 = Object.getOwnPropertySymbols( o.names ); + for( let n = 0 ; n < names2.length ; n++ ) + result[ names2[ n ] ] = declare( names2[ n ], o.names[ names2[ n ] ] ); + + return result; + + /* */ + + function declare( name, extension ) + { + let o2 = Object.assign( Object.create( null ), o ); + + _.assert( !_.routineIs( extension ) || !extension.identity || _.mapIs( extension.identity ) ); + + if( _.mapIs( extension ) ) + { + _.map.assertHasOnly( extension, _.accessor.DeclarationMultipleToSingleOptions ); + _.props.extend( o2, extension ); + _.assert( !!o2.object ); + } + else if( _.definitionIs( extension ) ) + { + o2.suite = extension; + } + else if( _.routineIs( extension ) && extension.identity && extension.identity.functor ) + { + _.props.extend( o2, { suite : extension } ); + } + else _.assert( name === extension, `Unexpected type ${_.entity.strType( extension )}` ); + + o2.name = name; + delete o2.names; + + return _.accessor.declareSingle( o2 ); + // return _.accessor.declareSingle.body( o2 ); + } + +} + +var defaults = declareMultiple_body.defaults = _.props.extend( null, declareSingle.defaults ); +defaults.names = null; +delete defaults.name; + +let declareMultiple = _.routine.uniteCloning_replaceByUnite( declareMultiple_head, declareMultiple_body ); + +// + +/** + * @summary Declares forbid accessor. + * @description + * Forbid accessor throws an Error when user tries to get value of the property. + * @param {Object} o - options {@link module:Tools/base/Proto.wTools.accessor~AccessorOptions}. + * + * @example + * const Self = ClassName; +function ClassName( o ) { }; + * _.accessor.forbid( Self, { a : 'a' } ) + * Self.a; // throw an Error + * + * @function forbid + * @namespace Tools.accessor + */ + +function forbid_body( o ) +{ + + _.routine.assertOptions( forbid_body, arguments ); + + if( !o.methods ) + o.methods = Object.create( null ); + + if( _.argumentsArray.like( o.object ) ) + { + _.each( o.object, ( object ) => + { + let o2 = _.props.extend( null, o ); + o2.object = object; + forbid_body( o2 ); + }); + return o.object; + } + + if( _.object.isBasic( o.names ) ) + o.names = _.props.extend( null, o.names ); + + if( o.prime === null ) + o.prime = !!_.workpiece && _.workpiece.prototypeIsStandard( o.object ); + + /* verification */ + + _.assert( !_.primitiveIs( o.object ), () => 'Expects object {-o.object-} but got ' + _.entity.exportStringDiagnosticShallow( o.object ) ); + _.assert( _.object.isBasic( o.names ) || _.arrayIs( o.names ), () => 'Expects object {-o.names-} as argument but got ' + _.entity.exportStringDiagnosticShallow( o.names ) ); + + /* message */ + + let _constructor = o.object.constructor || null; + _.assert( _.routineIs( _constructor ) || _constructor === null ); + if( !o.protoName ) + o.protoName = ( _constructor ? ( _constructor.name || _constructor._name || '' ) : '' ) + '.'; + if( o.message ) + o.message = _.arrayIs( o.message ) ? o.message.join( ' : ' ) : o.message; + else + o.message = 'is deprecated'; + + /* property */ + + if( _.object.isBasic( o.names ) ) + { + let result = Object.create( null ); + + for( let n in o.names ) + { + let name = o.names[ n ]; + let o2 = _.props.extend( null, o ); + o2.propName = name; + _.assert( n === name, () => 'Key and value should be the same, but ' + _.strQuote( n ) + ' and ' + _.strQuote( name ) + ' are not' ); + let declared = _.accessor._forbidSingle( o2 ); + if( declared ) + result[ name ] = declared; + else + delete o.names[ name ]; + } + + return result; + } + else + { + let result = []; + let namesArray = o.names; + + o.names = Object.create( null ); + for( let n = 0 ; n < namesArray.length ; n++ ) + { + let name = namesArray[ n ]; + let o2 = _.props.extend( null, o ); + o2.propName = name; + let delcared = _.accessor._forbidSingle( o2 ); + if( declared ) + { + o.names[ name ] = declared; + result.push( declared ); + } + } + + return result; + } + +} + +var defaults = forbid_body.defaults = +{ + + ... declareMultiple.body.defaults, + + preservingValue : 0, + enumerable : 0, + combining : 'rewrite', + writable : true, + message : null, + + prime : 0, + strict : 0, + +} + +let forbid = _.routine.uniteCloning_replaceByUnite( declareMultiple_head, forbid_body ); + +// + +function _forbidSingle() +{ + let o = _.routine.options_( _forbidSingle, arguments ); + let messageLine = o.protoName + o.propName + ' : ' + o.message; + + _.assert( _.strIs( o.protoName ) ); + _.assert( _.object.isBasic( o.methods ) ); + + /* */ + + let propertyDescriptor = _.props.descriptorActiveOf( o.object, o.propName ); + if( propertyDescriptor.descriptor ) + { + _.assert( _.strIs( o.combining ), 'forbid : if accessor overided expect ( o.combining ) is', _.accessor.Combining.join() ); + + if( _.routineIs( propertyDescriptor.descriptor.get ) && propertyDescriptor.descriptor.get.name === 'forbidden' ) + { + return false; + } + + } + + /* */ + + if( !Object.isExtensible( o.object ) ) + { + return false; + } + + o.methods = null; + o.suite = Object.create( null ); + o.suite.grab = forbidden; + o.suite.get = forbidden; + o.suite.put = forbidden; + o.suite.set = forbidden; + forbidden.isForbid = true; + + /* */ + + if( o.prime ) + { + + _.assert( 0, 'not tested' ); + let o2 = _.props.extend( null, o ); + o2.names = o.propName; + o2.object = null; + delete o2.protoName; + delete o2.propName; + + _.accessor._register + ({ + proto : o.object, + name : o.propName, + declaratorName : 'forbid', + declaratorArgs : [ o2 ], + combining : o.combining, + }); + + } + + _.assert( !o.strict ); + _.assert( !o.prime ); + + o.strict = 0; + o.prime = 0; + + let o2 = _.mapOnly_( null, o, _.accessor.declare.body.defaults ); + o2.name = o.propName; + delete o2.names; + return _.accessor.declareSingle.body( o2 ); + + /* */ + + function forbidden() + { + throw _.err( messageLine ); + } + +} + +var defaults = _forbidSingle.defaults = +{ + ... forbid.defaults, + propName : null, + protoName : null, +} + +// + +/** + * Checks if source object( object ) has own property( name ) and its forbidden. + * @param {Object} object - source object + * @param {String} name - name of the property + * + * @example + * const Self = ClassName; +function ClassName( o ) { }; + * _.accessor.forbid( Self, { a : 'a' } ); + * _.accessor.ownForbid( Self, 'a' ) // returns true + * _.accessor.ownForbid( Self, 'b' ) // returns false + * + * @function ownForbid + * @namespace Tools.accessor + */ + +function ownForbid( object, name ) +{ + if( !Object.hasOwnProperty.call( object, name ) ) + return false; + + let descriptor = Object.getOwnPropertyDescriptor( object, name ); + if( _.routineIs( descriptor.get ) && descriptor.get.isForbid ) + { + return true; + } + else + { + return false; + } + +} + +// -- +// etc +// -- + +/** + * @summary Declares read-only accessor( s ). + * @description Expects two arguments: (object), (names) or single as options map {@link module:Tools/base/Proto.wTools.accessor~AccessorOptions} + * + * @param {Object} object - target object + * @param {Object} names - contains names of properties that will get read-only accessor + * + * @example + * var Alpha = function _Alpha(){} + * _.classDeclare + * ({ + * cls : Alpha, + * parent : null, + * extend : { Composes : { a : null } } + * }); + * _.accessor.readOnly( Alpha.prototype,{ a : 'a' }); + * + * @function forbid + * @namespace Tools.accessor + */ + +function readOnly_body( o ) +{ + _.routine.assertOptions( readOnly_body, arguments ); + _.assert( _.boolLikeFalse( o.writable ) ); + return _.accessor.declare.body( o ); +} + +var defaults = readOnly_body.defaults = _.props.extend( null, declareMultiple.body.defaults ); +defaults.writable = false; + +let readOnly = _.routine.uniteCloning_replaceByUnite( declareMultiple_head, readOnly_body ); + +// + +let AccessorExtension = +{ + + // getter / setter generator + + _propertyGetterSetterNames, + _normalizedAsuiteForm, + _normalizedAsuiteUnfunct, + _amethodUnfunct, + + _objectMethodsNamesGet, + _objectMethodsGet, + _objectMethodsValidate, + _objectMethodMoveGet, + + _objectSetValue, + _objectAddMethods, + _objectInitStorage, + _declaringIsNeeded, + + _defaultsApply, + _methodsNormalize, + _objectInitStorageUnderscore, + methodWithStoringStrategyUnderscore, + _amethodFunctor, + _amethodFromMove, + _moveItMake, + _register, + + // declare + + suiteMove, /* qqq : cover */ + suiteSupplement, /* qqq : cover */ + suiteNormalize, + + declareSingle, + declareMultiple, + declare : declareMultiple, + + // forbid + + forbid, + _forbidSingle, + ownForbid, + + // etc + + readOnly, + + // fields + + Combining, + AmethodTypes, + AmethodTypesMap, + DeclarationOptions, + DeclarationDefaults, + DeclarationMultipleToSingleOptions, + +} + +// + +let ToolsExtension = +{ +} + +// -- +// extend +// -- + +_.accessor = _.accessor || Object.create( null ); +_.props.supplement( _, ToolsExtension ); +/* _.props.extend */Object.assign( _.accessor, AccessorExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l2/Accessor.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l2' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Accessor_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Accessor_s */ })(); + +/* */ /* begin of file Definition_s */ ( function Definition_s() { function Definition_s_naked() { ( function _Definition_s_() +{ + +'use strict'; + +/** +* Collection of definitions for constructions. +* @namespace wTools.define +* @extends Tools +* @module Tools/base/Proto +*/ + +const Self = _global_.wTools; +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implement +// -- + +/** +* @classdesc Class container for creating property-like entity from non-primitive value. + Is used by routines: + @see {@link module:Tools/base/Proto.wTools.define.own} + @see {@link module:Tools/base/Proto.wTools.define.common} + @see {@link module:Tools/base/Proto.wTools.define.instanceOf} + @see {@link module:Tools/base/Proto.wTools.define.makeWith} + @see {@link module:Tools/base/Proto.wTools.define.contained} +* @class Definition +* @namespace Tools.define +* @module Tools/base/Proto +*/ + +function Definition( o ) +{ + _.assert( arguments.length === 1 ); + if( !( this instanceof Definition ) ) + if( o instanceof Definition ) + return o; + else + return new( _.constructorJoin( Definition, arguments ) ); + _.props.extend( this, o ); + _.assert( _.longHas( _.definition.DefinitionGroup, o.defGroup ) ); + return this; +} + +Object.setPrototypeOf( Definition, null ); +Definition.prototype = Object.create( null ); +Definition.prototype.constructor = Definition; +Definition.prototype.cloneShallow = function() +{ + if( this._blueprint === false ) + { + _.assert( Object.isFrozen( this ) ); + return this; + } + + // let result = new Definition( this ); + let result = Object.create( Object.getPrototypeOf( this ) ); + // debugger; + Object.assign( result, this ); + // debugger; + + if( result._blueprint ) + result._blueprint = null; + if( result._ ) + result._ = Object.create( null ); + + // if( result._blueprint === false ) + // Object.freeze( result ); + // else + Object.preventExtensions( result ); + + return result; +} + +Definition.prototype.cloneDeep = function() +{ + return this.cloneShallow(); +} + +// + +function retype( o ) +{ + _.assert( _.mapIs( o ) ); + Object.setPrototypeOf( o, Definition.prototype ); + return o; +} + +// + +function toVal( definition ) +{ + _.assert( _.definitionIs( definition ) ); + _.assert( _.routineIs( definition.toVal ) ); + _.assert( definition.val !== undefined ); + return definition.toVal( definition.val ); +} + +// + +function nameOf( definition ) +{ + _.assert( _.definition.is( definition ) ); + return `${definition.name || ''}`; +} + +// + +function qnameOf( definition ) +{ + _.assert( _.definition.is( definition ) ); + let result = `${definition.defGroup}::${definition.kind}`; + if( definition.name !== undefined ) + result += `::${definition.name || ''}`; + return result +} + +// + +function _make( o ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.strDefined( o.kind ) ); + _.assert( _.strDefined( o.defGroup ) ); + _.assert( _.mapIs( o ) ); + _.assert( o._blueprint === null || o._blueprint === false || _.blueprint.isDefinitive( o._blueprint ) ); + + if( o._blueprint === undefined ) + o._blueprint = null; + + // let definition = new _.Definition( o ); + let definition = _.definition.retype( o ); + _.assert( definition === o ); + _.assert( definition.blueprintAmend === undefined ); + _.assert( definition.constructionAmend === undefined ); + _.assert( definition.blueprint === undefined ); + + if( definition._blueprint === false ) + Object.freeze( definition ); + else + Object.preventExtensions( definition ); + + return definition; +} + +_make.defaults = +{ + kind : null, + defGroup : null, + _blueprint : null, +} + +// + +function _unnamedMake( o ) +{ + _.assert( arguments.length === 1 ); + _.assert( !o.defGroup || o.defGroup === 'definition.unnamed' ); + if( !o.defGroup ) + o.defGroup = 'definition.unnamed'; + return _.definition._make( o ); +} + +// + +function _namedMake( o ) +{ + _.assert( arguments.length === 1 ); + _.assert( !o.defGroup || o.defGroup === 'definition.named' ); + if( !o.defGroup ) + o.defGroup = 'definition.named'; + return _.definition._make( o ); +} + +// + +function _traitMake( o ) +{ + _.assert( arguments.length === 1 ); + _.assert( !o.defGroup || o.defGroup === 'trait' ); + if( !o.defGroup ) + o.defGroup = 'trait'; + return _.definition._make( o ); +} + +// + +function extend( src ) +{ + _.assert( _.mapIs( src ) ); + + for( let name in src ) + { + _.assert + ( + name === src[ name ].name, + () => `Name of definition should be same as its alias, but \`${name} <> ${src[ name ].name}\`` + ); + _.definition._extend( src[ name ] ); + } + +} + +// + +function _extend( src ) +{ + + _.assert( _.routineIs( src ) ); + _.assert( _.strIs( src.name ) ); + _.assert( arguments.length === 1 ); + + _.assert + ( + _.mapIs( src.identity ), + () => `Expects defined \`identity\`, but routine::${src.name} does not have such` + ); + _.assert( !!src.identity.definition ); + _.assert( _.define.trait === _.trait ); + + if( src.identity.trait ) + { + _.define.trait[ src.name ] = src; + _.define[ src.name ] = src; + } + else + { + _.define[ src.name ] = src; + if( src.identity.named ) + _.define.named[ src.name ] = src; + else + _.define.unnamed[ src.name ] = src; + } + +} + +// -- +// define +// -- + +/** +* Routines to manipulate definitions. +* @namespace wTools.definition +* @extends Tools +* @module Tools/base/Proto +*/ + +let DefinitionExtension = +{ + + // implementation + + is : _.definitionIs, + retype, + toVal, + nameOf, + qnameOf, + _make, + _unnamedMake, + _namedMake, + _traitMake, + extend, + _extend, + + // fields + +} + +_.define = _.define || Object.create( null ); +_.define.named = _.define.named || Object.create( null ); +_.define.unnamed = _.define.unnamed || Object.create( null ); +_.define.trait = _.define.trait || Object.create( null ); +_.trait = _.define.trait; + +_.definition = _.definition || Object.create( null ); +/* _.props.extend */Object.assign( _.definition, DefinitionExtension ); +_.assert( _.routineIs( _.definitionIs ) ); +_.assert( _.definition.is === _.definitionIs ); + +// + +let ToolsExtension = +{ + Definition, +} + +_.props.extend( _, ToolsExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l2/Definition.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l2' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Definition_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Definition_s */ })(); + +/* */ /* begin of file Types_s */ ( function Types_s() { function Types_s_naked() { ( function _Types_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +// -- +// enums +// -- + +let DefinitionGroup = [ 'etc', 'trait', 'definition.unnamed', 'definition.named' ]; + +let DefinitionKnownFields = +{ + toVal : 'routine::toVal( map::o ) -> anything::', + constructionAmend : 'routine::constructionAmend( Construction::construction Primitive::key ) -> Nothing::', + blueprintAmend : 'routine::( map::o ) -> Nothing::', + blueprintForm1 : 'routine::( Blueprint::blueprint ) -> Nothing::', + blueprintForm2 : 'routine::( Blueprint::blueprint ) -> Nothing::', + blueprintForm3 : 'routine::( Blueprint::blueprint ) -> Nothing::', +} + +let BlueprintInternalRoutines = +{ + blueprintAmend : 'routine::( map::o ) -> Nothing::', + blueprintForm1 : 'routine::( Blueprint::blueprint ) -> Nothing::', + blueprintForm2 : 'routine::( Blueprint::blueprint ) -> Nothing::', + blueprintForm3 : 'routine::( Blueprint::blueprint ) -> Nothing::', +} + +let ConstructionRuntimeRoutines = +{ + constructionInit : { signature : 'routine::constructionInit( ConstructionContext::@ Genesis::@ ) -> Nothing::@', multiple : 1 }, + constructionAmend : { signature : 'routine::constructionAmend( Construction::@ Primitive::@ ) -> Nothing::@', multiple : 1 }, + allocate : { multiple : 0 }, + retype : { multiple : 0 }, + initBegin : { multiple : 1 }, + constructionInitEnd : { multiple : 1 }, +} + +let DefinitionExtension = +{ + + DefinitionGroup, + DefinitionKnownFields, + + BlueprintInternalRoutines, + ConstructionRuntimeRoutines, + +} + +_.definition = _.definition || Object.create( null ); +/* _.props.extend */Object.assign( _.definition, DefinitionExtension ); + +// -- +// Blueprint +// -- + +function Blueprint() +{ + return _.blueprint.define( ... arguments ); +} +Blueprint.prototype = Object.create( null ); +Object.setPrototypeOf( Blueprint, null ); +Object.preventExtensions( Blueprint ); + +// -- +// define tools +// -- + +var ToolsExtension = +{ + + Blueprint, + +} + +Object.assign( _, ToolsExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l2/Types.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l2' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Types_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Types_s */ })(); + +/* */ /* begin of file Blueprint_s */ ( function Blueprint_s() { function Blueprint_s_naked() { ( function _Blueprint_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +function is( blueprint ) +{ + if( !blueprint ) + return false; + return _.prototype.isPrototypeFor( _.Blueprint.prototype, blueprint ); +} + +// + +function isDefinitive( blueprint ) +{ + if( !blueprint ) + return false; + return _.prototype.isPrototypeFor( _.Blueprint.prototype, blueprint ) && !!blueprint.traitsMap; +} + +// + +function isRuntime( runtime ) +{ + if( !runtime ) + return false; + return _.prototype.isPrototypeFor( _.Blueprint.prototype, runtime ) && !runtime.traitsMap; +} + +// + +function isBlueprintOf( blueprint, construction ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.blueprint.isDefinitive( blueprint ) ); + return _.construction.isInstanceOf( construction, blueprint ); +} + +// + +function singleAt( src ) +{ + + return blueprintLook( src, null ); + + /* */ + + function blueprintLook( src, name ) + { + if( _.mapIs( src ) ) + return blueprintMapLook( src, name ); + else if( _.longIs( src ) ) + return blueprintArrayLook( src, name ) + else if( _.definitionIs( src ) ) + return { blueprint : false, name : false }; + else if( _.blueprintIsDefinitive( src ) ) + return { blueprint : src, name }; + else + return { blueprint : false, name : false }; + } + + /* */ + + function blueprintMapLook( map, name ) + { + let result = null + _.assert( _.mapIs( map ) ); + for( let name2 in map ) + { + let prop = map[ name2 ]; + let r = blueprintLook( prop, name ); + if( r.blueprint !== null ) + { + if( result ) + return { blueprint : false, name : false }; + else + result = r; + } + } + if( result ) + return result; + else + return { blueprint : false, name : false }; + } + + /* */ + + function blueprintArrayLook( array, name ) + { + let result = null; + for( let prop of array ) + { + let r = blueprintLook( prop, name ); + if( r.blueprint !== null ) + { + if( result ) + return { blueprint : false, name : false }; + else + result = r; + } + } + if( result ) + return result; + else + return { blueprint : false, name : false }; + } + + /* */ + +} + +// + +function compileSourceCode( blueprint ) +{ + _.assert( arguments.length === 1 ); + _.assert( 0, 'not implemented' ); + let generator = _.Generator(); + // generator.external( x ); /* zzz : implement */ + generator.import + ({ + src : _.construction._construct2 + }); + return generator.generateSourceCode(); +} + +// + +function defineConstructor() +{ + let blueprint = _.blueprint.define( ... arguments ); + _.assert( _.routineIs( blueprint.make ) ); + return blueprint.make; +} + +// + +function define() +{ + return _.blueprint._define({ src : arguments, amending : 'extend' }); +} + +// + +function _define( o ) +{ + + _.routine.options_( _define, o ); + _.assert( arguments.length === 1 ); + + let runtime = Object.create( _.Blueprint.prototype ); + runtime._practiceMap = Object.create( null ); + runtime.propsExtension = Object.create( null ); + runtime.propsSupplementation = Object.create( null ); + runtime.prototype = null; + runtime.name = null; + runtime.typed = null; + // runtime._makingTyped = null; + runtime._prototyping = null; + runtime.make = null; + runtime.makeEach = makeEach; + runtime.from = from; + runtime.fromEach = fromEach; + runtime.retype = retype; + runtime.retypeEach = retypeEach; + runtime.runtime = runtime; + Object.preventExtensions( runtime ); + + let blueprint = Object.create( runtime ); + blueprint.traitsMap = Object.create( null ); + blueprint.namedMap = Object.create( null ); + blueprint.unnamedArray = []; + Object.preventExtensions( blueprint ); + + _.blueprint._amend + ({ + blueprint, + extension : o.src, + amending : o.amending, + blueprintComposing : 'inherit', + }); + + let defContext = Object.create( null ); + defContext.blueprint = blueprint; + defContext.amending = o.amending; + + let defaultSupplement = + [ + _.trait.extendable( false ), + _.trait.typed({ val : false }), + ] + + _.blueprint._supplement( blueprint, defaultSupplement ); + + _.blueprint._associateDefinitions( blueprint ); + defContext.stage = 'blueprintForm1'; + _.blueprint._form( defContext ); + + runtime.typed = blueprint.traitsMap.typed.val; + _.assert( runtime._prototyping !== undefined ); + + let name = blueprint.name || 'Construction'; + let Construction = + { + [ name ] : function() + { + return _.construction._make( this, runtime, arguments ); + } + } + let make = Construction[ name ]; + Object.setPrototypeOf( make, null ); + make.prototype = blueprint.prototype; + + runtime.make = make; + make.runtime = runtime; + + defContext.stage = 'blueprintForm2'; + _.blueprint._form( defContext ); + defContext.stage = 'blueprintForm3'; + _.blueprint._form( defContext ); + + _.blueprint._preventExtensions( blueprint ); + _.blueprint._validate( blueprint ); + + _.assert( blueprint.name === null || blueprint.name === name ); + + return blueprint; + + /* */ + + function makeEach() + { + return _.construction._makeEach( this, runtime, arguments ); + } + + /* */ + + function from() + { + return _.construction._from( this, runtime, arguments ); + } + + /* */ + + function fromEach() + { + return _.construction._fromEach( this, runtime, arguments ); + } + + /* */ + + function retype() + { + return _.construction._retype( this, runtime, arguments ); + } + + /* */ + + function retypeEach() + { + return _.construction._retypeEach( this, runtime, arguments ); + } + + /* */ + +} + +_define.defaults = +{ + src : null, + amending : 'extend' +} + +// + +function _amend( o ) +{ + + _.assert( arguments.length === 1 ); + _.routine.options_( _amend, arguments ); + _.assert( _.longHas( [ 'extend', 'supplement' ], o.amending ) ); + _.assert( _.longHas( [ 'throw', 'amend', 'inherit' ], o.blueprintComposing ) ); + + _amendAct( o.extension, null ); + + return o.blueprint; + + /* - + +- amendWithArray +- amendWithMap +- amendWithBlueprint1 +- amendWithBlueprintAmend +- amendWithDefinition +- amendWithNamedDefinition +- blueprintNamedDefinitionRewrite +- amendWithUnnamedDefinition +- blueprintUnnamedDefinitionRewrite +- amendWithTrait +- blueprintTraitRewrite +- amendWithPrimitive +- definitionCloneMaybe +- definitionDepthCheck + + */ + + function _amendAct( src, name ) + { + if( _.longIs( src ) ) + amendWithArray( src, name ); + else if( _.blueprint.isDefinitive( src ) ) + amendWithBlueprint1( src, name ); + else if( _.mapIs( src ) ) + amendWithMap( src, name ); + else if( _.definitionIs( src ) ) + amendWithDefinition( src, name ); + else _.assert( 0, `Not clear how to amend blueprint by the amendment ${_.entity.strType( src )}` ); + } + + /* */ + + function amendWithArray( array, name ) + { + for( let e = 0 ; e < array.length ; e++ ) + _amendAct( array[ e ], null ); + } + + /* */ + + function amendWithMap( map ) + { + + _.assert( _.mapIs( map ) ); + + for( let name in map ) + { + let ext = map[ name ]; + if( _.definitionIs( ext ) ) + { + amendWithDefinition( ext, name ); + } + else if( _.arrayIs( ext ) ) + { + amendWithArray( ext, name ); + } + else if( _.primitiveIs( ext ) || _.routineIs( ext ) ) + { + amendWithPrimitive( ext, name ); + } + else + { + _amendAct( ext, name ); + } + } + + } + + /* */ + + function amendWithBlueprint1( srcBlueprint ) + { + if( o.blueprintComposing === 'amend' ) + { + amendWithBlueprintAmend( srcBlueprint ); + return o.blueprint; + } + else if( o.blueprintComposing === 'inherit' ) + { + let extension = _.define.inherit( srcBlueprint ); + _amendAct( extension ); + } + else + { + throw _.err( 'Not clear how to extend by blueprint' ); + } + } + + /* */ + + function amendWithBlueprintAmend( ext, k ) + { + o.blueprintDepth += 1; + for( let k in ext.traitsMap ) + { + let definition = ext.traitsMap[ k ]; + if( definitionDepthCheck( definition ) ) + { + // if( definition.kind === 'typed' && definition.val && ext.prototype ) /* yyy */ + // { + // definition = definitionClone( definition ); + // definition.prototype = ext.prototype; + // } + amendWithTrait( definition, k ); + } + } + for( let k = 0 ; k < ext.unnamedArray.length ; k++ ) + { + let definition = ext.unnamedArray[ k ]; + if( definitionDepthCheck( definition ) ) + amendWithUnnamedDefinition( definition, k ); + } + for( let k in ext.namedMap ) + { + let definition = ext.namedMap[ k ]; + if( definitionDepthCheck( definition ) ) + amendWithNamedDefinition( definition, k ); + } + for( let k in ext.propsSupplementation ) + { + amendWithPrimitive( ext.propsSupplementation[ k ], k ); + } + for( let k in ext.propsExtension ) + { + amendWithPrimitive( ext.propsExtension[ k ], k ); + } + o.blueprintDepth -= 1; + } + + /* */ + + function amendWithDefinition( definition, name ) + { + if( _.traitIs( definition ) ) + amendWithTrait( definition, name ); + else if( definition.defGroup === 'definition.named' ) + amendWithNamedDefinition( definition, name ); + else + amendWithUnnamedDefinition( definition, name ); + } + + /* */ + + function amendWithNamedDefinition( srcDefinition, name ) + { + _.assert( srcDefinition.defGroup === 'definition.named' ); + _.assert + ( + _.strDefined( name ) || _.strDefined( srcDefinition.name ) + , () => `${_.definition.qnameOf( srcDefinition )} should have name, but it is not defined in the blueprint` + ); + + if( name !== null && srcDefinition.name !== null && name !== srcDefinition.name ) + { + srcDefinition = definitionClone( srcDefinition ); + srcDefinition.name = name; + } + + _.assert( name === null || srcDefinition.name === null || name === srcDefinition.name ); + + if( name && name !== srcDefinition.name ) + { + _.assert( !Object.isFrozen( srcDefinition ) ); + srcDefinition.name = name; + } + + let dstDefinition = o.blueprint.namedMap[ name ] || null; + + srcDefinition = definitionCloneMaybe( srcDefinition ); + + let blueprintDefinitionRewrite2 = + ( dstDefinition && dstDefinition.blueprintDefinitionRewrite ) + || ( srcDefinition && srcDefinition.blueprintDefinitionRewrite ); + + _.assert( _.strDefined( srcDefinition.name ) ); + + let o2 = _.props.extend( null, o ); + o2.blueprintDefinitionRewrite = blueprintNamedDefinitionRewrite; + o2.name = srcDefinition.name; + o2.defGroup = 'definition.named'; + + if( o.amending === 'supplement' ) + { + o2.primeDefinition = dstDefinition; + o2.secondaryDefinition = srcDefinition; + } + else + { + o2.primeDefinition = srcDefinition; + o2.secondaryDefinition = dstDefinition; + } + + o2.definition = srcDefinition; + + if( blueprintDefinitionRewrite2 ) + { + _.assert( !dstDefinition || _.routineIs( dstDefinition.blueprintDefinitionRewrite ) ); + _.assert( _.routineIs( srcDefinition.blueprintDefinitionRewrite ) ); + srcDefinition.blueprintDefinitionRewrite( o2 ); + } + else + { + o2.blueprintDefinitionRewrite( o2 ); + } + + } + + /* */ + + function blueprintNamedDefinitionRewrite( op ) + { + + if( op.secondaryDefinition && !op.primeDefinition ) + op.blueprint.namedMap[ op.name ] = op.secondaryDefinition; + else + op.blueprint.namedMap[ op.name ] = op.primeDefinition; + + } + + /* */ + + function amendWithUnnamedDefinition( srcDefinition ) + { + _.assert( srcDefinition.defGroup === 'definition.unnamed' ); + + let dstDefinition = o.blueprint.traitsMap[ srcDefinition.kind ] || null; + + srcDefinition = definitionCloneMaybe( srcDefinition ); + + let blueprintDefinitionRewrite2 = + ( dstDefinition && dstDefinition.blueprintDefinitionRewrite ) + || ( srcDefinition && srcDefinition.blueprintDefinitionRewrite ); + + let o2 = _.props.extend( null, o ); + o2.blueprintDefinitionRewrite = blueprintUnnamedDefinitionRewrite; + o2.defGroup = 'definition.unnamed'; + + if( o.amending === 'supplement' ) + { + o2.primeDefinition = dstDefinition; + o2.secondaryDefinition = srcDefinition; + } + else + { + o2.primeDefinition = srcDefinition; + o2.secondaryDefinition = dstDefinition; + } + + o2.definition = srcDefinition; + + if( blueprintDefinitionRewrite2 ) + { + _.assert( !dstDefinition || _.routineIs( dstDefinition.blueprintDefinitionRewrite ) ); + _.assert( _.routineIs( srcDefinition.blueprintDefinitionRewrite ) ); + srcDefinition.blueprintDefinitionRewrite( o2 ); + } + else + { + o2.blueprintDefinitionRewrite( o2 ); + } + + } + + /* */ + + function blueprintUnnamedDefinitionRewrite( op ) + { + _.arrayAppendOnceStrictly( o.blueprint.unnamedArray, op.primeDefinition || op.secondaryDefinition ); + } + + /* */ + + function amendWithTrait( srcDefinition, key ) + { + _.assert( _.strIs( srcDefinition.kind ) ); + + srcDefinition = definitionCloneMaybe( srcDefinition ); + + let dstDefinition = o.blueprint.traitsMap[ srcDefinition.kind ] || null; + let blueprintDefinitionRewrite2 = + ( dstDefinition && dstDefinition.blueprintDefinitionRewrite ) + || ( srcDefinition && srcDefinition.blueprintDefinitionRewrite ); + + _.assert( dstDefinition === null || _.definitionIs( dstDefinition ) ); + + let o2 = _.props.extend( null, o ); + o2.blueprintDefinitionRewrite = blueprintTraitRewrite; + o2.kind = srcDefinition.kind; + + if( o.amending === 'supplement' ) + { + o2.primeDefinition = dstDefinition; + o2.secondaryDefinition = srcDefinition; + } + else + { + o2.primeDefinition = srcDefinition; + o2.secondaryDefinition = dstDefinition; + } + + o2.definition = srcDefinition; + + if( blueprintDefinitionRewrite2 ) + { + _.assert( !dstDefinition || _.routineIs( dstDefinition.blueprintDefinitionRewrite ) ); + _.assert( _.routineIs( srcDefinition.blueprintDefinitionRewrite ) ); + srcDefinition.blueprintDefinitionRewrite( o2 ); + } + else + { + o2.blueprintDefinitionRewrite( o2 ); + } + + } + + /* */ + + function blueprintTraitRewrite( op ) + { + if( op.secondaryDefinition && !op.primeDefinition ) + op.blueprint.traitsMap[ op.kind ] = op.secondaryDefinition; + else + op.blueprint.traitsMap[ op.kind ] = op.primeDefinition; + } + + /* */ + + function amendWithPrimitive( ext, key ) + { + _.assert( _.strIs( key ) ); + _.assert + ( + _.primitiveIs( ext ) || _.routineIs( ext ), + () => `Property could be prtimitive or routine, but element ${key} is ${_.entity.strType( key )}.` + + `\nUse _.define.*() to defined more complex data structure` + ); + if( o.amending === 'supplement' ) + if( Object.hasOwnProperty.call( o.blueprint.propsExtension, key ) ) + return; + if( Object.hasOwnProperty.call( o.blueprint.propsSupplementation, key ) ) + return; + o.blueprint.propsExtension[ key ] = ext; + } + + /* */ + + function definitionClone( definition ) + { + definition = definition.cloneShallow(); + if( definition._blueprint === null ) + definition._blueprint = o.blueprint; + _.assert( definition._blueprint === o.blueprint || definition._blueprint === null || definition._blueprint === false ); + return definition; + } + + /* */ + + function definitionCloneMaybe( definition ) + { + if( definition._blueprint && definition._blueprint !== o.blueprint ) + return definitionClone( definition ); + _.assert( definition._blueprint === o.blueprint || definition._blueprint === null || definition._blueprint === false ); + return definition; + } + + /* */ + + function definitionDepthCheck( definition ) + { + if( !definition.blueprintDepthLimit ) + return true; + return definition.blueprintDepthLimit + definition.blueprintDepthReserve + o.blueprintDepthReserve > o.blueprintDepth; + } + + /* */ + +} + +_amend.defaults = +{ + blueprint : null, + extension : null, + amending : null, + blueprintComposing : 'throw', + blueprintDepth : 0, + blueprintDepthReserve : 0, +} + +// + +function _supplement( blueprint, extension ) +{ + return _.blueprint._amend + ({ + blueprint, + extension, + amending : 'supplement', + }); +} + +// + +function _extend( blueprint, extension ) +{ + return _.blueprint._amend + ({ + blueprint, + extension, + amending : 'extend', + }); +} + +// + +function _associateDefinitions( blueprint ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.blueprint.isDefinitive( blueprint ) ); + + _.blueprint.eachDefinition( blueprint, ( blueprint, definition, key ) => + { + if( definition._blueprint === false ) + { + _.assert( Object.isFrozen( definition ) ); + return; + } + if( definition._blueprint === blueprint ) + return; + _.assert( definition._blueprint === null ); + _.assert( !Object.isFrozen( definition ) ); + definition._blueprint = blueprint; + }); + + return blueprint; +} + +// + +function _form( o ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.blueprint.isDefinitive( o.blueprint ) ); + _.assert( _.longHas( [ 'blueprintForm1', 'blueprintForm2', 'blueprintForm3' ], o.stage ) ); + _.routine.options_( _form, o ); + + _.blueprint.eachDefinition( o.blueprint, ( blueprint, definition, propName ) => + { + if( definition[ o.stage ] ) + { + o.propName = propName; + o.definition = definition; + _.assert( definition._blueprint === false || definition._blueprint === o.blueprint ); + definition[ o.stage ]( o ); + _.assert( definition._blueprint === false || definition._blueprint === o.blueprint ); + } + }); + + delete o.propName; + delete o.definition; + + return o.blueprint; +} + +_form.defaults = +{ + blueprint : null, + stage : null, + amending : 'extend' +} + +// + +function _preventExtensions( blueprint ) +{ + _.assert( _.blueprint.isDefinitive( blueprint ) ); + + Object.preventExtensions( blueprint.namedMap ); + Object.preventExtensions( blueprint.unnamedArray ); + Object.preventExtensions( blueprint.traitsMap ); + Object.preventExtensions( blueprint.propsExtension ); + Object.preventExtensions( blueprint.propsSupplementation ); + Object.preventExtensions( blueprint._practiceMap ); + Object.preventExtensions( blueprint ); + Object.freeze( blueprint ); + +} + +// + +function _validate( blueprint ) +{ + + if( !Config.debug ) + return; + + _.assert( _.blueprint.isDefinitive( blueprint ) ); + _.assert + ( + _.routineIs( blueprint._practiceMap.allocate ) + , `Each blueprint should have handler::allocate, but definition::${blueprint.name} does not have` + ); + _.assert + ( + _.routineIs( blueprint._practiceMap.retype ) + , `Each blueprint should have handler::retype, but definition::${blueprint.name} does not have` + ); + _.assert + ( + !blueprint.traitsMap.typed + || blueprint.typed === blueprint.traitsMap.typed.val + || blueprint.traitsMap.typed.val === _.maybe + ); + + _.blueprint.eachDefinition( blueprint, ( blueprint, definition, key ) => + { + if( definition._blueprint === false ) + { + _.assert( Object.isFrozen( definition ) ); + return; + } + _.assert + ( + definition._blueprint === blueprint + , () => `Blueprint of ${_.definition.qnameOf( definition )} is not set, but have to be set` + ); + _.assert + ( + !Object.isExtensible( definition ) + , () => `${_.definition.qnameOf( definition )} is extensible, but have to be not` + ); + _.assert + ( + Object.isFrozen( definition ) + , () => `${_.definition.qnameOf( definition )} is not frozen, but have to be frozen` + ); + }); + +} + +// + +function _practiceAdd( blueprint, name, routine ) +{ + + _.assert( _.routineIs( routine ) ); + _.assert( _.mapIs( _.definition.ConstructionRuntimeRoutines[ name ] ), `Unknown runtime routine::${name}` ); + + let descriptor = _.definition.ConstructionRuntimeRoutines[ name ]; + + if( descriptor.multiple ) + { + blueprint._practiceMap[ name ] = blueprint._practiceMap[ name ] || []; + blueprint._practiceMap[ name ].push( routine ); + } + else + { + _.assert( blueprint._practiceMap[ name ] === undefined, `Blueprint already have runtime routine::${name}` ); + blueprint._practiceMap[ name ] = routine; + } + +} + +// + +function eachDefinition( blueprint, onEach ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.blueprint.isDefinitive( blueprint ) ); + + for( let k in blueprint.traitsMap ) + { + let trait = blueprint.traitsMap[ k ]; + onEach( blueprint, trait, k ); + } + + for( let k in blueprint.namedMap ) + { + let definition = blueprint.namedMap[ k ]; + onEach( blueprint, definition, k ); + } + + for( let k = 0 ; k < blueprint.unnamedArray.length ; k++ ) + { + let definition = blueprint.unnamedArray[ k ]; + onEach( blueprint, definition, null ); + } + +} + +// + +function nameOf( blueprint ) +{ + _.assert( _.blueprint.is( blueprint ) ); + return blueprint.name; +} + +// + +function qnameOf( blueprint ) +{ + _.assert( _.blueprint.is( blueprint ) ); + return `Blueprint::${blueprint.name || ''}`; +} + +// + +function constructorOf( blueprint ) +{ + let result = blueprint.make; + _.assert( _.blueprint.isDefinitive( blueprint ) ); + _.assert( _.routineIs( result ) ); + return result; +} + +// + +function retyperOf( blueprint ) +{ + let result = blueprint.retype; + _.assert( _.blueprint.isDefinitive( blueprint ) ); + _.assert( _.routineIs( result ) ); + return result; +} + +// + +function construct( blueprint ) +{ + _.assert( arguments.length === 1 ); + + if( !_.blueprint.isDefinitive( blueprint ) ) + blueprint = _.blueprint.define( blueprint ); + + let construct = _.blueprint.constructorOf( blueprint ); + _.assert( _.routineIs( construct ), 'Cant find constructor for blueprint' ); + let construction = construct(); + return construction; +} + +// + +function retype( blueprint, construction ) +{ + _.assert( arguments.length === 2 ); + _.assert( !!construction ); + + if( !_.blueprint.isDefinitive( blueprint ) ) + blueprint = _.blueprint.define( blueprint ); + + let retyper = _.blueprint.retyperOf( blueprint ); + _.assert( _.routineIs( retyper ), 'Cant find retyped for blueprint' ); + let construction2 = retyper( construction ); + _.assert( construction === construction2 ); + return construction; +} + +// + +function qnameOfDefinition( blueprint, definition ) +{ + + _.assert( arguments.length === 2 ); + _.assert( _.blueprint.isDefinitive( blueprint ) ); + _.assert( _.definition.is( definition ) ); + + if( _.definition.trait.is( definition ) ) + { + for( let k in blueprint.traitsMap ) + { + if( blueprint.traitsMap[ k ] === definition ) + return `trait::${k}` + } + } + else + { + for( let k in blueprint.namedMap ) + { + if( blueprint.namedMap[ k ] === definition ) + return `definition::${k}` + } + for( let k = 0 ; k < blueprint.unnamedArray.length ; k++ ) + { + if( blueprint.unnamedArray[ k ] === definition ) + return `definition::${k}` + } + } + + return; +} + +// -- +// define blueprint +// -- + +var BlueprintExtension = +{ + + // implementation + + is, + isDefinitive, + isRuntime, + isBlueprintOf, + singleAt, + + compileSourceCode, + defineConstructor, + define, + _define, + _amend, + _supplement, + _extend, + _associateDefinitions, + _form, + _preventExtensions, + _validate, + + _practiceAdd, + eachDefinition, + + nameOf, + qnameOf, + constructorOf, + retyperOf, + construct, + retype, + qnameOfDefinition, + +} + +_.blueprint = _.blueprint || Object.create( null ); +Object.assign( _.blueprint, BlueprintExtension ); + +// -- +// define tools +// -- + +var ToolsExtension = +{ +} + +Object.assign( _, ToolsExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l3/Blueprint.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Blueprint_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Blueprint_s */ })(); + +/* */ /* begin of file Construction_s */ ( function Construction_s() { function Construction_s_naked() { ( function _Construction_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// implementation +// -- + +function isTyped( construction ) +{ + _.assert( arguments.length === 1 ); + + if( !construction ) + return false; + + let next = construction; + do + { + construction = next + next = Object.getPrototypeOf( construction ); + } + while( next ) + + if( construction !== _.Construction.prototype ) + return false; + + return true; +} + +// + +function isInstanceOf( construction, runtime ) +{ + + if( _.blueprint.isDefinitive( runtime ) ) + runtime = runtime.runtime; + + _.assert( arguments.length === 2 ); + _.assert( _.blueprint.isRuntime( runtime ) ); + _.assert( _.fuzzyLike( runtime.typed ) ); + _.assert( _.routineIs( runtime.make ) ); + + if( !construction ) + return false; + + if( runtime.typed && runtime.make.prototype !== null ) + { + return construction instanceof runtime.make; + } + + if( _.mapIs( construction ) ) + return _.maybe; + return false; +} + +// + +function amend( o ) +{ + o = _.routine.options_( amend, arguments ); + if( o.dstConstruction === null ) + o.dstConstruction = Object.create( null ); + let amending = o.amending; + + let blueprint = _.blueprint.singleAt( o.src ).blueprint; + + if( !blueprint ) + { + let defs = []; + let prototype = _.prototype.of( o.dstConstruction ); + let add = o.amending === 'supplement' ? 'push' : 'unshift'; + + defs[ add ]( o.src ); + + { + let opts = Object.create( null ); + opts.val = _.maybe; + if( prototype && prototype !== Object.prototype ) + { + opts.prototype = prototype; + opts.new = false; + } + opts._synthetic = o.dstConstruction; + defs[ add ]( _.trait.typed( opts ) ); + } + + defs[ add ]( _.trait.extendable( true ) ); + + blueprint = _.blueprint._define({ src : defs, amending : o.amending }); + } + + constructionBlueprintExtend( o.dstConstruction, blueprint, null ); + + return o.dstConstruction; + + /* */ + + function constructionBlueprintExtend( dstConstruction, blueprint, name ) + { + _.assert( !_.blueprint.is( dstConstruction ) ); + _.construction._retype + ({ + construction : dstConstruction, + runtime : blueprint.runtime, + amending, + }); + } + + /* */ + +} + +amend.defaults = +{ + dstConstruction : null, + src : null, + amending : 'extend', +} + +// + +/* zzz qqq : cover and extend */ +function extend( dstConstruction, src ) +{ + return _.construction.amend + ({ + dstConstruction, + src, + amending : 'extend' + }); +} + +// + +/* zzz qqq : cover and extend */ +function supplement( dstConstruction, src ) +{ + return _.construction.amend + ({ + dstConstruction, + src, + amending : 'supplement' + }); +} + +// + +function _amendCant( construction, definition, key ) +{ + throw _.err + ( + `Definition::${definition.kind} cant extend created construction after initialization.` + + ` Use this definition during initialization only.` + ); +} + +// -- +// make +// -- + +function _make_head( routine, args ) +{ + let genesis; + + if( args.length === 3 ) + { + genesis = Object.create( null ); + genesis.construction = args[ 0 ]; + genesis.runtime = args[ 1 ]; + genesis.args = args[ 2 ]; + if( args[ 2 ][ 0 ] ) + { + genesis.construction = args[ 2 ][ 0 ]; + } + else if( !_.construction.isInstanceOf( genesis.construction, genesis.runtime ) ) + { + _.assert( !( genesis.construction instanceof genesis.runtime.retype ), 'Use no "new" to call routine::from' ); + genesis.construction = null; + } + } + else + { + genesis = args[ 0 ]; + _.assert( _.mapIs( genesis ) ); + } + + _.routine.options_( routine, genesis ); + + if( genesis.args === null ) + genesis.args = []; + + if( Config.debug ) + { + let isInstance = _.construction.isInstanceOf( genesis.construction, genesis.runtime ); + _.assert( args.length === 1 || args.length === 3 ); + _.assert( !( genesis.construction instanceof genesis.runtime.retype ), 'Use no "new" to call routine::from' ); + _.assert( genesis.args.length === 0 || genesis.args.length === 1 ); + _.assert( genesis.runtime.makeCompiled === undefined, 'not implemented' ); + } + + return genesis; +} + +// + +function _make3( genesis ) +{ + + if( genesis.args === undefined || genesis.args === null ) + genesis.args = []; + + _.routine.assertOptions( _make3, arguments ); + _.assert( genesis.construction === null || _.object.isBasic( genesis.construction ) ); + _.assert( _.argumentsArray.like( genesis.args ) ); + _.assert( genesis.args.length === 0 || genesis.args.length === 1 ); + _.assert( arguments.length === 1 ); + _.assert( _.fuzzyIs( genesis.runtime.typed ) ); + + if( genesis.constructing === 'retype' ) + { + genesis.construction = genesis.runtime._practiceMap.retype( genesis ); + } + else if( genesis.constructing === 'allocate' ) + { + let wasNull = genesis.construction === null + genesis.construction = genesis.runtime._practiceMap.allocate( genesis ); + _.assert + ( + !!genesis.runtime.typed === false + || genesis.runtime.make.prototype === null + || genesis.construction instanceof genesis.runtime.make + ); + if( !!genesis.runtime.typed && wasNull ) + return genesis.construction; + } + else _.assert( genesis.constructing === false ); + + _.construction._init( genesis ); + _.construction._extendArguments( genesis ); + + return genesis.construction; +} + +_make3.defaults = +{ + constructing : null, + construction : null, + amending : null, + args : null, + runtime : null, +} + +// + +function _make2( construction, runtime, args ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + + let genesis = Object.create( null ); + genesis.construction = construction; + genesis.args = args; + genesis.runtime = runtime; + genesis.constructing = 'allocate'; + genesis.amending = 'extend'; + + return _.construction._make3( genesis ); +} + +// + +function _make( construction, runtime, args ) +{ + + _.assert( arguments.length === 3 ); + + if( !runtime.typed && runtime.make.prototype !== null && construction instanceof runtime.make ) + { + construction = null; + } + else if( _.construction.isInstanceOf( construction, runtime ) ) + { + } + else + { + construction = null; + } + + _.assert( !runtime.makeCompiled, 'not tested' ); + + construction = _.construction._make2( construction, runtime, args ); + + return construction; +} + +// + +function _makeEach( construction, runtime, args ) +{ + let result = []; + _.assert( arguments.length === 3 ); + for( let a = 0 ; a < args.length ; a++ ) + { + let construction = runtime.make( args[ a ] ); + if( construction !== undefined ) + result.push( construction ); + } + return result; +} + +// + +function _from( construction, runtime, args ) +{ + + if( Config.debug ) + { + let isInstance = _.construction.isInstanceOf( construction, runtime ); + _.assert( arguments.length === 3 ); + _.assert( isInstance === false || isInstance === _.maybe ); + _.assert( runtime.make.prototype === null || !( construction instanceof runtime.make ) ); + _.assert( !( construction instanceof runtime.from ), 'Use no "new" to call routine::from' ); + } + + if( _.construction.isInstanceOf( args[ 0 ], runtime ) ) + { + _.assert( args.length === 1 ); + construction = args[ 0 ]; + return construction; + } + else + { + construction = null; + } + + _.assert( !runtime.makeCompiled, 'not tested' ); + construction = _.construction._make2( construction, runtime, args ); + + return construction; +} + +// + +function _fromEach( construction, runtime, args ) +{ + let result = []; + _.assert( arguments.length === 3 ); + for( let a = 0 ; a < args.length ; a++ ) + { + let construction = runtime.from( args[ a ] ); + if( construction !== undefined ) + result.push( construction ); + } + return result; +} + +// + +function _retype_body( genesis ) +{ + + if( Config.debug ) + { + let isInstance = _.construction.isInstanceOf( genesis.construction, genesis.runtime ); + _.assert( arguments.length === 1 ); + _.assert( !( genesis.construction instanceof genesis.runtime.retype ), 'Use no "new" to call routine::from' ); + _.assert( genesis.args.length === 0 || genesis.args.length === 1 ); + _.assert( genesis.runtime.makeCompiled === undefined, 'not implemented' ); + } + + return _.construction._make3( genesis ); +} + +_retype_body.defaults = +{ + ... _make3.defaults, + constructing : 'retype', + amending : 'supplement', +} + +let _retype = _.routine.uniteCloning_replaceByUnite( _make_head, _retype_body ); + +// + +function _retypeEach( construction, runtime, args ) +{ + let result = []; + _.assert( arguments.length === 3 ); + for( let a = 0 ; a < args.length ; a++ ) + { + let construction = runtime.retype( args[ a ] ); + if( construction !== undefined ) + result.push( construction ); + } + return result; +} + +// + +function _init( genesis ) +{ + _.assert( arguments.length === 1 ); + + if( genesis.runtime._practiceMap.initBegin ) + for( let i = 0 ; i < genesis.runtime._practiceMap.initBegin.length ; i++ ) + genesis.runtime._practiceMap.initBegin[ i ]( genesis ); + + _.construction._initFields( genesis ); + _.construction._initDefines( genesis ); + + if( genesis.runtime._practiceMap.constructionInitEnd ) + for( let i = 0 ; i < genesis.runtime._practiceMap.constructionInitEnd.length ; i++ ) + genesis.runtime._practiceMap.constructionInitEnd[ i ]( genesis ); + + return genesis; +} + +_init.defaults = +{ + constructing : null, + construction : null, + amending : null, + runtime : null, +} + +// + +function _initFields( genesis ) +{ + + _.assert( _.object.isBasic( genesis.construction ) ); + _.assert( _.blueprint.isRuntime( genesis.runtime ) ); + _.assert( arguments.length === 1 ); + _.assert( _.longHas( [ 'extend', 'supplement' ], genesis.amending ) ); + _.assert( _.mapIs( genesis.runtime.propsSupplementation ) ); + + if( genesis.amending === 'extend' ) + _.props.extend( genesis.construction, genesis.runtime.propsExtension ); + else + _.props.supplement( genesis.construction, genesis.runtime.propsExtension ); + + _.props.supplement( genesis.construction, genesis.runtime.propsSupplementation ); + + return genesis.construction; +} + +_initFields.defaults = +{ + construction : null, + runtime : null, + constructing : null, +} + +// + +function _initDefines( genesis ) +{ + + _.assert( _.object.isBasic( genesis.construction ) ); + _.assert( _.blueprint.isRuntime( genesis.runtime ) ); + _.assert( arguments.length === 1 ); + _.assert( _.longHas( [ 'extend', 'supplement' ], genesis.amending ) ); + + if( genesis.runtime._practiceMap.constructionInit ) + for( let i = 0 ; i < genesis.runtime._practiceMap.constructionInit.length ; i++ ) + { + let constructionInit = genesis.runtime._practiceMap.constructionInit[ i ]; + constructionInit( genesis ); + } + + return genesis.construction; +} + +_initDefines.defaults = +{ + construction : null, + runtime : null, + constructing : null, +} + +// + +function _extendArguments( genesis ) +{ + + _.assert( _.object.isBasic( genesis.construction ) ); + _.assert( _.blueprint.isRuntime( genesis.runtime ) ); + _.assert( genesis.args === undefined || _.argumentsArray.like( genesis.args ) ); + _.assert( genesis.args === undefined || genesis.args.length === 0 || genesis.args.length === 1 ); + _.assert( arguments.length === 1 ); + + if( !genesis.args || !genesis.args.length ) + return genesis.construction; + + _.assert( genesis.args.length === 1 ); + + let o = genesis.args[ 0 ]; + if( o === null ) + return genesis.construction; + + _.assert( _.object.isBasic( o ) ); + + if( genesis.construction !== o ) + _.props.extend( genesis.construction, o ); + + return genesis.construction; +} + +_extendArguments.defaults = +{ + construction : null, + args : null, + runtime : null, + constructing : null, +} + +// -- +// class Construction +// -- + +function Construction() +{ +} + +Construction.prototype = Object.create( null ); +Object.freeze( Construction.prototype ); + +// -- +// namespace construction +// -- + +let construction = Object.create( null ); + +var ConstructionExtension = +{ + + isTyped, + isInstanceOf, + + amend, + extend, + supplement, + // _amendDefinitionWithoutMethod, + _amendCant, + + _make2, + _make3, + + _make, + _makeEach, + _from, + _fromEach, + _retype, + _retypeEach, + + _init, + _initFields, + _initDefines, + _extendArguments, + +} + +Object.assign( construction, ConstructionExtension ); + +// -- +// namespace tools +// -- + +var ToolsExtension = +{ + + construction, + Construction, + +} + +_.assert( _.construction === undefined ); + +Object.assign( _, ToolsExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l3/Construction.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Construction_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Construction_s */ })(); + +/* */ /* begin of file Definitions_s */ ( function Definitions_s() { function Definitions_s_naked() { ( function _Definitions_s_() +{ + +'use strict'; + +const Self = _global_.wTools; +const _global = _global_; +const _ = _global_.wTools; + +// + +let PropOptionsLogic = +{ + order : 0, + // before : null, + // after : null, + blueprintDepthLimit : null, + blueprintDepthReserve : 0, + _blueprint : false, +} + +let PropOptionsDescriptor = +{ + static : 0, + enumerable : null, + configurable : null, + writable : null, +} + +let PropOptionsMove = +{ + collection : 'scalar', + insToIns : 'val', + datToIns : 'val', + insToDat : 'val', + datToDat : 'val', + valToIns : 'val', + // relation : null, +} + +let PropOptionsAccessor = +{ + accessor : null, + methods : null, + storingStrategy : 'underscore', + combining : null, + addingMethods : null, + // ... _.accessor.AmethodTypesMap, +} + +// -- +// collection +// -- + +function _singleArgumentHead( routine, args ) +{ + let o = args[ 0 ]; + if( !o ) + o = Object.create( null ); + + o = _.routine.options_( routine, o ); + + _.assert( arguments.length === 2 ); + _.assert( args.length === 0 || args.length === 1, () => `Expects optional argument, but got ${args.length} arguments` ); + _.assert( _.mapIs( o ) ); + + return o; +} + +// + +function _pairArgumentsHead( routine, args ) +{ + let o = args[ 1 ]; + + if( o ) + o.val = args[ 0 ]; + else + o = { val : args[ 0 ] }; + + o = _.routine.options_( routine, o ); + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + _.assert( args[ 1 ] === undefined || _.mapIs( args[ 1 ] ) ); + + return o; +} + +// + +let _toVal = Object.create( null ); +_toVal.val = function val( val ) { return val } +_toVal.shallow = function shallow( val ) { return _.entity.cloneShallow( val ) } +// _toVal.deep = function deep( val ) { return _.entity.cloneDeep({ src : val }) } +_toVal.deep = function deep( val ) { return _.entity.cloneDeep( val ) } +_toVal.call = function call( val ) { return val() } +_toVal.new = function nw( val ) { return new val() } + +// + +function prop_head( routine, args ) +{ + let o = args[ 1 ]; + + if( !o ) + o = { val : args[ 0 ] }; + else if( args[ 0 ] !== undefined ) + o.val = args[ 0 ]; + + if( _.boolLike( o.accessor ) ) + o.accessor = !!o.accessor; + + o.accessor = _.accessor.suiteMove( o.accessor, o ) || routine.defaults.accessor; + + o = _.routine.options_( routine, o ); + + if( _.boolLike( o.writable ) ) + o.writable = !!o.writable; + if( o.configurable === null ) + o.configurable = true; + else + o.configurable = !!o.configurable; + + if( o.enumerable === null ) + o.enumerable = !o.static; + else + o.enumerable = !!o.enumerable; + + if( o.static === null ) + o.static = false; + else if( _.boolLike( o.static ) ) + o.static = !!o.static; + + if( o.blueprintDepthLimit === null ) + o.blueprintDepthLimit = o.static ? 1 : 0; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + _.assert( args[ 1 ] === undefined || _.mapIs( args[ 1 ] ) ); + + _.assert( _.mapIs( o ) ); + + _.assert( _.strIs( o.valToIns ) ); + _.assert( _.longHas( [ 'scalar', 'map', 'enumerable' ], o.collection ) ); + _.assert( 'scalar' === o.collection, 'not implemented' ); /* zzz : implement */ + _.assert( _.longHas( [ 'no', 'val', 'shallow', 'deep', 'call', 'new' ], o.valToIns ) ); + + _.assert( o.collection === 'scalar', 'not implemented' ); + _.assert( o.insToIns === 'val', 'not implemented' ); + _.assert( o.datToIns === 'val', 'not implemented' ); + _.assert( o.insToDat === 'val', 'not implemented' ); + _.assert( o.datToDat === 'val', 'not implemented' ); + + _.assert( o.blueprintDepthLimit >= 0 ); + _.assert( _.boolIs( o.writable ) || o.writable === null ); + _.assert( _.boolIs( o.configurable ) ); + _.assert( _.boolIs( o.enumerable ) ); + _.assert( _.fuzzyIs( o.static ) ); + + return o; +} + +// + +function prop_body( o ) +{ + + _.map.assertHasAll( o, prop_body.defaults ); + _.assert( o.val !== undefined ); + _.assert( o.blueprintDepthLimit >= 0 ); + _.assert( _.boolIs( o.writable ) || o.writable === null ); + _.assert( _.boolIs( o.configurable ) ); + _.assert( _.boolIs( o.enumerable ) ); + _.assert( o._blueprint !== undefined ); + + const toVal = o.toVal = _toVal[ o.valToIns ]; + _.assert( _.routineIs( toVal ), () => `Unknown toVal::${o.valToIns} )` ); + + o.blueprintForm1 = blueprintForm1; + o.blueprintForm2 = blueprintForm2; + o.kind = 'prop'; + return _.definition._namedMake( o ); + + /* - + +- blueprintForm2 +- declareStaticWithAccessor +- declareStaticWithoutAccessor +- declareWithAccessor +- declareOrdinary +- declareUnordinary +- valFrom + + */ + + function blueprintForm1( op ) + { + _.assert( _.strDefined( op.propName ) || _.strDefined( op.definition.name ) ); + _.assert( op.propName === null || op.propName === op.definition.name ); + Object.freeze( op.definition ); + } + + function blueprintForm2( op ) + { + + _.assert( _.strDefined( op.propName ) || _.strDefined( op.definition.name ) ); + _.assert( op.propName === null || op.propName === op.definition.name ); + + if( op.definition.static ) + { + let op2 = + { + definition : op.definition, + blueprint : op.blueprint, + name : op.propName, + amending : op.amending, + } + if( op.definition.accessor ) + declareStaticWithAccessor( op2 ); + else + declareStaticWithoutAccessor( op2 ); + + if( op.definition.static !== _.maybe ) + return; + if( op.blueprint.traitsMap.typed.val === true ) + return; + } + + if( op.definition.accessor ) + { + declareWithAccessor( op.blueprint, op.definition ); + } + else if + ( + op.definition.static === true + && op.definition.valToIns === 'val' + && op.definition.enumerable + && op.definition.configurable + && ( op.definition.writable || op.definition.writable === null ) + ) + { + if( op.definition.val === _.nothing ) + op.blueprint.propsSupplementation[ op.propName ] = undefined; + else + op.blueprint.propsExtension[ op.propName ] = _.escape.right( op.definition.val ); + } + else if + ( + op.definition.enumerable && op.definition.configurable && ( op.definition.writable || op.definition.writable === null ) + ) + { + declareOrdinary( op.blueprint, op.definition ); + } + else + { + declareUnordinary( op.blueprint, op.definition ); + } + + } + + /* */ + + function declareStaticWithAccessor( op ) + { + const prototype = op.blueprint.prototype; + const name = op.name; + const val = op.definition.val; + + if( prototype === null ) + return op.blueprint; + + let opts = + { + enumerable : op.definition.enumerable, + configurable : op.definition.configurable, + }; + + _.assert( _.boolIs( op.definition.configurable ) ); + _.assert( _.boolIs( op.definition.enumerable ) ); + _.assert( !_.boolLikeFalse( op.definition.accessor ) ); + _.assert( !_.prototype._ofStandardEntity( prototype ), 'Attempt to pollute _global_.Object.prototype' ); + + // if( _global_.debugger ) + // debugger; + + let val2 = valFrom( prototype, name, op.amending, val ); + + let op2 = + { + name : op.name, + object : prototype, + methods : op.definition.methods, + suite : op.definition.accessor, + val : val2, + storingStrategy : op.definition.storingStrategy, + enumerable : op.definition.enumerable, + configurable : op.definition.configurable, + writable : op.definition.writable, + combining : op.definition.combining, + addingMethods : op.definition.addingMethods, + } + + op2.needed = _.accessor._declaringIsNeeded( op2 ); + if( op2.needed ) + { + _.accessor.suiteNormalize( op2 ); + for( let mname in _.accessor.AmethodTypesMap ) + if( op2.normalizedAsuite[ mname ] ) + op2.normalizedAsuite[ mname ] = _.routineJoin( prototype, op2.normalizedAsuite[ mname ] ); + _.accessor.declareSingle.body( op2 ); + } + + opts.get = () => + { + return prototype[ name ]; + } + + if( op.definition.writable || op.definition.writable === null ) + { + opts.set = ( src ) => + { + prototype[ name ] = src; + } + } + + Object.defineProperty( op.blueprint.make, name, opts ); + + return op.blueprint; + } + + /* */ + + function declareStaticWithoutAccessor( op ) + { + const prototype = op.blueprint.prototype; + const name = op.name; + const enumerable = op.definition.enumerable; + const configurable = op.definition.configurable; + const writable = op.definition.writable; + const toVal = op.definition.toVal; + const val = op.definition.val; + + let opts = + { + enumerable, + configurable, + }; + + _.assert( _.boolIs( op.definition.configurable ) ); + _.assert( _.boolIs( op.definition.enumerable ) ); + _.assert( !_.prototype._ofStandardEntity( prototype ), 'Attempt to pollute _global_.Object.prototype' ); + + // if( _global_.debugger ) + // debugger; + + if( prototype ) + { + let val2 = _.escape.right( valFrom( prototype, name, op.amending, val ) ); + + if( op.definition.writable || op.definition.writable === null ) + { + opts.get = () => + { + return val2; + } + opts.set = ( src ) => + { + val2 = src; + return src; + } + } + else + { + opts.writable = false; + opts.value = val2; + } + Object.defineProperty( op.blueprint.make, name, opts ); + if( prototype !== null ) + Object.defineProperty( prototype, name, opts ); + } + + return op.blueprint; + } + + /* */ + + function declareWithAccessor( blueprint, definition ) + { + const toVal = definition.toVal; + const name = definition.name; + const methods = definition.methods; + const storingStrategy = definition.storingStrategy; + const enumerable = definition.enumerable; + const configurable = definition.configurable; + const writable = definition.writable; + const combining = definition.combining; + const addingMethods = definition.addingMethods; + const accessor = definition.accessor; + const val = definition.val; + const isStatic = definition.static; + const prototype = blueprint.prototype; + let op2, normalizedAsuite; + + _.assert( _.fuzzyIs( blueprint.typed ) ); + + // if( _global_.debugger ) + // debugger; + + if( !isStatic && blueprint.traitsMap.typed.val && blueprint.prototype ) + { + op2 = _.accessor.declareSingle + ({ + name, + object : blueprint.prototype, + methods, + suite : accessor ? _.props.extend( null, accessor ) : false, + storingStrategy, + storageIniting : true, + valueGetting : false, + valueSetting : false, + enumerable, + configurable, + writable, + combining, + addingMethods, + }); + normalizedAsuite = op2.normalizedAsuite; + } + + let constructionInit; + if( isStatic ) + constructionInit = constructionInitUntypedStatic; + else if( blueprint.traitsMap.typed.val === _.maybe ) + constructionInit = constructionInitMaybe; + else if( blueprint.traitsMap.typed.val === true && blueprint.prototype ) + constructionInit = constructionInitTyped; + else if + ( + blueprint.traitsMap.typed.val === false + || blueprint.prototype === null + || blueprint.traitsMap.typed.val + && !blueprint.prototype + ) + constructionInit = constructionInitUntyped; + else _.assert( 0 ); + + _.blueprint._practiceAdd( blueprint, 'constructionInit', constructionInit ); + + function constructionInitTyped( genesis ) + { + // if( _global_.debugger ) + // debugger; + _.accessor._objectInitStorage( genesis.construction, normalizedAsuite ); + + let val2 = valFrom( genesis.construction, name, genesis.amending, val ); + if( val2 !== _.nothing ) + _.accessor._objectSetValue + ({ + object : genesis.construction, + normalizedAsuite, + storingStrategy, + name, + val : val2, + }); + + } + + function constructionInitUntyped( genesis ) + { + // if( _global_.debugger ) + // debugger; + + let val2 = valFrom( genesis.construction, name, genesis.amending, val ); + _.accessor.declareSingle + ({ + object : genesis.construction, + methods, + suite : accessor ? _.props.extend( null, accessor ) : false, + storingStrategy, + name, + val : val2, + enumerable, + configurable, + writable, + combining, + addingMethods, + }); + } + + function constructionInitUntypedStatic( genesis ) + { + // if( _global_.debugger ) + // debugger; + + let prototype2 = Object.getPrototypeOf( genesis.construction ); + if( prototype2 && prototype2 === prototype ) + return; + + let val2 = valFrom( genesis.construction, name, genesis.amending, val ); + _.accessor.declareSingle + ({ + object : genesis.construction, + methods, + suite : accessor ? _.props.extend( null, accessor ) : false, + storingStrategy, + name, + val : val2, + enumerable, + configurable, + writable, + combining, + addingMethods, + }); + } + + function constructionInitMaybe( genesis ) + { + // if( _global_.debugger ) + // debugger; + if( prototype === null ) + { + constructionInitUntyped( genesis ); + return; + } + let prototype2 = Object.getPrototypeOf( genesis.construction ); + if( prototype2 === prototype ) + { + constructionInitTyped( genesis ); + } + else + { + constructionInitUntyped( genesis ); + } + } + + } + + /* */ + + function declareOrdinary( blueprint, definition ) + { + const toVal = definition.toVal; + const name = definition.name; + const isStatic = definition.static; + const prototype = blueprint.prototype; + const val = definition.val; + + _.blueprint._practiceAdd( blueprint, 'constructionInit', constructionInit ); + + function constructionInit( genesis ) + { + // if( _global_.debugger ) + // debugger; + + if( isStatic ) + { + let prototype2 = Object.getPrototypeOf( genesis.construction ); + if( prototype2 && prototype2 === prototype ) + return; + } + + let val2 = _.escape.right( valFrom( genesis.construction, name, genesis.amending, val ) ); + /* it is important to set even if value as it was before setting. property could be owned by prototype */ + genesis.construction[ name ] = val2; + } + } + + /* */ + + function declareUnordinary( blueprint, definition ) + { + const enumerable = definition.enumerable; + const configurable = definition.configurable; + const writable = definition.writable === null ? true : definition.writable; + const toVal = definition.toVal; + const name = definition.name; + const isStatic = definition.static; + const val = definition.val; + const prototype = blueprint.prototype; + + _.blueprint._practiceAdd( blueprint, 'constructionInit', constructionInit ); + + function constructionInit( genesis ) + { + // if( _global_.debugger ) + // debugger; + + if( isStatic ) + { + let prototype2 = Object.getPrototypeOf( genesis.construction ); + if( prototype2 && prototype2 === prototype ) + return; + } + + const opts = + { + enumerable, + configurable, + writable, + }; + + let val2 = _.escape.right( valFrom( genesis.construction, name, genesis.amending, val ) ); + opts.value = val2; + Object.defineProperty( genesis.construction, name, opts ); + } + } + + /* */ + + function valFrom( /* object, name, amending, val */ ) + { + let object = arguments[ 0 ]; + let name = arguments[ 1 ]; + let amending = arguments[ 2 ]; + let val = arguments[ 3 ]; + let val2; + if( amending === 'supplement' && Object.hasOwnProperty.call( object, name ) ) + { + val2 = _.escape.left( object[ name ] ); + } + else if( val === _.nothing ) + { + if( Object.hasOwnProperty.call( object, name ) ) + { + val2 = _.escape.left( object[ name ] ); + } + else /* keep nothing for declareSingle */ + { + val2 = _.nothing; + } + } + else + { + val2 = _.escape.left( toVal( _.escape.right( val ) ) ); + } + return val2; + } + + /* */ + +} + +prop_body.defaults = +{ + + ... PropOptionsLogic, + /* + order : 0, + // before : null, + // after : null, + blueprintDepthLimit : null, + blueprintDepthReserve : 0, + _blueprint : false, + */ + + ... PropOptionsDescriptor, + /* + static : 0, + enumerable : null, + configurable : null, + writable : null, + */ + + ... PropOptionsMove, + /* + collection : 'scalar', + insToIns : 'val', + datToIns : 'val', + insToDat : 'val', + datToDat : 'val', + valToIns : 'val', + // relation : null, + */ + + ... PropOptionsAccessor, + /* + accessor : null, + methods : null, + storingStrategy : 'underscore', + // grab : null, + // get : null, + // put : null, + // set : null, + */ + + name : null, + val : _.nothing, + _blueprint : null, + +} + +prop_body.identity = { definition : true, named : true }; + +let prop = _.routine.uniteCloning_replaceByUnite( prop_head, prop_body ); +_.routine.er( prop, _singleArgumentHead ); + +/* +| | Composes | Aggregates | Associates | Restricts | Medials | Statics | +| -------------- |:--------:|:----------:|:-----------:|:-----------:|:---------:|:-----------:| +| Static | | | | | | + | +| Ins to Ins | deep | val | val | - | - | | +| Dat to Ins | deep | deep | val | - | val | | +| Ins to Dat | deep | deep | val | - | - | | +| Dat to Dat | deep | deep | val | - | val | | +*/ + +/* +order : [ -10 .. +10 ] @default : 0 +static : [ 0 , 1 ] @default : 0 +enumerable : [ 0 , 1 ] @default : 1 +configurable : [ 0 , 1 ] @default : 1 +writable : [ 0 , 1 ] @default : 1 +toVal : routine @default : null +collection : [ scalar , array , map ] @default : scalar +insToIns : [ val , shallow , deep ] @default : val +datToIns : [ val , shallow , deep ] @default : val +insToDat : [ val , shallow , deep ] @default : val +datToDat : [ val , shallow , deep ] @default : val +valToIns : [ val , shallow , deep , call , new ] @default : val +relation : [ null , composes , aggregates , associates , restricts , medials , statics , copiers ] @default : null +val : * @default : null +*/ + +// + +function props_body( o ) +{ + let self = this; + + if( _.longIs( o.val ) ) + { + return _.container.map_( o.val, ( e ) => mapEach( e ) ); + } + else + { + return mapEach( o.val ); + } + + function mapEach( map ) + { + _.assert( _.mapIs( map ) ); + let r = _.container.map_( map, ( e, k ) => + { + let o2 = _.props.extend( null, o ); + o2.val = e; + _.assert( o2.name === null ); + o2.name = k; + let r = _.define.prop.body.call( self, o2 ); + _.assert( r.name === k ); + return r; + }); + r = _.props.vals( r ); + return r; + } + +} + +props_body.defaults = +{ + ... prop.defaults, +} + +let props = _.routine.uniteCloning_replaceByUnite( prop_head, props_body ); +props.identity = _.props.extend( null, prop.identity ); +props.identity.named = false; +_.routine.er( props, _singleArgumentHead ); + +// + +function val_body( o ) +{ + return _.define.prop.body.call( this, o ); +} + +val_body.defaults = +{ + ... prop.defaults, + valToIns : 'val', +} + +let val = _.routine.uniteCloning_replaceByUnite( prop_head, val_body ); +val.identity = _.props.extend( null, prop.identity ); +_.routine.er( val, _singleArgumentHead ); + +// + +function vals_body( o ) +{ + return _.define.props.body.call( this, o ); +} + +vals_body.defaults = +{ + ... prop.defaults, + valToIns : 'val', +} + +let vals = _.routine.uniteCloning_replaceByUnite( prop_head, vals_body ); +vals.identity = _.props.extend( null, val.identity ); +vals.identity.named = false; +_.routine.er( vals, _singleArgumentHead ); + +// + +function shallow_body( o ) +{ + return _.define.prop.body.call( this, o ); +} + +shallow_body.defaults = +{ + ... prop.defaults, + valToIns : 'shallow', +} + +let shallow = _.routine.uniteCloning_replaceByUnite( prop_head, shallow_body ); +shallow.identity = _.props.extend( null, prop.identity ); +_.routine.er( shallow, _singleArgumentHead ); + +// + +function shallows_body( o ) +{ + return _.define.props.body.call( this, o ); +} + +shallows_body.defaults = +{ + ... prop.defaults, + valToIns : 'shallow', +} + +let shallows = _.routine.uniteCloning_replaceByUnite( prop_head, shallows_body ); +shallows.identity = _.props.extend( null, shallow.identity ); +shallows.identity.named = false; +_.routine.er( shallows, _singleArgumentHead ); + +// + +function deep_body( o ) +{ + return _.define.prop.body.call( this, o ); +} + +deep_body.defaults = +{ + ... prop.defaults, + valToIns : 'deep', +} + +let deep = _.routine.uniteCloning_replaceByUnite( prop_head, deep_body ); +deep.identity = _.props.extend( null, prop.identity ); +_.routine.er( deep, _singleArgumentHead ); + +// + +function deeps_body( o ) +{ + return _.define.props.body.call( this, o ); +} + +deeps_body.defaults = +{ + ... prop.defaults, + valToIns : 'deep', +} + +let deeps = _.routine.uniteCloning_replaceByUnite( prop_head, deeps_body ); +deeps.identity = _.props.extend( null, deep.identity ); +deeps.identity.named = false; +_.routine.er( deeps, _singleArgumentHead ); + +// + +function call_body( o ) +{ + return _.define.prop.body.call( this, o ); +} + +call_body.defaults = +{ + ... prop.defaults, + valToIns : 'call', +} + +let call = _.routine.uniteCloning_replaceByUnite( prop_head, call_body ); +call.identity = _.props.extend( null, prop.identity ); +_.routine.er( call, _singleArgumentHead ); + +// + +function calls_body( o ) +{ + return _.define.props.body.call( this, o ); +} + +calls_body.defaults = +{ + ... prop.defaults, + valToIns : 'call', +} + +let calls = _.routine.uniteCloning_replaceByUnite( prop_head, calls_body ); +calls.identity = _.props.extend( null, call.identity ); +calls.identity.named = false; +_.routine.er( calls, _singleArgumentHead ); + +// + +function new_body( o ) +{ + return _.define.prop.body.call( this, o ); +} + +new_body.defaults = +{ + ... prop.defaults, + valToIns : 'new', +} + +let _new = _.routine.uniteCloning_replaceByUnite( prop_head, new_body ); +_new.identity = _.props.extend( null, prop.identity ); +_.routine.er( _new, _singleArgumentHead ); + +// + +function news_body( o ) +{ + return _.define.props.body.call( this, o ); +} + +news_body.defaults = +{ + ... prop.defaults, + valToIns : 'new', +} + +let _news = _.routine.uniteCloning_replaceByUnite( prop_head, news_body ); +_news.identity = _.props.extend( null, _new.identity ); +_news.identity.named = false; +_.routine.er( _news, _singleArgumentHead ); + +// + +function static_body( o ) +{ + return _.define.prop.body.call( this, o ); +} + +static_body.defaults = +{ + ... prop.defaults, + static : 1, +} + +let _static = _.routine.uniteCloning_replaceByUnite( prop_head, static_body ); +_static.identity = _.props.extend( null, prop.identity ); +_.routine.er( _static, _singleArgumentHead ); + +// + +function statics_body( o ) +{ + return _.define.props.body.call( this, o ); +} + +statics_body.defaults = +{ + ... prop.defaults, + static : 1, +} + +let _statics = _.routine.uniteCloning_replaceByUnite( prop_head, statics_body ); +_statics.identity = _.props.extend( null, _static.identity ); +_statics.identity.named = false; +_.routine.er( _statics, _singleArgumentHead ); + +// + +function alias_head( routine, args ) +{ + let o = args[ 0 ]; + + if( !_.mapIs( args[ 0 ] ) ) + o = { originalName : args[ 0 ] }; + + _.assert( args.length === 1 ); + + return _.define.prop.head( routine, [ undefined, o ] ); +} + +function alias_body( o ) +{ + + _.routine.assertOptions( alias_body, arguments ); + + let originalContainer = o.originalContainer; + let originalName = o.originalName; + + _.assert( originalContainer === null || !!originalContainer ); + _.assert( _.strDefined( originalName ), 'Expects defined `originalName`' ); + _.assert( o.val === undefined ); + _.assert( o.accessor === null || _.boolLikeTrue( o.accessor ) || _.mapIs( o.accessor ) ); + + if( !_.mapIs( o.accessor ) ) + o.accessor = Object.create( null ); + + if( originalContainer === null ) + { + let accessor2 = { grab : selfGet, get : selfGet, put : selfSet, set : selfSet } + _.accessor.suiteSupplement( o.accessor, accessor2 ); + } + else + { + let accessor2 = { grab : get, get, put : set, set } + _.accessor.suiteSupplement( o.accessor, accessor2 ); + } + + o.val = _.nothing; + _.props.supplement( o, _.define.prop.defaults ); + return _.define.prop.body( o ); + + /* */ + + function get() + { + return originalContainer[ originalName ]; + } + + function set( src ) + { + originalContainer[ originalName ] = src; + return originalContainer[ originalName ]; + } + + function selfGet() + { + return this[ originalName ]; + } + + function selfSet( src ) + { + this[ originalName ] = src; + return this[ originalName ]; + } + +} + +alias_body.defaults = +{ + ... _.mapBut_( null, prop.defaults, { methods : null, val : null } ), + originalContainer : null, + originalName : null, +} + +let alias = _.routine.uniteCloning_replaceByUnite( alias_head, alias_body ); +alias.identity = _.props.extend( null, prop.identity ); +_.routine.er( alias ); + +/* xxx : implement definition::aliases */ + +// -- +// +// -- + +function nothing_functor() +{ + + nothing_body.identity = { definition : true, named : false }; + nothing_body.defaults = + { + ... PropOptionsLogic, + blueprintDepthReserve : -1, + blueprintDepthLimit : 1, + _blueprint : false, + } + + let prototype = Object.create( null ); + prototype.defGroup = 'definition.unnamed'; + prototype.kind = 'nothing'; + prototype.name = null; + _.props.extend( prototype, nothing_body.defaults ); + prototype.blueprintDefinitionRewrite = blueprintDefinitionRewrite; + _.definition.retype( prototype ); + Object.freeze( prototype ); + + let nothing = _.routine.uniteCloning_replaceByUnite( _head, nothing_body ); + return nothing; + + /* */ + + function _head( routine, args ) + { + let o = args[ 0 ]; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 0 || args.length === 1, () => `Expects optional argument, but got ${args.length} arguments` ); + _.assert( o === undefined || _.mapIs( o ) ); + + if( !o ) + return prototype; + + _.map.assertHasOnly( o, routine.defaults ); + return o; + } + + /* */ + + function nothing_body( o ) + { + if( o === prototype ) + return prototype; + _.assert( o === undefined || _.mapIs( o ) || Object.getPrototypeOf( o ) === prototype ); + if( Object.getPrototypeOf( o ) !== prototype ) + Object.setPrototypeOf( o, prototype ); + Object.freeze( o ); + _.assert( arguments.length === 1 ); + return o; + } + + /* */ + + function blueprintDefinitionRewrite( op ) + { + } + + /* */ + +} + +let nothing = nothing_functor(); + +// function nothing_body( o ) +// { +// +// _.routine.assertOptions( nothing_body, arguments ); +// o.defGroup = 'definition.unnamed'; +// o.blueprintDefinitionRewrite = blueprintDefinitionRewrite; +// o.kind = 'nothing'; +// return _.definition._unnamedMake( o ); +// +// function blueprintDefinitionRewrite( op ) +// { +// } +// +// } +// +// nothing_body.defaults = +// { +// ... PropOptionsLogic, +// blueprintDepthReserve : -1, +// blueprintDepthLimit : 1, +// _blueprint : false, +// } +// +// nothing_body.identity = { definition : true, named : false }; +// +// let nothing = _.routine.uniteCloning_replaceByUnite( _singleArgumentHead, nothing_body ); + +// + +function _constant_functor() +{ + /* xxx : use predefined object for other definitions to optimize */ + + let prototype = Object.create( null ); + prototype.defGroup = 'definition.named'; + prototype.kind = 'constant'; + prototype.subKind = 'constant'; + prototype.asAccessorSuite = asAccessorSuite; + prototype.toVal = toVal; + prototype.blueprintForm1 = blueprintForm1; + prototype.blueprintForm2 = blueprintForm2; + _.definition.retype( prototype ); + Object.freeze( prototype ); + + let r = + { + 'constant' : function( val ) + { + return _constant( val ); + } + } + + r.constant.identity = { definition : true, named : true }; + return r.constant; + + /* */ + + function _constant( val ) + { + let definition = Object.create( prototype ); + definition.val = val; + definition.name = null; + definition._blueprint = null; + Object.preventExtensions( definition ); + _.assert( arguments.length === 1 ); + _.assert( definition.val !== undefined ); + return definition; + } + + /* */ + + function blueprintForm1( op ) + { + const val = op.definition.val; + const name = op.definition.name; + _.assert( _.strDefined( op.propName ) || _.strDefined( op.definition.name ) ); + _.assert( op.propName === null || op.propName === op.definition.name ); + Object.freeze( op.definition ); + } + + /* */ + + function blueprintForm2( op ) + { + const val = op.definition.val; + const name = op.definition.name; + + _.blueprint._practiceAdd( op.blueprint, 'constructionInit', constructionInitUntyped ); + + function constructionInitUntyped( genesis ) + { + // if( _global_.debugger ) + // debugger; + + let val2 = val; + + let opts = + { + enumerable : false, + configurable : false, + writable : false, + value : val2, + }; + + Object.defineProperty( genesis.construction, name, opts ); + } + + } + + /* */ + + function asAccessorSuite( op ) + { + _.assert( _.definitionIs( op.amethod ) ); + return { get : op.amethod, set : false, put : false }; + } + + /* */ + + function toVal( val ) + { + _.assert( val !== undefined ); + return val; + } + + /* */ + +} + +let _constant = _constant_functor(); + +// + +function _amendment_head( routine, args ) +{ + let o = _pairArgumentsHead( ... arguments ); + _.assert( _.longHas( [ 'extend', 'supplement' ], o.amending ) ); + return o; +} + +function _amendment_body( o ) +{ + + _.routine.assertOptions( _amendment_body, arguments ); + _.assert( _.object.isBasic( o.val ) ); + _.assert( _.blueprintIsDefinitive( o.val ) ); + o.defGroup = 'definition.unnamed'; + o.kind = 'amend'; + o.blueprintDefinitionRewrite = blueprintDefinitionRewrite; + return _.definition._unnamedMake( o ); + + function blueprintDefinitionRewrite( op ) + { + let definition = op.definition; + let blueprint = op.blueprint; + return _.blueprint._amend + ({ + blueprint : op.blueprint, + blueprintDepth : op.blueprintDepth, + extension : definition.val, + amending : op.amending === 'extend' ? definition.amending : op.amending, + blueprintComposing : 'amend', + blueprintDepthReserve : definition.blueprintDepthReserve + op.blueprintDepthReserve, + }); + } + +} + +_amendment_body.defaults = +{ + amending : null, + val : null, + blueprintDepthReserve : 0, + blueprintDepthLimit : 1, + _blueprint : false, +} + +_amendment_body.identity = { definition : true, named : false }; + +let _amendment = _.routine.uniteCloning_replaceByUnite( _amendment_head, _amendment_body ); + +// + +let extension = _.routine.uniteCloning_replaceByUnite({ head : _amendment_head, body : _amendment_body, name : 'extension' }); + +extension.defaults = +{ + ... _amendment.defaults, + amending : 'extend', +} + +_.assert( !!extension.identity.definition ); +_.assert( !extension.identity.anemd ); + +_.routine.er( extension, _singleArgumentHead ); + +// + +let supplementation = _.routine.uniteCloning_replaceByUnite({ head : _amendment_head, body : _amendment_body, name : 'supplementation' }); + +supplementation.defaults = +{ + ... _amendment.defaults, + amending : 'supplement', +} + +_.routine.er( supplementation, _singleArgumentHead ); + +// + +function inherit_body( o ) +{ + + _.routine.assertOptions( inherit_body, arguments ); + _.assert( _.object.isBasic( o.val ) ); + _.assert( _.blueprintIsDefinitive( o.val ) ); + o.defGroup = 'definition.unnamed'; + o.kind = 'inherit'; + o.blueprintDefinitionRewrite = blueprintDefinitionRewrite; + o._blueprint = false; + return _.definition._unnamedMake( o ); + + /* */ + + function blueprintDefinitionRewrite( op ) + { + _.assert( !op.primeDefinition || !op.secondaryDefinition, 'not tested' ); + let definition = op.primeDefinition || op.secondaryDefinition; + let blueprint = op.blueprint; + let add = op.amending === 'supplement' ? 'unshift' : 'push'; + + // if( _global_.debugger ) + // debugger; + + let result = []; + result[ add ]( definition.val ); + let prototype = null; + if( definition.val.prototype ) + prototype = definition.val; + + if( definition.val.traitsMap.typed ) + { + if( prototype ) + result[ add ]( _.trait.typed( definition.val.traitsMap.typed.val || true, { prototype, new : true, _synthetic : true } ) ); + else + result[ add ] + ( + _.trait.typed + ( + definition.val.traitsMap.typed.val, { prototype : definition.val.traitsMap.typed.prototype, _synthetic : true } + ) + ); + } + + return _.blueprint._amend + ({ + blueprint : op.blueprint, + blueprintDepth : op.blueprintDepth, + extension : result, + amending : op.amending, + blueprintComposing : 'amend', + blueprintDepthReserve : ( definition.blueprintDepthReserve || 0 ) + op.blueprintDepthReserve, + }); + } + +} + +inherit_body.defaults = +{ + val : null, +} + +inherit_body.identity = { definition : true, named : false }; + +let inherit = _.routine.uniteCloning_replaceByUnite( _pairArgumentsHead, inherit_body ); + +// -- +// +// -- + +let DefinitionExtension = +{ + PropOptionsLogic, + PropOptionsDescriptor, + PropOptionsMove, + PropOptionsAccessor, +} + +/* _.props.extend */Object.assign( _.definition, DefinitionExtension ); + +let BlueprintExtension = +{ + + _singleArgumentHead, + _pairArgumentsHead, + _toVal, + +} + +_.blueprint = _.blueprint || Object.create( null ); +/* _.props.extend */Object.assign( _.blueprint, BlueprintExtension ); + +let DefineExtension = +{ + + prop, + props, + val, + vals, + shallow, + shallows, + deep, + deeps, + call, + calls, + new : _new, + news : _news, + static : _static, + statics : _statics, + alias, + + nothing, + constant : _constant, + + _amendment, + extension, + supplementation, + inherit, + + +} + +_.define = _.define || Object.create( null ); +_.definition.extend( DefineExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l3/Definitions.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Definitions_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Definitions_s */ })(); + +/* */ /* begin of file Traits_s */ ( function Traits_s() { function Traits_s_naked() { ( function _Traits_s_() +{ + +'use strict'; + +const Self = _global_.wTools; +const _global = _global_; +const _ = _global_.wTools; + +let Definition = _.Definition; +_.routineIs( Definition ); + +// -- +// implementation +// -- + +function _pairArgumentsHead( routine, args ) +{ + let o = args[ 1 ]; + + if( o ) + o.val = args[ 0 ]; + else + o = { val : args[ 0 ] }; + + o = _.routine.options_( routine, o ); + + _.assert( arguments.length === 2 ); + _.assert( args.length === 0 || args.length === 1 || args.length === 2 ); + _.assert( args[ 1 ] === undefined || _.mapIs( args[ 1 ] ) ); + + return o; +} + +// + +function callable( o ) +{ + if( !_.mapIs( o ) ) + o = { callback : arguments[ 0 ] }; + _.routine.options_( callable, o ); + _.assert( arguments.length === 1 ); + _.assert( _.routineIs( o.callback ) ); + o.kind = 'callable'; + return _.definition._traitMake( o ); + // return _.definition._traitMake( 'callable', o ); +} + +callable.defaults = +{ + callback : null, + _blueprint : false, +} + +callable.identity = { definition : true, trait : true, enabled : false }; + +// + +/* + +== typed:0 + +prototype:0 +preserve prototype of the map, but change if not map to pure map + +prototype:1 +change prototype to null + +prototype:null +change prototype to null + +prototype:object +throw error + +== typed:1 + +prototype:0 +preserve prototype of typed destination, but change if it is map + +prototype:1 +set generated prototype + +prototype:null +throw error + +prototype:object +set custom prototype + +== typed:maybe + +prototype:0 +preserve prototype of typed destination +preserve as map if untyped destination +create typed + +prototype:1 +set generated prototype if destination is typed +change prototype to null if untyped +create typed + +prototype:null +preserve prototype if typed +set prototype to null if untyped +create untyped + +prototype:object +set custom prototype if typed +preserve if untyped +create typed + +*/ + +function typed_head( routine, args ) +{ + let o = args[ 1 ]; + + if( _.mapIs( args[ 0 ] ) ) + { + o = args[ 0 ]; + _.assert( args.length === 1 ); + } + else if( o ) + { + o.val = args[ 0 ]; + } + else + { + if( args.length > 0 ) + o = { val : args[ 0 ] }; + else + o = {}; + } + + o = _.routine.options_( routine, o ); + + _.assert( arguments.length === 2 ); + _.assert( args.length === 0 || args.length === 1 || args.length === 2 ); + _.assert( args[ 1 ] === undefined || _.mapIs( args[ 1 ] ) ); + + return o; +} + +function typed_body( o ) +{ + _.routine.options_( typed_body, o ); + + if( !_.mapIs( o ) ) + o = arguments.length > 0 ? { val : arguments[ 0 ] } : {}; + _.routine.optionsWithoutUndefined( typed, o ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( _.boolLike( o.val ) ) + o.val = !!o.val; + if( _.boolLike( o.new ) ) + o.new = !!o.new; + if( _.boolLike( o.prototype ) ) + o.prototype = !!o.prototype; + + _.assert( _.fuzzyIs( o.val ), () => `Expects fuzzy-like argument, but got ${_.entity.strType( o.val )}` ); + _.assert + ( + o.new === _.nothing || _.boolIs( o.new ), + () => `Expects bool-like option::new, but got ${_.entity.strType( o.new )}` + ); + _.assert + ( + o.val !== false || _.primitiveIs( o.prototype ) + , () => `Trait::typed should be either not false or prototype should be [ true, false, null ]` + + `, it is ${_.entity.strType( o.prototype )}` + ); + _.assert( o.prototype !== null || o.val !== true, 'Object with null prototype cant be typed' ); + + o.blueprintDefinitionRewrite = blueprintDefinitionRewrite; + o.blueprintForm1 = blueprintForm1; + o.blueprintForm2 = blueprintForm2; + + let allocate, retype; + + o.kind = 'typed'; + return _.definition._traitMake( o ); + +/* - + +- blueprintDefinitionRewrite +- bluprintDefinitionSupplement +- bluprintDefinitionSupplementAct +- definitionRewritePrototype +- canRewritePrototype +- blueprintForm1 +- blueprintForm2 +- allocateTyped +- allocateUntyped +- retypeMaybe +- retypeTyped +- retypeUntypedPreserving +- retypeUntypedForcing +- retypeToMap + +*/ + + /* */ + + function blueprintDefinitionRewrite( op ) + { + _.assert( !op.primeDefinition || !op.secondaryDefinition || op.primeDefinition.kind === op.secondaryDefinition.kind ); + + if( op.primeDefinition && op.secondaryDefinition ) + bluprintDefinitionSupplement( op ); + + if( op.primeDefinition && op.secondaryDefinition && !_.boolIs( op.secondaryDefinition._synthetic ) ) + { + + // if( _global_.debugger ) + // debugger; + _.assert( _.boolIs( op.primeDefinition._synthetic ) ); + + let prototype = _.prototype.of( op.secondaryDefinition._synthetic ); + let definition = op.primeDefinition + + _.assert( definition._blueprint === op.blueprint || definition._blueprint === null, 'not tested' ) + if( definition._blueprint !== op.blueprint && definition._blueprint !== null ) + definition.cloneShallow(); + definition._blueprint = op.blueprint; + + if( op.primeDefinition.val === true && op.primeDefinition.prototype === _.nothing ) + definition.prototype = true; + + if + ( + prototype + && prototype !== Object.prototype + && op.primeDefinition.val + && ( definition.prototype === _.nothing || definition.prototype === false ) ) + { + + definition.prototype = prototype; + definition.new = false; + + } + else if + ( + !_.boolIs( op.secondaryDefinition._synthetic ) + && ( _.boolIs( definition.prototype ) || definition.prototype === _.nothing ) + && op.primeDefinition.val === _.maybe + ) + { + + if( definition.prototype === _.nothing ) + { + if( prototype === Object.prototype ) + definition.prototype = false; + else + definition.prototype = prototype; + } + else if( prototype === null || prototype === Object.prototype ) + { + if( definition.prototype !== true ) + definition.prototype = false; + } + + } + + op.blueprint.traitsMap[ op.primeDefinition.kind ] = definition; + return; + } + + /* + default handler otherwise + */ + op.blueprintDefinitionRewrite( op ); + + } + +/* + += extend + +- typed1 ↓ +- synthetic ↓ +- typed2 ↓ + += supplement + +- typed2 ↑ +- synthetic ↑ +- typed1 ↑ + +*/ + + /* */ + + function bluprintDefinitionSupplement( op ) + { + let secondaryDefinition = op.secondaryDefinition; + + // if( _global_.debugger ) + // debugger; + + if( op.primeDefinition._synthetic === true ) + { + if( secondaryDefinition._synthetic === true ) + op.primeDefinition._notSyntheticDefinition = secondaryDefinition._notSyntheticDefinition; + else + op.primeDefinition._notSyntheticDefinition = secondaryDefinition; + /* preserve non-synthetic definition to use in case of attempt of partial supplementation */ + } + + if( secondaryDefinition._synthetic === true ) + { + if( op.primeDefinition.prototype !== _.nothing || !canRewritePrototype( op, secondaryDefinition ) ) + { + /* reject partial supplementing by trait generated inheriting */ + if( secondaryDefinition._notSyntheticDefinition === _.nothing ) + return; + else + secondaryDefinition = secondaryDefinition._notSyntheticDefinition; + } + } + else if( !_.boolIs( secondaryDefinition._synthetic ) ) + { + /* reject partial supplementing by trait generated construction */ + return; + } + + return bluprintDefinitionSupplementAct( op, secondaryDefinition ); + } + + /* */ + + function bluprintDefinitionSupplementAct( op, secondaryDefinition ) + { + + let prototypeRewriting = false; + if( op.primeDefinition.prototype === _.nothing ) + prototypeRewriting = true; + + let newRewriting = false; + if( op.primeDefinition.new === _.nothing ) + newRewriting = true; + + if( op.primeDefinition._blueprint && op.primeDefinition._blueprint !== op.blueprint ) + op.primeDefinition = op.primeDefinition.cloneShallow(); + + if( prototypeRewriting ) + { + definitionRewritePrototype( op, secondaryDefinition ); + } + else + { + if + ( + op.primeDefinition._secondaryPrototype === _.nothing + || op.primeDefinition._secondaryPrototype === op.primeDefinition.prototype + ) + if( secondaryDefinition.prototype !== _.nothing ) + op.primeDefinition._secondaryPrototype = secondaryDefinition.prototype; /* qqq : cover logic of amending of prototype in case of many amendings */ + } + + if( newRewriting ) + op.primeDefinition.new = secondaryDefinition.new; + + return true; + } + + /* */ + + function definitionRewritePrototype( op, secondaryDefinition ) + { + if( canRewritePrototype( op, secondaryDefinition.prototype ) ) + op.primeDefinition.prototype = secondaryDefinition.prototype; + else if( canRewritePrototype( op, secondaryDefinition._secondaryPrototype ) ) + op.primeDefinition.prototype = secondaryDefinition._secondaryPrototype; + else + op.primeDefinition._secondaryPrototype = secondaryDefinition.prototype; + } + + /* */ + + function canRewritePrototype( op, prototype ) + { + if( prototype === _.nothing ) + return false; + if( !op.primeDefinition.val && !_.primitiveIs( prototype ) ) + return false; + if( op.primeDefinition.val === true && prototype === null ) + return false; + return true; + } + + /* */ + + function blueprintForm1( op ) + { + let prototype; + let trait = op.blueprint.traitsMap.typed; + let runtime = op.blueprint.runtime; + + /**/ + + if( _.boolLike( trait.new ) ) + trait.new = !!trait.new; + if( _.boolLike( trait.prototype ) ) + trait.prototype = !!trait.prototype; + + if( trait.prototype === _.nothing ) + { + if( _.mapIs( trait._synthetic ) && trait.val === _.maybe ) + trait.prototype = false; + else if( trait.val === true ) + trait.prototype = true; + else + trait.prototype = false; + } + + if( trait.new === _.nothing ) + { + if( trait.val === _.maybe && trait.prototype === true ) + trait.new = false; + else + trait.new = _.blueprint.is( trait.prototype ) || trait.prototype === true; + } + + _.assert( _.boolIs( trait.new ), () => `Expects bool-like option::new, but got ${_.entity.strType( trait.new )}` ); + _.assert + ( + trait.prototype === null || _.boolIs( trait.prototype ) || !_.primitiveIs( trait.prototype ) + , () => `Prototype should be either bool, null or non-primitive, but is ${_.entity.strType( trait.prototype )}` + ); + _.assert + ( + trait.val !== false || _.primitiveIs( trait.prototype ) + , () => `Trait::typed should be either not false or prototype should be any of [ true, false, null ]` + + `, but it is ${_.entity.strType( trait.prototype )}` + ); + _.assert( trait._blueprint === op.blueprint ); + + /* */ + + if( trait._synthetic ) + trait._synthetic = false; + + _.assert( trait._synthetic === false ); + _.assert( op.blueprint.make === null ); + _.assert( runtime.prototype === null ); + + if( _.boolIs( trait.prototype ) ) + { + + if( trait.val === false && trait.val !== _.maybe ) + { + prototype = null; + } + else if( trait.val === _.maybe ) + { + if( trait.prototype === true || trait.prototype === false ) + prototype = Object.create( _.Construction.prototype ); + else + prototype = runtime.prototype; + } + else + { + prototype = Object.create( _.Construction.prototype ); + } + + runtime.prototype = prototype; + } + else + { + + if( _.blueprint.is( trait.prototype ) ) + { + prototype = trait.prototype.prototype; + _.assert( _.routineIs( trait.prototype.make ) ); + _.assert + ( + _.object.isBasic( trait.prototype.prototype ) + , `Cant use ${_.blueprint.qnameOf( trait.prototype )} as prototype. This blueprint is not prototyped.` + ); + } + else if( trait.val === _.maybe && trait.prototype === null ) + { + prototype = _.Construction.prototype; + } + else + { + prototype = trait.prototype; + } + + if( ( prototype === _.Construction.prototype || trait.new ) && prototype ) + runtime.prototype = Object.create( prototype ); + else + runtime.prototype = prototype; + + } + + /* */ + + // runtime._makingTyped = !!op.blueprint.traitsMap.typed.val; + + /* */ + + runtime._prototyping = trait.prototype; + + /* */ + + allocate = trait.val ? allocateTyped : allocateUntyped; + + /* */ + + retype = trait.val ? retypeTyped : retypeUntypedPreserving; + if( trait.val === _.maybe ) + retype = retypeMaybe; + else if( trait.val === false && ( trait.prototype === null || trait.prototype === true ) ) + retype = retypeUntypedForcing; + + _.blueprint._practiceAdd( op.blueprint, 'allocate', allocate ); + _.blueprint._practiceAdd( op.blueprint, 'retype', retype ); + + } + + /* */ + + function blueprintForm2( op ) + { + let trait = op.blueprint.traitsMap.typed; + let prototype; + + _.assert( _.fuzzyIs( trait.val ) ); + _.assert( op.blueprint.typed === trait.val || trait.val === _.maybe ); + _.assert( trait._blueprint === op.blueprint ); + _.assert( _.fuzzyIs( op.blueprint.typed ) ); + + Object.freeze( trait ); + + if( _.boolIs( trait.prototype ) ) + return; + + if( _.blueprint.is( trait.prototype ) ) + { + prototype = trait.prototype.prototype; + _.assert( _.blueprint.isDefinitive( trait.prototype ) ); + _.assert( _.routineIs( op.blueprint.make ) ); + _.assert( _.routineIs( trait.prototype.make ) ); + Object.setPrototypeOf( op.blueprint.make, trait.prototype.make ); + } + else + { + prototype = trait.prototype; + _.assert( prototype !== null || op.blueprint.typed !== true, 'Object with null prototype cant be typed' ); + if( prototype && Object.hasOwnProperty.call( prototype, 'constructor' ) && _.routineIs( prototype.constructor ) ) + if( op.blueprint.make !== prototype.constructor ) + Object.setPrototypeOf( op.blueprint.make, prototype.constructor ); + } + + } + + /* */ + + function allocateTyped( genesis ) + { + // if( _global_.debugger ) + // debugger; + _.assert( !!genesis.runtime.typed ); + if( genesis.construction === null ) + genesis.construction = new( _.constructorJoin( genesis.runtime.make, genesis.args ) ); + _.assert + ( + genesis.construction === null || !genesis.runtime.prototype || genesis.construction instanceof genesis.runtime.make + ); + return genesis.construction; + } + + /* */ + + function allocateUntyped( genesis ) + { + // if( _global_.debugger ) + // debugger; + + if( genesis.runtime.prototype === null && !_.mapIsPure( genesis.construction ) ) + genesis.construction = Object.create( null ); + else if( genesis.construction && genesis.runtime.prototype !== null && genesis.construction instanceof genesis.runtime.make ) + genesis.construction = Object.create( null ); + else if( genesis.construction === null ) + genesis.construction = Object.create( null ); + _.assert( genesis.construction === null || _.mapIs( genesis.construction ) ); + _.assert( genesis.runtime.prototype === null || !( genesis.construction instanceof genesis.runtime.make ) ); + return genesis.construction; + } + + /* */ + + function retypeMaybe( genesis ) + { + // if( _global_.debugger ) + // debugger; + + if( genesis.construction === null ) + { + if( !genesis.runtime._prototyping || genesis.runtime.prototype === null ) + { + _.assert( 0, 'not tested' ); + genesis.construction = Object.create( null ); + } + else + { + _.assert( 0, 'not tested' ); + genesis.construction = new( _.constructorJoin( genesis.runtime.make, genesis.args ) ); + } + } + else if( _.mapIs( genesis.construction ) ) + { + if( genesis.runtime._prototyping === null || genesis.runtime._prototyping === true ) + if( Object.getPrototypeOf( genesis.construction ) !== null ) + Object.setPrototypeOf( genesis.construction, null ); + } + else + { + + if( genesis.runtime._prototyping ) + if( Object.getPrototypeOf( genesis.construction ) !== genesis.runtime.prototype ) + Object.setPrototypeOf( genesis.construction, genesis.runtime.prototype ); + + } + + return genesis.construction; + } + + /* */ + + function retypeTyped( genesis ) + { + // if( _global_.debugger ) + // debugger; + if( genesis.construction === null ) + { + genesis.construction = new( _.constructorJoin( genesis.runtime.make, genesis.args ) ); + } + else if( genesis.construction ) + { + if( genesis.runtime._prototyping !== false || _.mapIs( genesis.construction ) ) + if( genesis.runtime.prototype === null || !( genesis.construction instanceof genesis.runtime.make ) ) + Object.setPrototypeOf( genesis.construction, genesis.runtime.prototype ); + } + + _.assert + ( + !_.mapIs( genesis.construction ) + ); + + _.assert + ( + genesis.runtime._prototyping === false + || genesis.runtime.typed === _.maybe + || genesis.runtime.prototype === null + || genesis.construction instanceof genesis.runtime.make + ); + return genesis.construction; + } + + /* */ + + function retypeUntypedPreserving( genesis ) + { + // if( _global_.debugger ) + // debugger; + if( genesis.construction ) + { + let wasProto = Object.getPrototypeOf( genesis.construction ); + if( wasProto !== null && wasProto !== Object.prototype ) + if( genesis.runtime.typed !== _.maybe ) + Object.setPrototypeOf( genesis.construction, null ); + } + else if( genesis.construction === null ) + { + genesis.construction = Object.create( null ); + } + _.assert( _.mapIs( genesis.construction ) ); + return genesis.construction; + } + + /* */ + + function retypeUntypedForcing( genesis ) + { + // if( _global_.debugger ) + // debugger; + if( genesis.construction ) + { + let wasProto = Object.getPrototypeOf( genesis.construction ); + if( genesis.runtime.typed !== _.maybe ) + Object.setPrototypeOf( genesis.construction, null ); + } + else if( genesis.construction === null ) + { + genesis.construction = Object.create( null ); + } + _.assert( _.mapIs( genesis.construction ) ); + return genesis.construction; + } + + /* */ + +} + +typed_body.defaults = +{ + val : true, + prototype : _.nothing, + new : _.nothing, + _synthetic : false, /* false for ordinary, true if created by inheriting, construction if spawned by _.construction.amend */ + _blueprint : null, + _notSyntheticDefinition : _.nothing, + _secondaryPrototype : _.nothing, +} + +typed_body.identity = { definition : true, trait : true }; + +let typed = _.routine.uniteCloning_replaceByUnite( typed_head, typed_body ); + +// + +function constructor( o ) +{ + if( !_.mapIs( o ) ) + o = arguments.length > 0 ? { val : arguments[ 0 ] } : {}; + _.routine.options_( constructor, o ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.boolLike( o.val ) ); + + o.val = !!o.val; + o.blueprintForm2 = blueprintForm2; + o._blueprint = false; + o.kind = 'constructor'; + return _.definition._traitMake( o ); + + /* */ + + function blueprintForm2( op ) + { + + // if( _global_.debugger ) + // debugger; + + if( !op.blueprint.traitsMap.constructor.val ) + return; + + let prototyped = op.blueprint.prototype && op.blueprint.prototype !== Object.prototype; + + _.assert( _.routineIs( op.blueprint.make ) ); + _.assert( _.fuzzyIs( op.blueprint.typed ) ); + + if( prototyped ) + if( op.amending !== 'supplement' || !_.mapOnlyOwnKey( op.blueprint.prototype, 'constructor' ) ) + { + let properties = + { + value : op.blueprint.make, + enumerable : false, + configurable : false, + writable : false, + }; + Object.defineProperty( op.blueprint.prototype, 'constructor', properties ); + } + + let prototype = op.blueprint.prototype; + let supplementing = op.amending === 'supplement'; + let constructor = op.blueprint.make; + let typed = op.blueprint.typed; + if( typed !== true ) + { + _.blueprint._practiceAdd( op.blueprint, 'constructionInitEnd', constructionInitEnd ); + } + + function constructionInitEnd( genesis ) + { + // if( _global_.debugger ) + // debugger; + _.assert( !_.primitiveIs( genesis.construction ) ); + if( typed ) + { + let prototype2 = Object.getPrototypeOf( genesis.construction ); + if( prototype2 && prototype2 === prototype ) + return; + } + if( genesis.amending === 'supplement' && Object.hasOwnProperty.call( genesis.construction, 'constructor' ) ) + return; + let properties = + { + value : constructor, + enumerable : false, + configurable : false, + writable : false, + }; + Object.defineProperty( genesis.construction, 'constructor', properties ); + } + + } + +} + +constructor.identity = { definition : true, trait : true }; +constructor.defaults = +{ + val : true, +} + +// + +function extendable( o ) +{ + if( !_.mapIs( o ) ) + o = arguments.length > 0 ? { val : arguments[ 0 ] } : {}; + _.routine.options_( extendable, o ); + + if( _.boolLike( o.val ) ) + o.val = !!o.val; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.boolIs( o.val ) ); + + o.blueprintForm2 = blueprintForm2; + + o.kind = 'extendable'; + return _.definition._traitMake( o ); + + function blueprintForm2( op ) + { + _.assert( _.boolIs( op.blueprint.traitsMap.extendable.val ) ); + if( op.blueprint.traitsMap.extendable.val ) + return; + _.blueprint._practiceAdd( op.blueprint, 'constructionInitEnd', preventExtensions ); + } + + function preventExtensions( genesis ) + { + Object.preventExtensions( genesis.construction ); + } + +} + +extendable.identity = { definition : true, trait : true }; +extendable.defaults = +{ + val : true, + _blueprint : false, +} + +// + +function name( o ) +{ + if( !_.mapIs( o ) ) + o = arguments.length > 0 ? { val : arguments[ 0 ] } : {}; + _.routine.options_( name, o ); + _.assert( arguments.length === 1 ); + _.assert( _.strIs( o.val ) ); + o.blueprintForm1 = blueprintForm1; + o.kind = 'name'; + return _.definition._traitMake( o ); + + function blueprintForm1( op ) + { + _.assert( op.blueprint.make === null ); + _.assert( op.blueprint.name === null ); + op.blueprint.runtime.name = op.definition.val; + } + +} + +name.identity = { definition : true, trait : true }; +name.defaults = +{ + val : null, + _blueprint : false, +} + +// -- +// define +// -- + +/** +* Collection of definitions which are traits. +* @namespace wTools.trait +* @extends Tools +* @module Tools/base/Proto +*/ + +let TraitExtension = +{ + + callable, + typed, + constructor, /* xxx : reuse static:maybe _.define.prop() ?*/ + extendable, + name, + +} + +_.definition.extend( TraitExtension ); + +// + +/** +* Routines to manipulate traits. +* @namespace wTools.definition +* @extends Tools +* @module Tools/base/Proto +*/ + +let DefinitionTraitExtension = +{ + + is : _.traitIs, + +} + +_.definition.trait = _.definition.trait || Object.create( null ); +/* _.props.extend */Object.assign( _.definition.trait, DefinitionTraitExtension ); +_.assert( _.routineIs( _.traitIs ) ); +_.assert( _.definition.trait.is === _.traitIs ); + +// + +let ToolsExtension = +{ +} + +_.props.extend( _, ToolsExtension ); +_.assert( _.routineIs( _.traitIs ) ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l3/Traits.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wblueprint/proto/wtools/abase/l2_blueprint/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Traits_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Traits_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wcloner/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wcloner/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wcloner */ ( function wcloner() { function wcloner_naked() { +module.exports = require( '../wtools/abase/l5/Cloner.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wCloner', 'wcloner' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wcloner/proto/node_modules/wcloner' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wcloner/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wcloner_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wcloner */ })(); + +/* */ /* begin of file Cloner_s */ ( function Cloner_s() { function Cloner_s_naked() { ( function _Cloner_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to copy / clone data structures, no matter how complex and cycled them are. Cloner relies on class relations definition for traversing. Use the module to replicate your data. + @module Tools/base/Cloner + @extends Tools +*/ + +/** + * Collection of cross-platform routines to copy / clone data structures, no matter how complex and cycled them are. +*/ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + _.include( 'wTraverser' ); + +} + +const _global = _global_; +const _ = _global_.wTools; +const _ObjectHasOwnProperty = Object.hasOwnProperty; + +_.assert( !!_._traverser ); + +// -- +// implementation +// -- + +function _cloneMapUp( it ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + + /* low copy degree */ + + if( it.copyingDegree === 1 ) + { + it.dst = it.src; + return _.dont; + } + + // if( _.routineIs( it.src ) ) + // debugger; + + /* copiers */ + + var copier; + if( it.down && _.instanceIs( it.down.dst ) && it.down.dst.Copiers && it.down.dst.Copiers[ it.key ] ) + { + copier = it.down.dst.Copiers[ it.key ]; + it.dst = copier.call( it.down.dst, it ); + return; + } + else if( it.down && _.instanceIs( it.down.src ) && it.down.src.Copiers && it.down.src.Copiers[ it.key ] ) + { + copier = it.down.src.Copiers[ it.key ]; + it.dst = copier.call( it.down.src, it ); + return; + } + + /* definition */ + + if( _.definitionIs( it.src ) ) + { + it.dst = it.src; + return _.dont; + } + + /* map */ + + var mapLike = _.aux.is( it.src ) || _.objectLikeStandard( it.src ) || it.instanceAsMap; + + // if( !mapLike && !_.regexpIs( it.src ) ) + // debugger; + + if( !mapLike && !_.lconstruction.is( it.src ) ) + { + throw _.err + ( + 'Complex objets should have ' + + ( it.iterator.technique === 'data' ? 'traverseData' : 'traverseObject' ) + + ', but object ' + _.entity.strType( it.src ) + ' at ' + ( it.path || '.' ), 'does not have such method', '\n', + it.src, + '\ntry to mixin wCopyable' + ); + } + + /* */ + + if( it.dst ) + { + } + else if( it.proto ) + { + it.dst = new it.proto.constructor(); + } + else + { + if( _.objectLikeStandard( it.src ) && !_.aux.is( it.src ) ) + it.dst = _.entity.cloneShallow( it.src ); + else + it.dst = _.entity.makeUndefined( it.src ); + // it.dst = _.entity.cloneShallow( it.src ); /* yyy */ + /* xxx : the previous version was _.entityMakeConstructing. + The routine created empty map from any it.src map + _.entityMakeConstructing({ a : 1 }); // return : {} + The routine _.entity.cloneShallow makes clone of the map + _.entity.cloneShallow({ a : 1 }); // return : { a : 1 } + + Some routines of other modules ( willbe ) uses this private routine directly. + The modules use feature with empty map for filtering fields with value `undefined`. + See test routine `traverseMapWithClonerRoutines` which demonstrates described behavior + + The fix is using routine _.entity.makeUndefined which have same behavior with _.entityMakeConstructing. + _.entity.makeUndefined({ a : 1 }); // return : {} + */ + } + + return it; +} + +// + +function _cloneMapElementUp( it, eit ) +{ + var key = eit.key; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( it.iterator === eit.iterator ); + _.assert( it.copyingDegree > 1 ); + _.assert( !_.primitiveIs( it.dst ) ); + + if( Config.debug ) + { + var errd = 'Object does not have ' + key; + _.assert( ( key in it.dst ) || Object.isExtensible( it.dst ), errd ); + } + + eit.cloningWithSetter = 0; + if( !it.iterator.deserializing && eit.copyingDegree > 1 && it.dst._Accessors && it.dst._Accessors[ key ] ) + { + _.assert( eit.copyingDegree > 0, 'not expected' ); + eit.copyingDegree = 1; + eit.cloningWithSetter = 1; + } + + return eit; +} + +// + +function _cloneMapElementDown( it, eit ) +{ + var key = eit.key; + var val = eit.dst; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( it.iterator === eit.iterator ); + + if( it.compact ) + { + val = eit.dst = it.onCompactField( it, eit ); + if( val === undefined ) + return eit; + } + + let copy = _.accessor._objectMethodMoveGet( it.dst, key ); + if( copy ) + copy.call( it.dst, _.accessor._moveItMake + ({ + srcInstance : it.src, + dstInstance : it.dst, + instanceKey : key, + value : val, + })); + else + it.dst[ key ] = val; + + if( eit.cloningWithSetter ) + if( Config.debug ) + { + var errd = 'Component setter "' + key + '" of object "' + it.dst.constructor.name + '" didn\'t copy data, but had to.'; + if( !( _.primitiveIs( eit.src ) || it.dst[ key ] !== eit.src ) ) + { + it.dst[ key ] = val; + } + _.assert( _.primitiveIs( eit.src ) || it.dst[ key ] !== eit.src, errd ); + } + + return eit; +} + +// + +function _cloneArrayUp( it ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( it.copyingDegree >= 1 ); + + /* low copy degree */ + + if( it.copyingDegree === 1 ) + { + it.dst = it.src; + return _.dont; + } + + if( it.dst ) + {} + else if( it.proto ) + { + it.dst = new it.proto( it.src.length ); + } + else + { + it.dst = []; + } + + return it; +} + +// + +function _cloneArrayElementUp( it, eit ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + return eit; +} + +// + +function _cloneArrayElementDown( it, eit ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + it.dst.push( eit.dst ); + return eit; +} + +// + +function _cloneBufferUp( src, it ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( it.copyingDegree >= 1 ); + + if( it.copyingDegree >= 2 ) + { + // debugger; + /* zzz : use _.bufferMake maybe? */ + it.dst = _._longClone( it.src ); + } + else + { + it.dst = it.src; + } + + // return it; +} + +// + +function _cloneSetUp( src, it ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( it.copyingDegree >= 1 ); + + if( it.copyingDegree >= 2 ) + { + it.dst = new Set([ ... it.src ]); + } + else + { + it.dst = it.src; + } + +} + +// + +function _cloner( routine, o ) +{ + var routine = routine || _cloner; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.routine.options_( routine, o ); + + /* */ + + o.onMapUp = [ _._cloneMapUp, o.onMapUp ]; + o.onMapElementUp = [ _._cloneMapElementUp, o.onMapElementUp ]; + o.onMapElementDown = [ _._cloneMapElementDown, o.onMapElementDown ]; + o.onArrayUp = [ _._cloneArrayUp, o.onArrayUp ]; + o.onArrayElementUp = [ _._cloneArrayElementUp, o.onArrayElementUp ]; + o.onArrayElementDown = [ _._cloneArrayElementDown, o.onArrayElementDown ]; + o.onBuffer = [ _._cloneBufferUp, o.onBuffer ]; + o.onSet = [ _._cloneSetUp, o.onSet ]; + + var result = _._traverser( routine, o ); + + return result; +} + +_cloner.iterationDefaults = Object.create( _._traverser.iterationDefaults ); +_cloner.defaults = Object.create( _._traverser.defaults ); + +// + +function _cloneAct( it ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + return _._traverseAct( it ); +} + +// + +function _clone( o ) +{ + var it = _cloner( _clone, o ); + _.assert( !it.iterator.src || !!it.iterator.rootSrc ); + _.assert( arguments.length === 1, 'Expects single argument' ); + return _cloneAct( it ); +} + +_clone.defaults = _cloner.defaults; +_clone.iterationDefaults = _cloner.iterationDefaults; + +// -- +// +// -- + +/** + * @summary Short-cut for clone routine. Clones source entity( src ) with default options. + * @param {*} src Entity to clone. + * @function cloneJust + * @namespace Tools + * @module Tools/base/Cloner +*/ + +function cloneJust( src ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + var o = Object.create( null ); + o.src = src; + + _.routine.options_( cloneJust, o ); + + return _._clone( o ); +} + +cloneJust.defaults = +{ + technique : 'object', +} + +// cloneJust.defaults.__proto__ = _clone.defaults; +Object.setPrototypeOf( cloneJust.defaults, _clone.defaults ); + +// + +/** + * @summary Clones source entity( src ). Returns new entity as copy of source( src ). + * @description + * If source entity( src ) is instance of a class, then result object will be also an instance of same class. + * @param {*} src Entity to clone. + * @function cloneObject + * @namespace Tools + * @module Tools/base/Cloner +*/ + +function cloneObject( o ) +{ + if( o.rootSrc === undefined ) + o.rootSrc = o.src; + _.routine.options_( cloneObject, o ); + var result = _clone( o ); + return result; +} + +cloneObject.defaults = +{ + copyingAssociates : 1, + technique : 'object', +} + +// cloneObject.defaults.__proto__ = _clone.defaults; +Object.setPrototypeOf( cloneObject.defaults, _clone.defaults ); + +// + +function cloneObjectMergingBuffers( o ) +{ + var result = Object.create( null ); + var src = o.src; + var descriptorsMap = o.src.descriptorsMap; + var buffer = o.src.buffer; + var data = o.src.data; + + if( o.rootSrc === undefined ) + o.rootSrc = o.src; + + _.routine.options_( cloneObjectMergingBuffers, o ); + + _.assert( _.object.isBasic( o.src.descriptorsMap ) ); + _.assert( _.bufferRawIs( o.src.buffer ) ); + _.assert( o.src.data !== undefined ); + _.assert( arguments.length === 1 ) + + /* */ + + var optionsForCloneObject = _.mapOnly_( null, o, _.cloneObject.defaults ); + optionsForCloneObject.src = data; + + /* onString */ + + optionsForCloneObject.onString = function onString( strString, it ) + { + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + var id = _.strUnjoin( strString, [ '--buffer-->', _.strUnjoin.any, '<--buffer--' ] ) + + if( id === undefined ) + return strString; + + var descriptor = descriptorsMap[ strString ]; + _.assert( descriptor !== undefined ); + + let bufferConstructorName = descriptor[ 'bufferConstructorName' ]; + var bufferConstructor; + + if( bufferConstructorName !== 'null' ) + { + if( _.long.toolsNamespacesByType[ bufferConstructorName ] ) + bufferConstructor = _.long.toolsNamespacesByType[ bufferConstructorName ].long.default.InstanceConstructor; + else if( _[ bufferConstructorName ] ) + bufferConstructor = _[ bufferConstructorName ]; + else if( _global_[ bufferConstructorName ] ) + bufferConstructor = _global_[ bufferConstructorName ]; + _.sure( _.routineIs( bufferConstructor ) ); + + // _.assert( 0, 'not tested' ); /* Dmytro : tested */ + // + // // if( _.LongDescriptors[ bufferConstructorName ] ) + // // bufferConstructor = _.LongDescriptors[ bufferConstructorName ].make; + // if( _.long.toolsNamespacesByType[ bufferConstructorName ] ) + // bufferConstructor = _.long.toolsNamespacesByType[ bufferConstructorName ].long.default.make; /* Dmytro : interface of routines `make` has no offset */ + // else if( _[ bufferConstructorName ] ) + // bufferConstructor = _[ bufferConstructorName ]; + // else if( _global_[ bufferConstructorName ] ) + // bufferConstructor = _global_[ bufferConstructorName ]; + // _.sure( _.routineIs( bufferConstructor ) ); + } + + var offset = descriptor[ 'offset' ]; + var size = descriptor[ 'size' ]; + var sizeOfScalar = descriptor[ 'sizeOfScalar' ]; + var result = bufferConstructor ? new bufferConstructor( buffer, offset, size / sizeOfScalar ) : null; + + it.dst = result; + + return result; + } + + optionsForCloneObject.onInstanceCopy = function onInstanceCopy( src, it ) + { + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + var newIt = it.iterationClone(); + newIt.dst = null; + newIt.proto = null; + + var technique = newIt.iterator.technique; + newIt.iterator.technique = 'data'; + newIt.usingInstanceCopy = 0; + _._cloneAct( newIt ); + newIt.iterator.technique = technique; + + it.src = newIt.dst; + + } + + /* clone object */ + + var result = _.cloneObject( optionsForCloneObject ); + + return result; +} + +cloneObjectMergingBuffers.defaults = +{ + copyingBuffers : 1, +}; + +// cloneObjectMergingBuffers.defaults.__proto__ = cloneObject.defaults; +Object.setPrototypeOf( cloneObjectMergingBuffers.defaults, cloneObject.defaults ); + +// + +/** + * @summary Clones source entity( src ). + * @description Returns map that is ready for serialization. Can contain maps, arrays and primitives, but don't contain objects or class instances. + * @param {*} src Entity to clone. + * @function cloneData + * @namespace Tools + * @module Tools/base/Cloner +*/ + +function cloneData( o ) +{ + + _.routine.options_( cloneData, o ); + + var result = _clone( o ); + + return result; +} + +cloneData.defaults = +{ + technique : 'data', + copyingAssociates : 0, +} + +// cloneData.defaults.__proto__ = _clone.defaults; +Object.setPrototypeOf( cloneData.defaults, _clone.defaults ); + +// + +function cloneDataSeparatingBuffers( o ) +{ + var result = Object.create( null ); + var buffers = []; + var descriptorsArray = []; + var descriptorsMap = Object.create( null ); + var size = 0; + var offset = 0; + + _.routine.options_( cloneDataSeparatingBuffers, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + /* onBuffer */ + + o.onBuffer = function onBuffer( srcBuffer, it ) + { + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.bufferTypedIs( srcBuffer ), 'not tested' ); + + var index = buffers.length; + var id = _.strJoin([ '--buffer-->', index, '<--buffer--' ]); + var bufferSize = srcBuffer ? srcBuffer.length*srcBuffer.BYTES_PER_ELEMENT : 0; + size += bufferSize; + + let bufferConstructorName; + if( srcBuffer ) /* yyy */ + { + let longDescriptor = _.long.namespaceOf( srcBuffer ); + + if( longDescriptor ) + bufferConstructorName = longDescriptor.TypeName; + else + bufferConstructorName = srcBuffer.constructor.name; + + // let longDescriptor = _.LongTypeToDescriptorsHash.get( srcBuffer.constructor ); + // + // if( longDescriptor ) + // bufferConstructorName = longDescriptor.name; + // else + // bufferConstructorName = srcBuffer.constructor.name; + + } + else + { + bufferConstructorName = 'null'; + } + + var descriptor = + { + bufferConstructorName, + 'sizeOfScalar' : srcBuffer ? srcBuffer.BYTES_PER_ELEMENT : 0, + 'offset' : -1, + 'size' : bufferSize, + index, + } + + buffers.push( srcBuffer ); + descriptorsArray.push( descriptor ); + descriptorsMap[ id ] = descriptor; + + it.dst = id; + + } + + /* clone data */ + + result.data = _._clone( o ); + result.descriptorsMap = descriptorsMap; + + /* sort by atom size */ + + descriptorsArray.sort( function( a, b ) + { + return b[ 'sizeOfScalar' ] - a[ 'sizeOfScalar' ]; + }); + + /* alloc */ + + result.buffer = new BufferRaw( size ); + var dstBuffer = _.bufferBytesGet( result.buffer ); + + /* copy buffers */ + + for( var b = 0 ; b < descriptorsArray.length ; b++ ) + { + + var descriptor = descriptorsArray[ b ]; + var buffer = buffers[ descriptor.index ]; + var bytes = buffer ? _.bufferBytesGet( buffer ) : new U8x(); + var bufferSize = descriptor[ 'size' ]; + + descriptor[ 'offset' ] = offset; + + _.bufferMove( dstBuffer.subarray( offset, offset+bufferSize ), bytes ); + + offset += bufferSize; + + } + + return result; +} + +cloneDataSeparatingBuffers.defaults = +{ + copyingBuffers : 1, +} + +// cloneDataSeparatingBuffers.defaults.__proto__ = cloneData.defaults; +Object.setPrototypeOf( cloneDataSeparatingBuffers.defaults, cloneData.defaults ); + +// -- +// declare +// -- + +const Proto = +{ + + _cloneMapUp, + _cloneMapElementUp, + _cloneMapElementDown, + _cloneArrayUp, + _cloneArrayElementUp, + _cloneArrayElementDown, + _cloneBufferUp, + _cloneSetUp, + + _cloner, + _cloneAct, + _clone, + + // + + cloneJust, + cloneObject, + cloneObjectMergingBuffers, /* experimental */ + cloneData, + cloneDataSeparatingBuffers, /* experimental */ + +} + +_.props.extend( _, Proto ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wcloner/proto/wtools/abase/l5/Cloner.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wcloner/proto/wtools/abase/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Cloner_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Cloner_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wequaler/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wequaler/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wequaler */ ( function wequaler() { function wequaler_naked() { +module.exports = require( '../wtools/abase/l6/Equaler.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wEqualer', 'wequaler' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wequaler/proto/node_modules/wequaler' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wequaler/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wequaler_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wequaler */ })(); + +/* */ /* begin of file Equaler_s */ ( function Equaler_s() { function Equaler_s_naked() { ( function _Equaler_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to compare two complex structures. The module can answer questions: are two structures equivalent? are them identical? what is the difference between each other? Use the module avoid manually work and cherry picking. + @module Tools/base/Equaler + @extends Tools +*/ + +/** + * Collection of light-weight routines to traverse complex data structure. + * @namespace Tools.Equaler + * @module Tools/base/Looker + */ + +/** + * Collection of light-weight routines to traverse complex data structure. + * @namespace Tools.equaler + * @module Tools/base/Looker + */ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + + _.include( 'wLooker' ); + _.include( 'wSelector' ); + +} + +const _global = _global_; +const _ = _global_.wTools; +const Parent = _.looker.Looker; +const _ObjectToString = Object.prototype.toString; + +_.equaler = _.equaler || Object.create( _.looker ); + +_.assert( !!_realGlobal_ ); +_.assert( !!_.look ); +_.assert( !!_.select ); + +/* qqq : write nice example for readme */ + +// -- +// relations +// -- + +let Prime = Object.create( null ); + +Prime.src2 = undefined; +Prime.containing = 0; +Prime.strict = 1; +Prime.revisiting = 1; +Prime.strictTyping = null; +Prime.strictNumbering = null; +Prime.strictCycling = null; +Prime.strictString = null; +Prime.strictContainer = null; +Prime.withImplicit = null; +Prime.withCountable = 'countable'; +Prime.accuracy = 1e-7; +Prime.recursive = Infinity; +Prime.onNumbersAreEqual = null; +Prime.onStringsAreEqual = null; +Prime.onStringPreprocess = null; +Prime.iterableEval = null; + +// -- +// implementation +// -- + +/** + * Deep comparsion of two entities. Uses recursive comparsion for objects, arrays and array-like objects. + * Returns string refering to first found difference or false if entities are sames. + * + * @param {*} src - Entity for comparison. + * @param {*} src2 - Entity for comparison. + * @param {wTools~entityEqualOptions} o - Comparsion options {@link wTools~entityEqualOptions}. + * @returns {boolean} result - Returns false for same entities or difference as a string. + * + * @example + * //returns + * //"at : + * //src1 : + * //1 + * //src2 : + * //1 " + * _.entityDiff( '1', 1 ); + * + * @example + * //returns + * //"at : .2 + * //src1 : + * //3 + * //src2 : + * //4 + * //difference : + * //*" + * _.entityDiff( [ 1, 2, 3 ], [ 1, 2, 4 ] ); + * + * @function entityDiff + * @throws {exception} If( arguments.length ) is not equal 2 or 3. + * @throws {exception} If( o ) is not a Object. + * @throws {exception} If( o ) is extended by unknown property. + * @namespace Tools + * @module Tools/base/Equaler + */ + +function entityDiff( src, src2, opts ) +{ + + opts = opts || Object.create( null ); + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + let equal = _.equaler._equal( src, src2, opts ); + + if( equal ) + return false; + + let it = opts; + _.assert( it.lastPath !== undefined ); + + let result = _.entityDiffExplanation + ({ + srcs : [ src, src2 ], + path : it.lastPath, + }); + + return result; +} + +// + +function entityDiffExplanation( o ) +{ + let result = ''; + let isDiffProto = false; + + o = _.routine.options_( entityDiffExplanation, arguments ); + _.assert( _.arrayIs( o.srcs ) ); + _.assert( o.srcs.length === 2 ); + _.assert( arguments.length === 1 ); + + if( o.onStringPreprocess === null ) + if( o.strictString ) + o.onStringPreprocess = stringsPreprocessNo; + else + o.onStringPreprocess = stringsPreprocessLose; + + if( o.path ) + { + + let src0 = _.select( o.srcs[ 0 ], o.path ); + let src1 = _.select( o.srcs[ 1 ], o.path ); + + if( _.aux.is( src0 ) && _.aux.is( src1 ) ) /* yyy */ + { + o.srcs[ 0 ] = src0; + o.srcs[ 1 ] = src1; + } + else + { + let dir = _.strSplit( o.path, '/' ) + .slice( 0, -1 ) + .join( '' ); + + if( !dir ) + dir = '/'; + o.srcs[ 0 ] = _.select( o.srcs[ 0 ], dir ); + o.srcs[ 1 ] = _.select( o.srcs[ 1 ], dir ); + } + + if( o.path !== '/' ) + result += 'at ' + o.path + '\n'; + + } + + if( _.strIs( o.srcs[ 0 ] ) ) + o.srcs[ 0 ] = o.onStringPreprocess( o.srcs[ 0 ] ); + if( _.strIs( o.srcs[ 1 ] ) ) + o.srcs[ 1 ] = o.onStringPreprocess( o.srcs[ 1 ] ); + + if( _.aux.is( o.srcs[ 0 ] ) && _.aux.is( o.srcs[ 1 ] ) ) + { + let protoGot = Object.getPrototypeOf( o.srcs[ 0 ] ); + let protoExpected = Object.getPrototypeOf( o.srcs[ 1 ] ); + let srcOwn0 = _.props.onlyOwn( o.srcs[ 0 ] ); + let srcOwn1 = _.props.onlyOwn( o.srcs[ 1 ] ); + + let common = _.filter_( null, srcOwn0, ( e, k ) => _.entityIdentical( e, srcOwn1[ k ] ) ? e : undefined ); + o.srcs[ 0 ] = _.mapBut_( null, srcOwn0, common ); + o.srcs[ 1 ] = _.mapBut_( null, srcOwn1, common ); + + if( _.map.isEmpty( o.srcs[ 0 ] ) && _.map.isEmpty( o.srcs[ 1 ] ) ) + { + if( !isEquivalentProto( protoGot, protoExpected ) ) + { + isDiffProto = true; + if( protoGot === null ) + { + o.srcs[ 1 ] = '__proto__'; + o.srcs[ 0 ] = '__proto__ = null'; + } + else if( protoExpected === null ) + { + o.srcs[ 0 ] = '__proto__'; + o.srcs[ 1 ] = '__proto__ = null'; + } + else + { + o.srcs[ 0 ] = '__proto__'; + o.srcs[ 1 ] = '__proto__'; + } + } + } + } + + o.srcs[ 0 ] = _.entity.exportString( o.srcs[ 0 ], { levels : o.levels, keyWrapper : '\'' } ); + o.srcs[ 1 ] = _.entity.exportString( o.srcs[ 1 ], { levels : o.levels, keyWrapper : '\'' } ); + + o.srcs[ 0 ] = ' ' + _.strLinesIndentation( o.srcs[ 0 ], ' ' ); + o.srcs[ 1 ] = ' ' + _.strLinesIndentation( o.srcs[ 1 ], ' ' ); + + result += _.entity.exportStringDiagnosticShallow/*exportStringSimple*/( o.name1 + ' :\n' + o.srcs[ 0 ] + '\n' + o.name2 + ' :\n' + o.srcs[ 1 ] ); + + /* */ + + let strDiff = false; + + if( !isDiffProto ) + strDiff = _.strDifference( o.srcs[ 0 ], o.srcs[ 1 ] ); + + if( strDiff !== false ) + result += ( '\n' + o.differenceName + ' :\n' + strDiff ); + + /* */ + + if( o.accuracy !== null ) + result += '\n' + o.accuracyName + ' ' + o.accuracy + '\n'; + + return result; + + /* */ + + function stringsPreprocessLose( str ) + { + return _.str.lines.strip( str ); + } + + /* */ + + function stringsPreprocessNo( str ) + { + return str; + } + + /* */ + + function isEquivalentProto( proto1, proto2 ) + { + if( proto1 === proto2 ) + return true; + + if( proto1 === null && proto2 === Object.prototype ) + return true; + + if( proto2 === null && proto1 === Object.prototype ) + return true; + + return false; + } + + /* */ + +} + +var defaults = entityDiffExplanation.defaults = Object.create( null ); + +defaults.name1 = '- src1'; +defaults.name2 = '- src2'; +defaults.differenceName = '- difference'; +defaults.accuracyName = 'with accuracy'; +defaults.srcs = null; +defaults.path = null; +defaults.accuracy = null; +defaults.levels = 3; +defaults.strictString = 1; /* qqq : cover option strictString */ +defaults.onStringPreprocess = null + +// -- +// options +// -- + +function head( routine, args ) +{ + _.assert( arguments.length === 2 ); + if( args.length === 3 && _.looker.iterationIs( args[ 2 ] ) ) + { + let it = args[ 2 ]; + _.assert( it.src === args[ 1 ] ); + _.assert( it.src2 === args[ 0 ] ); + return it; + } + _.assert( !!routine.defaults.Seeker ); + let o = routine.defaults.Seeker.optionsFromArguments( args ); + + o.Seeker = o.Seeker || routine.defaults; + + _.map.assertHasOnly( o, routine.defaults ); + _.assert( routine.defaults === o.Seeker ); + _.assert( routine.defaults.withImplicit === null ); + let it = o.Seeker.optionsToIteration( null, o ); + return it; +} + +// + +function optionsFromArguments( args ) +{ + let o = args[ 2 ] || Object.create( null ); + + /* + second argument should goes first to make contain work properly + */ + + o.src = args[ 1 ]; + o.src2 = args[ 0 ]; + + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + _.assert( arguments.length === 1 ); + _.assert( _.mapIs( o ) ); + + return o; +} + +// + +function optionsToIteration( iterator, o ) +{ + let it = Parent.optionsToIteration.call( this, iterator, o ); + + _.assert( arguments.length === 2 ); + _.assert( it.iterator.visitedContainer2 === null ); + _.assert( it.originalSrc === null ); + _.assert( it.originalSrc2 === null ); + _.assert( it.result === true ); + + return it; +} + +// + +function iteratorInitEnd( iterator ) +{ + let looker = this; + + _.assert( iterator.iteratorProper( iterator ) ); + _.assert( 0 <= iterator.revisiting && iterator.revisiting <= 2 ); + _.assert( iterator.withImplicit !== undefined ); + _.assert + ( + _.longHasAll( [ 0, false, 'all', 'any', 'only', 'none' ], iterator.containing ) + , () => `Unknown value of option iterator.containing : ${iterator.containing}` + + `\nExpects any of [ ${[ 0, false, 'all', 'any', 'only', 'none' ].join( ' ' )} ]` + ); + + let accuracy = iterator.accuracy; + + if( iterator.strictTyping === null ) + iterator.strictTyping = iterator.strict; + if( iterator.strictNumbering === null ) + iterator.strictNumbering = iterator.strict; + if( iterator.strictCycling === null ) + iterator.strictCycling = iterator.strict; + if( iterator.strictString === null ) + iterator.strictString = iterator.strict; + if( iterator.strictContainer === null ) + iterator.strictContainer = iterator.strict; + if( iterator.withImplicit === null ) + iterator.withImplicit = iterator.strictTyping ? 'aux' : ''; + + if( iterator.onNumbersAreEqual === null ) + if( iterator.strictNumbering && iterator.strictTyping ) + iterator.onNumbersAreEqual = _.number.identicalShallowStrictly.bind( _.number ); /* Dmytro : callbacks should be binded to namespace, bind should bind original routine, not alias */ + else if( iterator.strictNumbering && !iterator.strictTyping ) + iterator.onNumbersAreEqual = _.number.identicalShallow.bind( _.number ); + else + iterator.onNumbersAreEqual = ( a, b, acc ) => + { + return _.number.equivalent( a, b, ( acc === undefined || acc === null ) ? accuracy : acc ); + } + // if( iterator.onNumbersAreEqual === null ) + // if( iterator.strictNumbering && iterator.strictTyping ) + // iterator.onNumbersAreEqual = _.number.identicalStrictly; + // else if( iterator.strictNumbering && !iterator.strictTyping ) + // iterator.onNumbersAreEqual = _.number.identical; + // else + // iterator.onNumbersAreEqual = ( a, b, acc ) => + // { + // return _.number.equivalent( a, b, ( acc === undefined || acc === null ) ? accuracy : acc ); + // } + + if( iterator.onStringsAreEqual === null ) + iterator.onStringsAreEqual = stringsAreIdentical; + + if( iterator.onStringPreprocess === null ) + if( iterator.strictString ) + iterator.onStringPreprocess = stringsPreprocessNo; + else + iterator.onStringPreprocess = stringsPreprocessLose; + + return Parent.iteratorInitEnd.call( this, iterator ); + + /* */ + + function stringsAreIdentical( a, b ) + { + if( !_.strIs( a ) ) + return false; + if( !_.strIs( b ) ) + return false; + return a === b; + } + + /* */ + + function stringsPreprocessLose( str ) + { + return _.str.lines.strip( str ); + } + + /* */ + + function stringsPreprocessNo( str ) + { + return str; + } + +} + +// -- +// looker routines +// -- + +function performBegin() +{ + let it = this; + Parent.performBegin.apply( it, arguments ); + + _.assert( it.iterator.visitedContainer2 === null ); + + if( it.iterator.revisiting < 2 ) + { + if( it.iterator.revisiting === 0 ) + it.iterator.visitedContainer2 = _.containerAdapter.from( new Set ); + else + it.iterator.visitedContainer2 = _.containerAdapter.from( new Array ); + } + _.assert( it.iterator.revisiting >= 2 || !!it.iterator.visitedContainer2 ); + + return it; +} + +// + +function performEnd() +{ + let it = this; + + _.assert( _.boolIs( it.result ) ); + _.assert( ( it.withImplicit === '' ) === ( !it.strictTyping ) ); + + Parent.performEnd.apply( it, arguments ); + return it; +} + +// + +function chooseBegin() +{ + let it = this; + let e = arguments[ 0 ]; + let k = arguments[ 1 ]; + let c = arguments[ 2 ]; + let exists = arguments[ 3 ]; + + [ e, k, c, exists ] = Parent.chooseBegin.apply( it, arguments ); + + // _.assert( arguments.length === 4 ); + // _.assert( it.level >= 0 ); + // _.assert( _.object.isBasic( it.down ) ); + + _.debugger; + + let k2, exists2; + [ it.src2, k2, exists2 ] = _.entity.elementWithImplicit( it.src2, k ); /* xxx : use maybe functor */ + it.originalSrc2 = it.src2; + + return [ e, k, c, exists ]; +} + +// + +function chooseRoot() +{ + let it = this; + + _.assert( arguments.length === 0 ); + + it.originalSrc = it.src; + it.originalSrc2 = it.src2; + + if( it.containing === 'only' ) + { + let x; + x = it.src; + it.src = it.src2; + it.src2 = x; + x = it.originalSrc; + it.originalSrc = it.originalSrc2; + it.originalSrc2 = x; + } + + it.srcChanged(); + it.revisitedEval( it.originalSrc ); + + return it; +} + +// + +function iterableEval() +{ + let it = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + it.secondCoerce(); + it._iterableEval(); + + _.assert( it.iterable >= 0 ); +} + +// + +function _iterableEval() +{ + let it = this; + it.iterable = null; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.debugger; + + /* xxx : handle custom type */ + + if( _.class.methodEqualOf( it.src ) && !_.aux.is( it.src ) ) + { + it.type1 = it.ContainerType.object; + it.iterable = it.ContainerType.object; + } + else if( _.hashMapLike( it.src ) ) + { + it.type1 = it.ContainerType.hashMap; + it.iterable = it.ContainerType.hashMap + } + else if( _.setLike( it.src ) ) + { + it.type1 = it.ContainerType.set; + it.iterable = it.ContainerType.set; + } + else if( it.isCountable( it.src ) ) + { + it.type1 = it.ContainerType.countable; + it.iterable = it.ContainerType.countable; + } + else if( _.primitiveIs( it.src ) ) + { + it.type1 = 0; + it.iterable = 0; + } + else if( _.aux.is( it.src ) ) + { + it.type1 = it.ContainerType.aux; + it.iterable = it.ContainerType.aux; + } + else + { + it.type1 = it.ContainerType.object; + + if( it.containing === 'only' ) + it.iterable = it.ContainerType.aux; + + if( !it.iterable ) + it.iterable = it.ContainerType.object; + } + + if( _.class.methodEqualOf( it.src2 ) && !_.aux.is( it.src2 ) ) + { + it.type2 = it.ContainerType.object; + it.iterable = it.ContainerType.object; + } + else if( _.hashMapLike( it.src2 ) ) + { + it.type2 = it.ContainerType.hashMap; + } + else if( _.setLike( it.src2 ) ) + { + it.type2 = it.ContainerType.set; + if( it.iterable === it.ContainerType.countable ) /* yyy */ + it.iterable = it.ContainerType.set; + } + else if( it.isCountable( it.src2 ) ) + { + it.type2 = it.ContainerType.countable; + } + else if( _.aux.is( it.src2 ) ) + { + it.type2 = it.ContainerType.aux; + } + else if( _.primitiveIs( it.src2 ) ) + { + it.type2 = 0; + } + else + { + it.type2 = it.ContainerType.object; + + if( it.iterable !== it.ContainerType.aux && it.iterable !== it.ContainerType.countable ) + { + it.iterable = it.ContainerType.object; + } + else if( !it.containing || it.containing === 'only' ) + { + it.iterable = it.ContainerType.object; + } + + } + +} + +// + +function visitPush() +{ + let it = this; + + if( it.iterator.visitedContainer2 ) + if( it.visitCounting && it.type2 ) + { + it.iterator.visitedContainer2.push( it.originalSrc2 ); + } + + Parent.visitPush.apply( it, arguments ); +} + +// + +function visitPop() +{ + let it = this; + + if( it.iterator.visitedContainer2 && it.iterator.revisiting !== 0 ) + if( it.visitCounting && it.type2 ) + if( _.arrayIs( it.iterator.visitedContainer2.original ) || !it.revisited ) + { + if( _.arrayIs( it.iterator.visitedContainer2.original ) ) + _.assert + ( + Object.is( it.iterator.visitedContainer2.original[ it.iterator.visitedContainer2.original.length-1 ], it.originalSrc2 ), + () => `Top-most visit ${it.path} does not match` + + `${_.entity.exportStringDiagnosticShallow( it.originalSrc2 )} <> ${_.entity.exportStringDiagnosticShallow + ( + it.iterator.visitedContainer2.original[ it.iterator.visitedContainer2.original.length-1 ] + )}` + ); + it.iterator.visitedContainer2.pop( it.originalSrc2 ); + } + + Parent.visitPop.apply( it, arguments ); +} + +// + +function visitUp() +{ + let it = this; + + it.visitUpBegin(); + + _.assert( _.routineIs( it.onUp ) ); + let r = it.onUp.call( it, it.src, it.key, it ); + _.assert( r === undefined ); + + it.equalUp(); + + it.visitUpEnd() +} + +// + +function visitDown() +{ + let it = this; + it.visitDownBegin(); + + _.assert( it.visiting ); + if( it.visiting ) + if( it.onDown ) + { + let r = it.onDown.call( it, it.src, it.key, it ); + _.assert( r === undefined ); + } + + it.equalDown(); + + it.visitDownEnd(); + return it; +} + +// + +function stop( result ) +{ + let it = this; + + _.assert( arguments.length === 1 ); + _.assert( _.boolIs( result ) ); + _.debugger; + + if( it.containing ) + { + + if( it.containing === 'any' ) + { + let any = + [ + it.ContainerType.aux, + ContainerType.hashMap, + ContainerType.set, + ContainerType.object + ]; + if( it.down && _.longHasAny( any, it.down.iterable ) ) + { + it.result = false; + it.result = it.result || result; + if( it.result ) + { + it.continue = false; + if( it.down ) + { + it.down.result = it.result; + it.down.continue = false; + } + } + return; + } + } + else if( it.containing === 'none' ) + { + let any = + [ + it.ContainerType.aux, + ContainerType.hashMap, + ContainerType.set, + ContainerType.object + ]; + if( it.down && _.longHasAny( any, it.down.iterable ) ) + { + result = !result; + it.result = it.result && result; + if( !it.result ) + { + it.iterator.continue = false; + it.continue = false; + } + return; + } + } + + } + + it.result = it.result && result; + if( !it.result ) + it.iterator.continue = false; + it.continue = false; + +} + +// + +function downUpdate() +{ + let it = this; + + if( it.down ) + it.down.result = it.down.result && it.result; + +} + +// + +function equalUp() +{ + let it = this; + + _.assert( it.ascending === true ); + _.assert( arguments.length === 0, 'Expects no arguments' ); + + /* if containing mode then src2 could even don't have such entry */ + + if( it.containing ) + if( it.down && it.down.iterable === it.ContainerType.aux ) + { + if( !( it.key in it.down.src2 ) ) + { + return it.stop( false ); + } + } + + /* */ + + if( Object.is( it.src, it.src2 ) ) + { + return it.stop( true ); + } + + /* fast comparison if possible */ + + if( it.strictTyping ) + { + + if( _ObjectToString.call( it.src ) !== _ObjectToString.call( it.src2 ) ) + return it.stop( false ); + + } + else + { + if( !it.type1 || !it.type2 ) + { + if + ( + it.src === null + || it.src === undefined + || it.src2 === null + || it.src2 === undefined + ) + return it.stop( it.src === it.src2 ); + } + } + + /* */ + + it.containerIdToEqual[ it.iterable ].call( it ); + + it.equalCycle(); + +} + +// + +function equalDown() +{ + let it = this; + + _.assert( it.ascending === false ); + _.assert( arguments.length === 0, 'Expects no arguments' ); + + it.downUpdate(); + +} + +// + +function equalCycle() +{ + let it = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( !it.revisited ) + return; + if( !it.result ) + return; + + /* if cycled and strict cycling */ + if( it.strictCycling ) + { + /* if opposite branch was cycled earlier */ + if( it.down.src2 !== undefined ) + if( it.iterator.visitedContainer2 ) + { + if( _.arrayIs( it.iterator.visitedContainer2.original ) ) + { + let i = it.iterator.visitedContainer2.original.indexOf( it.down.src2 ); + if( 0 <= i && i <= it.iterator.visitedContainer2.original.length-2 ) + { + it.result = false; + it.iterator.continue = false; + it.continue = false; + } + } + else + { + /* qqq : cover revisiting : 0, ask how */ + if( it.iterator.visitedContainer2 && it.iterator.visitedContainer2.has( it.down.originalSrc2 ) ) + { + it.result = false; + it.iterator.continue = false; + it.continue = false; + } + } + } + /* or not yet cycled */ + if( it.result ) + { + if( it.iterator.visitedContainer2 && _.arrayIs( it.iterator.visitedContainer2.original ) ) + { + it.result = it + .iterator + .visitedContainer2 + .original[ it.visitedContainer.original.indexOf( it.originalSrc ) ] === it.originalSrc2; + } + if( !it.result ) + { + it.iterator.continue = false; + it.continue = false; + } + } + /* then not equal otherwise equal */ + } + else + { + if( it.level >= it.recursive ) + { + let containing = it.containing; + if( containing === 'only' ) + { + _.assert( 0, 'not tested' ); /* qqq : cover */ + containing = 'all'; + } + it.result = it.reperform( it.src2, it.src, { recursive : 0, containing } ) && it.result; + if( !it.result ) + { + it.iterator.continue = false; + it.continue = false; + } + } + } + +} + +// + +// function reperform() +// { +// let it = this; +// +// _.assert( arguments.length === 1 ); +// _.assert( it.selector !== null, () => `Iteration is not looked` ); +// _.assert +// ( +// it.iterationProper( it ), +// () => `Expects iteration of ${Self.constructor.name} but got ${_.entity.exportStringDiagnosticShallow( it )}` +// ); +// +// let it2 = it.iterationMake(); +// let args = _.longSlice( arguments ); +// if( args.length === 1 && !_.object.isBasic( args[ 0 ] ) ) +// args = [ it.src, args[ 0 ] ]; +// let o = Self.optionsFromArguments( args ); +// o.Seeker = o.Seeker || it.Seeker || Self; +// +// _.assert( _.mapIs( o ) ); +// _.map.assertHasOnly( o, { src : null, selector : null, Seeker : null }, 'Implemented only for options::selector' ); +// _.assert( _.strIs( o.selector ) ); +// _.assert( _.strIs( it2.iterator.selector ) ); +// +// it2.iterator.selector = it2.iterator.selector + _.strsShortest( it2.iterator.upToken ) + o.selector; +// // it2.iterator.prevSelectIteration = it; +// it2.iteratorSelectorChanged(); +// it2.chooseRoot( it2.src ); +// it2.iterate(); +// +// return it2.lastIt; +// } + +// + +/* xxx0 : improve */ +/* xxx : cover */ +function reperform() +{ + let it = this; + + _.assert( arguments.length === 2 || arguments.length === 3 ); + _.assert( it.selector !== null, () => `Iteration is not looked` ); + _.assert + ( + it.iterationProper( it ), + () => `Expects iteration of ${Self.constructor.name} but got ${_.entity.exportStringDiagnosticShallow( it )}` + ); + + let o = arguments[ 2 ] || Object.create( null ); + o.Seeker = o.Seeker || it.Seeker || Self; + + o.src = arguments[ 0 ]; + o.src2 = arguments[ 1 ]; + + _.assert( _.mapIs( o ) ); + _.map.assertHasOnly( o, o.Seeker, 'Implemented only for options::selector' ); + + _.assert( it.iterator.continue === true ); + + /* xxx0 : move out */ + let iterator2 = Object.create( it.iterator ); + iterator2.iterator = iterator2; + iterator2.iterationPrototype = Object.create( iterator2 ); + iterator2.firstIterationPrototype = Object.create( iterator2.iterationPrototype ); + Object.assign( iterator2.iterationPrototype, iterator2.Seeker.Iteration ); + Object.preventExtensions( iterator2.iterationPrototype ); + + _.props.extend( iterator2, o ); + let it2 = iterator2.iteratorIterationMake(); + _.assert( it2.iterator === iterator2 ); + it2.src = o.src; + it2.src2 = o.src2; + it2.chooseRoot(); + _.assert( it.Seeker.iterationProper( it2 ) ); + + it2.iterate(); + + _.assert( it.iterator.continue === true ); + return it2.result; +} + +// + +function secondCoerce() +{ + let it = this; + + if( !_.primitiveIs( it.src ) && _.routineIs( it.src[ equalSecondCoerceSymbol ] ) ) + { + it.src[ equalSecondCoerceSymbol ]( it ); + return true; + } + + if( !_.primitiveIs( it.src2 ) && _.routineIs( it.src2[ equalSecondCoerceSymbol ] ) ) + { + it.src2[ equalSecondCoerceSymbol ]( it ); + return true; + } + + return false; +} + +// + +function equalSets() +{ + let it = this; + let unpaired1 = new Set(); + let unpaired2 = new Set(); + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( it.strictTyping ) + { + if( it.type1 !== it.ContainerType.set || it.type2 !== it.ContainerType.set ) + return it.stop( false ); + } + else + { + + if( it.type1 !== it.ContainerType.set ) + it.src = new Set([ ... it.src ]); + + if( it.type2 !== it.ContainerType.set ) + it.src2 = new Set([ ... it.src2 ]); + + } + + // debugger; + // if( !_.setLike( it.src2 ) ) + // return it.stop( false ); + + if( it.containing ) + { + if( it.containing === 'all' || it.containing === 'only' ) + { + if( it.src.size > it.src2.size ) + return it.stop( false ); + } + } + else + { + if( it.src.size !== it.src2.size ) + return it.stop( false ); + } + + _.assert( _.setLike( it.src ) ); + _.assert( _.setLike( it.src2 ) ); + _.assert( !it.containing, 'not implemented' ); + + for( let e of it.src ) + unpaired1.add( e ); + for( let e of it.src2 ) + unpaired2.add( e ); + + for( let e of unpaired1 ) + { + if( unpaired2.has( e ) ) + pairFound( e, e ); + } + + for( let e1 of unpaired1 ) + { + let found = false; + for( let e2 of unpaired2 ) + { + if( equal( e1, e2 ) ) /* xxx0 : improve? */ + { + pairFound( e1, e2 ); + found = true; + break; + } + } + if( !found ) + return it.stop( false ); + } + + if( unpaired1.size || unpaired2.size ) + return it.stop( false ); + + it.continue = false; + return true; + + /* */ + + function pairFound( e1, e2 ) + { + unpaired1.delete( e1 ); + unpaired2.delete( e2 ); + } + + function equal( e1, e2 ) + { + return it.reperform( e1, e2, {} ); + } + +} + +// + +function equalCountable() +{ + let it = this; + + if( !it.src2 ) + return it.stop( false ); + + if( it.strictContainer ) + { + + if( _.bufferAnyIs( it.src ) || _.bufferAnyIs( it.src2 ) ) + return it.equalBuffers(); + + if( !it.isCountable( it.src2 ) ) + return it.stop( false ); + + } + else + { + + if( !it.type1 || !it.type2 ) + return it.stop( false ); + + if( !_.vectorLike( it.src2 ) && !_.class.methodIteratorOf( it.src2 ) ) + return it.stop( false ); + + } + + if( it.containing ) + { + if( it.containing === 'all' || it.containing === 'only' ) + { + if( _.container.lengthOf( it.src ) > _.container.lengthOf( it.src2 ) ) + return it.stop( false ); + } + } + else + { + if( _.container.lengthOf( it.src ) !== _.container.lengthOf( it.src2 ) ) + return it.stop( false ); + } + +} + +// + +function equalHashes() +{ + let it = this; + let unpaired1 = new HashMap(); + let unpaired2 = new HashMap(); + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( !_.hashMapLike( it.src2 ) ) + return it.stop( false ); + + if( it.containing ) + { + if( it.containing === 'all' || it.containing === 'only' ) + { + if( it.src.size > it.src2.size ) + return it.stop( false ); + } + } + else + { + if( it.src.size !== it.src2.size ) + return it.stop( false ); + } + + _.assert( _.hashMapLike( it.src ) ); + _.assert( _.hashMapLike( it.src2 ) ); + _.assert( !it.containing, 'not implemented' ); + + for( let [ k, e ] of it.src ) + unpaired1.set( k, e ); + for( let [ k, e ] of it.src2 ) + unpaired2.set( k, e ); + + for( let [ k1, e1 ] of unpaired1 ) + { + if( !unpaired2.has( k1 ) ) + continue; + let e2 = unpaired2.get( k1 ); + if( !equal( e1, e2 ) ) + return it.stop( false ); + pairFound( k1, k1 ); + } + + for( let [ k1, e1 ] of unpaired1 ) + { + let found = false; + for( let [ k2, e2 ] of unpaired1 ) + { + if( !equal( k1, k2 ) ) + continue; + if( !equal( e1, e2 ) ) + continue; + pairFound( k1, k2 ); + } + if( !found ) + return it.stop( false ); + } + + if( unpaired1.size || unpaired2.size ) + return it.stop( false ); + + return true; + + /* */ + + function pairFound( k1, k2 ) + { + unpaired1.delete( k1 ); + unpaired2.delete( k2 ); + } + + /* */ + + function equal( e1, e2 ) + { + return it.reperform( e1, e2, {} ); + } + +} + +// + +function equalAuxiliary() +{ + let it = this; + let types = + [ + it.ContainerType.aux, + it.ContainerType.object, + ]; + + _.assert( _.longHas( types, it.iterable ) ); + + if( !_.longHas( types, it.type1 ) || !_.longHas( types, it.type2 ) ) + return it.stop( false ); + + if( it.containing ) + { + + if( it.containing === 'only' ) + { + if( _.aux.is( it.src ) && !_.aux.is( it.src2 ) ) + return it.stop( true ); + } + else + { + if( !_.aux.is( it.src ) && _.aux.is( it.src2 ) ) + return it.stop( false ); + } + + if( it.containing === 'all' || it.containing === 'only' ) + { + if( it.type1 !== it.ContainerType.object || _.routineIs( it.src[ equalAreSymbol ] ) || 'length' in it.src ) + if( it.type2 !== it.ContainerType.object || _.routineIs( it.src2[ equalAreSymbol ] ) || 'length' in it.src2 ) + if( _.entity.lengthOf( it.src ) > _.entity.lengthOf( it.src2 ) ) + return it.stop( false ); + } + + } + else + { + + if( it.strictTyping ) + { + /* + there is no such check in contain branch because + second argument of contain-comparison does not have to be object, but may be auxiliary to give true + */ + if( _.mapIs( it.src ) ^ _.mapIs( it.src2 ) ) + return it.stop( false ); + if( _.props.keys( it.src ).length !== _.props.keys( it.src2 ).length ) + return it.stop( false ); + if( _.props.onlyOwnKeys( it.src ).length !== _.props.onlyOwnKeys( it.src2 ).length ) + return it.stop( false ); + } + else + { + if( !it.type1 || !it.type2 ) + return it.stop( false ); + if( _.props.keys( it.src ).length !== _.props.keys( it.src2 ).length ) + return it.stop( false ); + } + + } + +} + +// + +function equalObjects() +{ + let it = this; + + _.debugger; + + _.assert + ( + it.iterable === it.ContainerType.object + ); + + if( it.src && _.routineIs( it.src[ equalAreSymbol ] ) ) + { + _.assert( it.src[ equalAreSymbol ].length <= 1 ); + let r = it.src[ equalAreSymbol ]( it ); + _.assert( r === undefined, `Equalizer should return undefined, but it returned ${_.entity.strType( r )}` ); + } + else if( it.src2 && _.routineIs( it.src2[ equalAreSymbol ] ) ) + { + _.assert( it.src2[ equalAreSymbol ].length <= 1 ); + let r = it.src2[ equalAreSymbol ]( it ); + _.assert( r === undefined, `Equalizer should return undefined, but it returned ${_.entity.strType( r )}` ); + } + else if( _.regexpIs( it.src ) ) + { + return it.equalRegexps(); + } + else if( _.dateIs( it.src ) ) + { + return it.equalDates(); + } + else if( _.bufferAnyIs( it.src ) ) + { + return it.equalBuffers(); + } + else + { + if( !_.class.methodIteratorOf( it.src ) ) + return it.stop( false ); + } + +} + +// + +function equalTerminals() +{ + let it = this; + + if( it.type1 || it.type2 ) + return it.stop( false ); + + if( _.strIs( it.src ) ) + { + if( !_.strIs( it.src2 ) ) + return it.stop( false ); + return it.stop( it.onStringsAreEqual( it.onStringPreprocess( it.src ), it.onStringPreprocess( it.src2 ) ) ); + } + else if( it.strictTyping && ( _.boolIs( it.src ) || _.boolIs( it.src2 ) ) ) + { + it.stop( it.src === it.src2 ); + } + else if( !it.strictTyping && ( _.boolIs( it.src ) || _.boolIs( it.src2 ) ) ) + { + if( !_.boolLike( it.src ) || !_.boolLike( it.src2 ) ) + it.stop( false ); + else /* Yevhen : case 1 and true or false and 0 */ + it.stop + ( + ( _.boolLikeTrue( it.src ) && _.boolLikeTrue( it.src2 ) ) + || ( _.boolLikeFalse( it.src ) && _.boolLikeFalse( it.src2 ) ) + ) + } + else if( _.numberIs( it.src ) || _.bigIntIs( it.src ) ) + { + return it.stop( it.onNumbersAreEqual( it.src, it.src2 ) ); + } + else + { + if( it.strictTyping ) + return it.stop( it.src === it.src2 ); + else + return it.stop( it.src === it.src2 ); + } + +} + +// + +function equalRegexps() +{ + let it = this; + if( it.strictTyping ) + return it.stop( _.regexpIdentical( it.src, it.src2 ) ); + else + return it.stop( _.regexpEquivalent( it.src, it.src2 ) ); +} + +// + +function equalDates() +{ + let it = this; + it.stop( _.datesAreIdentical( it.src, it.src2 ) ); +} + +// + +function equalBuffers() +{ + let it = this; + + if( it.strictNumbering && it.strictTyping ) + { + return it.stop( _.buffersAreIdentical( it.src, it.src2 ) ); + } + else + { + + if( it.strictTyping ) + { + return it.stop( _.buffersAreEquivalent( it.src, it.src2, it.strictNumbering ? 0 : it.accuracy ) ); + } + else + { + let src1 = it.src; + let src2 = it.src2; + if( !_.longIs( src1 ) && _.class.methodIteratorOf( src1 ) ) + src1 = [ ... src1 ]; + if( !_.longIs( src2 ) && _.class.methodIteratorOf( src2 ) ) + src2 = [ ... src2 ]; + return it.stop( _.buffersAreEquivalent( src1, src2, it.strictNumbering ? 0 : it.accuracy ) ); + } + + } + +} + +// + +function _objectAscend( src ) +{ + let it = this; + + _.assert( it.iterator.continue === true ); + _.assert( it.continue === true ); + _.assert( arguments.length === 1 ); + + if( _.class.methodIteratorOf( src ) ) + { + + let c = 0; + for( let e of src ) + { + let eit = it.iterationMake().choose( e, c, c, true ); + eit.iterate(); + c += 1; + if( !it.canSibling() ) + break; + } + + } + +} + +// -- +// relations +// -- + +_.assert( !!_.looker.Looker.ContainerTypeToName[ 5 ] ); +_.assert( !_.looker.Looker.ContainerTypeToName[ 6 ] ); + +let last = _.looker.Looker.ContainerType.last; +let equalAreSymbol = Symbol.for( 'equalAre' ); +let equalSecondCoerceSymbol = Symbol.for( 'equalSecondCoerce' ); + +let ContainerType = +{ + ... _.looker.Looker.ContainerType, + 'object' : last+1, + 'last' : last+1, +} + +_.assert( ContainerType.hashMap >= 0 ); + +let ContainerTypeToName = +[ + ... _.looker.Looker.ContainerTypeToName, + 'object', +] + +let Ascend = +[ + ... _.looker.Looker.Ascend, + _objectAscend, +] + +/* xxx : custom */ +let containerIdToEqual = +{ + [ ContainerType.terminal ] : equalTerminals, + [ ContainerType.countable ] : equalCountable, + [ ContainerType.aux ] : equalAuxiliary, + [ ContainerType.hashMap ] : equalHashes, + [ ContainerType.set ] : equalSets, + [ ContainerType.object ] : equalObjects, +} + +// + +let LookerExtension = +{ + + constructor : function Equaler(){}, + head, + optionsFromArguments, + optionsToIteration, + iteratorInitEnd, + performBegin, + performEnd, + chooseBegin, + chooseRoot, + iterableEval, + _iterableEval, + visitPush, + visitPop, + visitUp, + visitDown, + stop, + downUpdate, + equalUp, + equalDown, + equalCycle, + reperform, /* xxx : improve */ + secondCoerce, + equalSets, + equalCountable, + equalHashes, + equalAuxiliary, + equalObjects, + equalTerminals, + equalRegexps, + equalDates, + equalBuffers, + _objectAscend, + + // feilds + + ContainerType, + ContainerTypeToName, + Ascend, + containerIdToEqual, + +} + +let Iterator = +{ + + // + + visitedContainer2 : null, + + // defaults fields + + src : undefined, + src2 : undefined, + containing : 0, + strict : 1, + revisiting : 1, + strictTyping : null, + strictNumbering : null, + strictCycling : null, + strictString : null, + strictContainer : null, + withImplicit : null, + withCountable : 'countable', + accuracy : 1e-7, + recursive : Infinity, + onNumbersAreEqual : null, + onStringsAreEqual : null, + onStringPreprocess : null, + +} + +let Iteration = Object.create( null ); +Iteration.result = true; +Iteration.originalSrc2 = null; /* qqq : cover the field */ +Iteration.type1 = null; +Iteration.type2 = null; + +let IterationPreserve = Object.create( null ); +IterationPreserve.src2 = undefined; + +const Equaler = _.looker.classDefine +({ + name : 'Equaler', + parent : _.looker.Looker, + prime : Prime, + seeker : LookerExtension, + iterator : Iterator, + iteration : Iteration, + iterationPreserve : IterationPreserve, +}); + +_.assert( !_.props.has( Equaler.Iteration, 'src2' ) || Equaler.Iteration.src2 === undefined ); +_.assert( _.props.has( Equaler.IterationPreserve, 'src2' ) && Equaler.IterationPreserve.src2 === undefined ); +_.assert( _.props.has( Equaler, 'src2' ) && Equaler.src2 === undefined ); + +// -- +// +// -- + +function _equal_head( routine, args ) +{ + return routine.defaults.head( routine, args ); +} + +// + +function _equalIt_body( it ) +{ + let it2 = _.look.body( it ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( it2 === it ); + return it; +} + +_equalIt_body.defaults = Equaler; + +let _equalIt = _.routine.uniteReplacing( _equal_head, _equalIt_body ); + +_.assert( _equalIt_body.defaults === Equaler ); +_.assert( _equalIt.body.defaults === Equaler ); +_.assert( _equalIt.defaults === Equaler ); + +// + +function _equal_body( it ) +{ + it = _.equaler._equalIt.body( it ); + return it.result; +} + +_equal_body.defaults = Equaler; + +let _equal = _.routine.uniteReplacing( _equal_head, _equal_body ); + +// + +/** + * Deep strict comparsion of two entities. Uses recursive comparsion for objects, arrays and array-like objects. + * Returns true if entities are identical. + * + * @param {*} src - Entity for comparison. + * @param {*} src2 - Entity for comparison. + * @param {wTools~entityEqualOptions} options - Comparsion options {@link wTools~entityEqualOptions}. + * @param {boolean} [ options.strictTyping = true ] - Method uses strict equality mode( '===' ). + * @returns {boolean} result - Returns true for identical entities. + * + * @example + * //returns true + * let src1 = { a : 1, b : { a : 1, b : 2 } }; + * let src2 = { a : 1, b : { a : 1, b : 2 } }; + * _.entityIdentical( src1, src2 ) ; + * + * @example + * //returns false + * let src1 = { a : '1', b : { a : 1, b : '2' } }; + * let src2 = { a : 1, b : { a : 1, b : 2 } }; + * _.entityIdentical( src1, src2 ) ; + * + * @function entityIdentical + * @function identical + * @throws {exception} If( arguments.length ) is not equal 2 or 3. + * @throws {exception} If( options ) is extended by unknown property. + * @namespace Tools + * @module Tools/base/Equaler + */ + +let entityIdentical = _.routine.uniteInheriting( _equal_head, _equal_body ); +var defaults = entityIdentical.defaults; +defaults.strict = 1; +defaults.Seeker = defaults; + +// + +function entityNotIdentical( src, src2, opts ) +{ + let it = _equal.head.call( this, entityNotIdentical, arguments ); + let result = _equal.body.call( this, it ); + it.result = !it.result; + return !result; +} + +_.routine.extendReplacing( entityNotIdentical, entityIdentical ); + +// + +/** + * Deep soft comparsion of two entities. Uses recursive comparsion for objects, arrays and array-like objects. + * By default uses own( onNumbersAreEqual ) routine to compare numbers using( options.accuracy ). Returns true if two numbers are NaN, strict equal or + * ( a - b ) <= ( options.accuracy ). For example: '_.entityEquivalent( 1, 1.5, { accuracy : .5 } )' returns true. + * + * @param {*} src1 - Entity for comparison. + * @param {*} src2 - Entity for comparison. + * @param {wTools~entityEqualOptions} options - Comparsion options {@link wTools~entityEqualOptions}. + * @param {boolean} [ options.strict = false ] - Method uses( '==' ) equality mode . + * @param {number} [ options.accuracy = 1e-7 ] - Maximal distance between two numbers. + * Example: If( options.accuracy ) is '1e-7' then 0.99999 and 1.0 are equivalent. + * @returns {boolean} Returns true if entities are equivalent. + * + * @example + * //returns true + * _.entityEquivalent( 2, 2.1, { accuracy : .2 } ); + * + * @example + * //returns true + * _.entityEquivalent( [ 1, 2, 3 ], [ 1.9, 2.9, 3.9 ], { accuracy : 0.9 } ); + * + * @function entityEquivalent + * @throws {exception} If( arguments.length ) is not equal 2 or 3. + * @throws {exception} If( options ) is extended by unknown property. + * @namespace Tools + * @module Tools/base/Equaler +*/ + +let entityEquivalent = _.routine.uniteInheriting( _equal_head, _equal_body ); + +var defaults = entityEquivalent.defaults; +defaults.strict = 0; +defaults.Seeker = defaults; + +// + +function entityNotEquivalent( src, src2, opts ) +{ + let it = _equal.head.call( this, entityNotEquivalent, arguments ); + let result = _equal.body.call( this, it ); + it.result = !it.result; + return !result; +} + +_.routine.extendReplacing( entityNotEquivalent, entityEquivalent ); + +// + +/** + * Deep contain comparsion of two entities. Uses recursive comparsion for objects, arrays and array-like objects. + * Returns true if entity( src1 ) contains keys/values from entity( src2 ) or they are indentical. + * + * @param {*} src1 - Entity for comparison. + * @param {*} src2 - Entity for comparison. + * @param {wTools~entityEqualOptions} opts - Comparsion options {@link wTools~entityEqualOptions}. + * @param {boolean} [ opts.strict = true ] - Method uses strict( '===' ) equality mode . + * @param {boolean} [ opts.containing = true ] - Check if( src1 ) contains keys/indexes and same appropriates values from( src2 ). + * @returns {boolean} Returns boolean result of comparison. + * + * @example + * //returns true + * _.entityContains( [ 1, 2, 3 ], [ 1 ] ); + * + * @example + * //returns false + * _.entityContains( [ 1, 2, 3 ], [ 1, 4 ] ); + * + * @example + * //returns true + * _.entityContains( { a : 1, b : 2 }, { a : 1 , b : 2 } ); + * + * @function entityContains + * @throws {exception} If( arguments.length ) is not equal 2 or 3. + * @throws {exception} If( opts ) is extended by unknown property. + * @namespace Tools + * @module Tools/base/Equaler +*/ + +function entityContains( src, src2, opts ) +{ + let it = _equal.head.call( this, entityContains, arguments ); + let result = _equal.body.call( this, it ); + return result; +} + +_.routine.extendInheriting( entityContains, _equal ); + +var defaults = entityContains.defaults; +defaults.containing = 'all'; +defaults.strict = 1; +defaults.strictTyping = 0; +defaults.strictNumbering = 0; +defaults.strictString = 0; +defaults.strictCycling = 1; +defaults.strictContainer = 0; /* qqq : cover option strictContainer */ +defaults.Seeker = defaults; + +_.assert( entityContains.defaults.containing === 'all' ); + +// + +function entityNotContains( src, src2, opts ) +{ + let it = _equal.head.call( this, entityNotContains, arguments ); + let result = _equal.body.call( this, it ); + it.result = !it.result; + return !result; +} + +_.routine.extendReplacing( entityNotContains, entityContains ); + +// + +function entityContainsAll( src, src2, opts ) +{ + let it = _equal.head.call( this, entityContainsAll, arguments ); + let result = _equal.body.call( this, it ); + return result; +} + +_.routine.extendInheriting( entityContainsAll, entityContains ); + +var defaults = entityContainsAll.defaults; +defaults.containing = 'all'; +defaults.Seeker = defaults; + +// + +function entityNotContainsAll( src, src2, opts ) +{ + let it = _equal.head.call( this, entityNotContainsAll, arguments ); + let result = _equal.body.call( this, it ); + it.result = !it.result; + return !result; +} + +_.routine.extendReplacing( entityNotContainsAll, entityContainsAll ); + +// + +function entityContainsAny( src, src2, opts ) +{ + let it = _equal.head.call( this, entityContainsAny, arguments ); + let result = _equal.body.call( this, it ); + return result; +} + +_.assert( entityContains.defaults.containing === 'all' ); + +_.routine.extendInheriting( entityContainsAny, entityContains ); + +var defaults = entityContainsAny.defaults; +defaults.containing = 'any'; +defaults.Seeker = defaults; + +_.assert( entityContains.defaults !== entityContainsAny.defaults ); +_.assert( entityContains.defaults.containing === 'all' ); + +// + +function entityNotContainsAny( src, src2, opts ) +{ + let it = _equal.head.call( this, entityNotContainsAny, arguments ); + let result = _equal.body.call( this, it ); + it.result = !it.result; + return !result; +} + +_.routine.extendReplacing( entityNotContainsAny, entityContainsAny ); + +// + +function entityContainsOnly( src, src2, opts ) +{ + let it = _equal.head.call( this, entityContainsOnly, arguments ); + let result = _equal.body.call( this, it ); + return result; +} + +_.routine.extendInheriting( entityContainsOnly, entityContains ); + +var defaults = entityContainsOnly.defaults; +defaults.containing = 'only'; +defaults.Seeker = defaults; + +// + +function entityNotContainsOnly( src, src2, opts ) +{ + let it = _equal.head.call( this, entityNotContainsOnly, arguments ); + let result = _equal.body.call( this, it ); + it.result = !it.result; + return !result; +} + +_.routine.extendReplacing( entityNotContainsOnly, entityContainsOnly ); + +// + +function entityContainsNone( src, src2, opts ) +{ + let it = _equal.head.call( this, entityContainsNone, arguments ); + let result = _equal.body.call( this, it ); + return result; +} + +_.routine.extendInheriting( entityContainsNone, entityContains ); + +var defaults = entityContainsNone.defaults; +defaults.containing = 'none'; +defaults.Seeker = defaults; + +// + +function entityNotContainsNone( src, src2, opts ) +{ + let it = _equal.head.call( this, entityNotContainsNone, arguments ); + let result = _equal.body.call( this, it ); + it.result = !it.result; + return !result; +} + +_.routine.extendReplacing( entityNotContainsNone, entityContainsNone ); + +_.assert( entityContains.defaults.containing === 'all' ); +_.assert( entityContainsNone.defaults.containing === 'none' ); +_.assert( entityNotContainsNone.defaults.containing === 'none' ); + +// -- +// +// -- + +Equaler.exec = _equalIt; + +let EqualerExtension = +{ + + name : 'equaler', + Equaler, + + _equalIt, + _equal, + + identical : entityIdentical, + notIdentical : entityNotIdentical, + equivalent : entityEquivalent, + notEquivalent : entityNotEquivalent, + + contains : entityContains, + notContains : entityNotContains, + containsAll : entityContainsAll, + notContainsAll : entityNotContainsAll, + containsAny : entityContainsAny, + notContainsAny : entityNotContainsAny, + containsOnly : entityContainsOnly, + notContainsOnly : entityNotContainsOnly, + containsNone : entityContainsNone, + notContainsNone : entityNotContainsNone, + + diff : entityDiff, + diffExplanation : entityDiffExplanation, /* qqq : cover and extend */ + +} + +let EntityExtension = +{ + + identical : entityIdentical, + notIdentical : entityNotIdentical, + equivalent : entityEquivalent, + notEquivalent : entityNotEquivalent, + + contains : entityContains, + notContains : entityNotContains, + containsAll : entityContainsAll, + notContainsAll : entityNotContainsAll, + containsAny : entityContainsAny, + notContainsAny : entityNotContainsAny, + containsOnly : entityContainsOnly, + notContainsOnly : entityNotContainsOnly, + containsNone : entityContainsNone, + notContainsNone : entityNotContainsNone, + + diff : entityDiff, + diffExplanation : entityDiffExplanation, + +} + +let ToolsExtension = +{ + + identical : entityIdentical, + entityIdentical, + notIdentical : entityNotIdentical, + entityNotIdentical, + equivalent : entityEquivalent, + entityEquivalent, + notEquivalent : entityNotEquivalent, + entityNotEquivalent, + + contains : entityContains, + entityContains, + notContains : entityNotContains, + entityNotContains, + containsAll : entityContainsAll, + entityContainsAll, + notContainsAll : entityNotContainsAll, + entityNotContainsAll, + containsAny : entityContainsAny, + entityContainsAny, + notContainsAny : entityNotContainsAny, + entityNotContainsAny, + containsOnly : entityContainsOnly, + entityContainsOnly, + notContainsOnly : entityNotContainsOnly, + entityNotContainsOnly, + containsNone : entityContainsNone, + entityContainsNone, + notContainsNone : entityNotContainsNone, + entityNotContainsNone, + + diff : entityDiff, + entityDiff, + diffExplanation : entityDiffExplanation, + entityDiffExplanation, + +} + +const Self = Equaler; +/* _.props.extend */Object.assign( _.equaler, EqualerExtension ); +/* _.props.extend */Object.assign( _.entity, EntityExtension ); +_.props.extend( _, ToolsExtension ); + +/* xxx +class looker should not have properties +add asserts into declare + - dst and related + - result and related + - onUp2, onDown2 +*/ + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wequaler/proto/wtools/abase/l6/Equaler.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wequaler/proto/wtools/abase/l6' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Equaler_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Equaler_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfieldsstack/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfieldsstack/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wfieldsstack */ ( function wfieldsstack() { function wfieldsstack_naked() { +module.exports = require( '../wtools/abase/l7_mixin/FieldsStack.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wFieldsStack', 'wfieldsstack' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfieldsstack/proto/node_modules/wfieldsstack' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfieldsstack/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wfieldsstack_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wfieldsstack */ })(); + +/* */ /* begin of file FieldsStack_s */ ( function FieldsStack_s() { function FieldsStack_s_naked() { ( function _FieldsStack_s_( ) +{ + +'use strict'; + +/** + * Mixin adds fields rotation mechanism to your class. It's widespread problem to change the value of a field and then after some steps revert old value, no matter what it was. FieldsStack does it for you behind the scene. FieldsStack mixins methods fieldPush, fieldPop which allocate a map of stacks of fields and manage it to avoid any corruption. Use the module to keep it simple and don't repeat yourself. + @module Tools/base/FieldsStack +*/ + +/** + * */ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + + _.include( 'wProto' ); + +} + +const _ObjectHasOwnProperty = Object.hasOwnProperty; +const _global = _global_; +const _ = _global_.wTools; + +// + +/** + * @classdesc Mixin adds fields rotation mechanism to your class. + * @class wFieldsStack + * @namespace Tools + * @module Tools/base/FieldsStack + */ + +const Parent = null; +const Self = wFieldsStack; +function wFieldsStack( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'FieldsStack'; + +// + +/** + * @summary Changes value of field `name` saving previous value + * @param { String } property - name of property + * @param {*} value - value of property + * @method fieldPush + * @module Tools/base/FieldsStack + * @namespace Tools + * @class wFieldsStack + */ + +function fieldPush( fields ) +{ + let self = this; + + if( arguments.length === 2 ) + { + _.assert( _.strIs( arguments[ 0 ] ) ); + _.assert( arguments[ 1 ] !== undefined ); + fields = { [ arguments[ 0 ] ] : arguments[ 1 ] } + } + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.mapIs( fields ) ) + + for( let s in fields ) + { + if( !self._fields[ s ] ) + self._fields[ s ] = []; + self._fields[ s ].push( self[ s ] ); + // logger.log( 'fieldPush ' + s + ' ' + _.entity.exportStringDiagnosticShallow( self[ s ] ) + ' -> ' + _.entity.exportStringDiagnosticShallow( fields[ s ] ) ); + self[ s ] = fields[ s ]; + // logger.log( 'fieldPush new value of ' + s + ' ' + self[ s ] ); + } + + return self; +} + +// + +/** + * @summary Restores previous value of field `name` + * @param { String } property - name of property + * @param {*} value - current value of property + * @method fieldPop + * @module Tools/base/FieldsStack + * @namespace Tools + * @class wFieldsStack + */ + +function fieldPop( fields ) +{ + let self = this; + let result = Object.create( null ); + + if( arguments.length === 2 ) + { + _.assert( _.strIs( arguments[ 0 ] ) ); + _.assert( arguments[ 1 ] !== undefined ); + fields = { [ arguments[ 0 ] ] : arguments[ 1 ] } + } + else if( arguments.length === 1 && _.strIs( arguments[ 0 ] ) ) + { + fields = { [ arguments[ 0 ] ] : _.nothing } + } + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.mapIs( fields ) ); + + for( let s in fields ) + { + let wasVal = fields[ s ]; + let selfVal = self[ s ]; + let _field = self._fields[ s ]; + + // logger.log( 'fieldPop ' + s + ' ' + _.entity.exportStringDiagnosticShallow( selfVal ) + ' ~ ' + _.entity.exportStringDiagnosticShallow( wasVal ) ); + + _.assert( _.arrayIs( _field ) ); + _.assert( selfVal === wasVal || wasVal === _.nothing, () => 'Decoupled fieldPop ' + _.entity.exportStringDiagnosticShallow( selfVal ) + ' != ' + _.entity.exportStringDiagnosticShallow( wasVal ) ); + self[ s ] = _field.pop(); + if( !self._fields[ s ].length ) + delete self._fields[ s ]; + result[ s ] = self[ s ]; + } + + // if( !Object.keys( result ).length === 1 ) + // debugger; + + if( Object.keys( result ).length === 1 ) + result = result[ Object.keys( result )[ 0 ] ]; + + return result; +} + +// -- +// relations +// -- + +let Composes = +{ +} + +let Aggregates = +{ +} + +let Associates = +{ +} + +let Restricts = +{ + _fields : _.define.own( {} ), +} + +let Statics = +{ +} + +// -- +// declare +// -- + +let Supplement = +{ + + fieldPush, + fieldPop, + + // + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + +} + +// + +_.classDeclare +({ + cls : Self, + supplement : Supplement, + withMixin : true, + withClass : true, +}); + +// -- +// export +// -- + +_global_[ Self.name ] = _[ Self.shortName ] = Self; + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfieldsstack/proto/wtools/abase/l7_mixin/FieldsStack.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfieldsstack/proto/wtools/abase/l7_mixin' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, FieldsStack_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file FieldsStack_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wfilesbasic */ ( function wfilesbasic() { function wfilesbasic_naked() { +module.exports = require( '../wtools/amid/l4_files/entry/Basic.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wFilesBasic', 'wfilesbasic' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/node_modules/wfilesbasic' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wfilesbasic_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wfilesbasic */ })(); + +/* */ /* begin of file Basic_s */ ( function Basic_s() { function Basic_s_naked() { ( function _Basic_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + require( '../include/Providers.s' ); + module[ 'exports' ] = _; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/entry/Basic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/entry' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Basic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Basic_s */ })(); + +/* */ /* begin of file Extract_s */ ( function Extract_s() { function Extract_s_naked() { ( function _Extract_s_() +{ + +'use strict'; + +/** + * File provider implements strategy for module files to access files in JS structure. + @module Tools/mid/FilesExtract +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + require( '../include/Extract.s' ) + module[ 'exports' ] = _; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/entry/Extract.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/entry' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Extract_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Extract_s */ })(); + +/* */ /* begin of file HardDrive_ss */ ( function HardDrive_ss() { function HardDrive_ss_naked() { ( function _HardDrive_ss_() +{ + +'use strict'; + +/** + * File provider implements strategy for module files to access files system of operating system. + @module Tools/mid/FilesHardDrive +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + require( '../include/HardDrive.ss' ) + module[ 'exports' ] = _; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/entry/HardDrive.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/entry' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, HardDrive_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file HardDrive_ss */ })(); + +/* */ /* begin of file Basic_s */ ( function Basic_s() { function Basic_s_naked() { ( function _Basic_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + + _.include( 'wProto' ); + _.include( 'wPathBasic' ); + _.include( 'wUriBasic' ); + _.include( 'wPathTools' ); + _.include( 'wRegexpObject' ); + _.include( 'wFieldsStack' ); + _.include( 'wConsequence' ); + _.include( 'wStringer' ); + _.include( 'wStringsExtra' ); + _.include( 'wVerbal' ); + + _.include( 'wSelector' ); + // _.include( 'wProcess' ); + _.include( 'wIntrospectorBasic' ); + _.include( 'wLogger' ); + _.include( 'wWebUriBasic' ); + + _.include( 'wGdf' ); /* xxx2 : remove */ + + _.assert( !!_.FieldsStack ); + + module[ 'exports' ] = _; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include/Basic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Basic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Basic_s */ })(); + +/* */ /* begin of file Extract_s */ ( function Extract_s() { function Extract_s_naked() { ( function _Extract_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + + // _.include( 'wFilesBasic' ); + require( '../l7_provider/Extract.s' ); + + module[ 'exports' ] = _; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include/Extract.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Extract_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Extract_s */ })(); + +/* */ /* begin of file HardDrive_ss */ ( function HardDrive_ss() { function HardDrive_ss_naked() { ( function _HardDrive_ss_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + + // _.include( 'wFilesBasic' ); + require( '../l7_provider/HardDrive.ss' ); + + module[ 'exports' ] = _; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include/HardDrive.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, HardDrive_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file HardDrive_ss */ })(); + +/* */ /* begin of file Mid_s */ ( function Mid_s() { function Mid_s_naked() { ( function _Mid_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( './Basic.s' ); + + require( '../l1/Namespace.s' ); + + require( '../l2/Encoder.s' ); + require( '../l2/Encoders.s' ); + require( '../l2/Linker.s' ); + require( '../l2/RecordContext.s' ); + + require( '../l3/Path.s' ); + if( Config.interpreter === 'njs' ) + require( '../l3/Path.ss' ); + require( '../l3/Record.s' ); + require( '../l3/RecordFactory.s' ); + require( '../l3/RecordFilter.s' ); + require( '../l3/StatClass.s' ); + require( '../l3/StatNamespace.s' ); + + require( '../l4/Abstract.s' ); + + require( '../l5/Partial.s' ); + require( '../l6/System.s' ); + + require( './MixinFind.s' ); + require( './MixinConfig.s' ); + require( './MixinSecondary.s' ); + require( './MixinTemp.s' ); + + module[ 'exports' ] = _; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include/Mid.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Mid_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Mid_s */ })(); + +/* */ /* begin of file MixinConfig_s */ ( function MixinConfig_s() { function MixinConfig_s_naked() { ( function _MixinConfig_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + + require( '../l7/ConfigMixin.s' ); + + module[ 'exports' ] = _; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include/MixinConfig.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, MixinConfig_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file MixinConfig_s */ })(); + +/* */ /* begin of file MixinFind_s */ ( function MixinFind_s() { function MixinFind_s_naked() { ( function _MixinFind_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + + // _.include( 'wFilesBasic' ); + require( '../l6/FindMixin.s' ); + + module[ 'exports' ] = _; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include/MixinFind.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, MixinFind_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file MixinFind_s */ })(); + +/* */ /* begin of file MixinSecondary_s */ ( function MixinSecondary_s() { function MixinSecondary_s_naked() { ( function _MixinSecondary_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + + require( '../l7/SecondaryMixin.s' ); + + module[ 'exports' ] = _; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include/MixinSecondary.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, MixinSecondary_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file MixinSecondary_s */ })(); + +/* */ /* begin of file MixinTemp_s */ ( function MixinTemp_s() { function MixinTemp_s_naked() { ( function _MixinFind_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + + // _.include( 'wFilesBasic' ); + require( '../l7/TempMixin.s' ); + + module[ 'exports' ] = _; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include/MixinTemp.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, MixinTemp_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file MixinTemp_s */ })(); + +/* */ /* begin of file Providers_s */ ( function Providers_s() { function Providers_s_naked() { ( function _Providers_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( './Mid.s' ); + + /* l7_provider */ + + require( './Extract.s' ); + if( Config.interpreter === 'njs' ) + require( './HardDrive.ss' ); + + module[ 'exports' ] = _; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include/Providers.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Providers_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Providers_s */ })(); + +/* */ /* begin of file Namespace_s */ ( function Namespace_s() { function Namespace_s_naked() { ( function _Namespace_s_() +{ + +'use strict'; + +/** + * @namespace Tools.files + * @module Tools/mid/Files + */ + +/** + * @namespace wTools.files.FileProvider + * @module Tools/mid/Files + */ + +/** + * @namespace wTools.files.FileFilter + * @module Tools/mid/Files + */ + +/** + * @namespace wTools.files.ReadEncoders + * @module Tools/mid/Files + */ + +/** + * @namespace wTools.files.WriteEncoders + * @module Tools/mid/Files + */ + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.files = _.files || Object.create( null ); +let Crypto; + +_.FileProvider = _.files.FileProvider = _.FileProvider || _.files.FileProvider || Object.create( null ); +_.FileFilter = _.files.FileFilter = _.FileFilter || _.files.FileFilter || Object.create( null ); +_.files.ReadEncoders = _.files.ReadEncoders || Object.create( null ); +_.files.WriteEncoders = _.files.WriteEncoders || Object.create( null ); +_.files._ = _.files._ || Object.create( null ); + +_.assert( !!_.FieldsStack ); +_.assert( !_.files.FileRecord ); +_.assert( !_.files.FileRecordFactory ); +_.assert( !_.files.FileRecordFilter ); +_.assert( !_.files.FileStat ); + +// -- +// meta +// -- + +let vectorize = _.routineDefaults( null, _.vectorize, { vectorizingContainerAdapter : 1, unwrapingContainerAdapter : 0 } ); +let vectorizeAll = _.routineDefaults( null, _.vectorizeAll, { vectorizingContainerAdapter : 1, unwrapingContainerAdapter : 0 } ); +let vectorizeAny = _.routineDefaults( null, _.vectorizeAny, { vectorizingContainerAdapter : 1, unwrapingContainerAdapter : 0 } ); +let vectorizeNone = +_.routineDefaults( null, _.vectorizeNone, { vectorizingContainerAdapter : 1, unwrapingContainerAdapter : 0 } ); + +// + +function vectorizeKeysAndVals( routine, select ) +{ + select = select || 1; + + let routineName = routine.name; + + _.assert( _.routineIs( routine ) ); + _.assert( _.strDefined( routineName ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + let routine2 = _.routineVectorize_functor + ({ + routine : [ routineName ], + vectorizingArray : 1, + vectorizingMapVals : 1, + vectorizingMapKeys : 1, + select, + }); + + _.routineExtend( routine2, routine ); + + return routine2; +} + + +// -- +// implementation +// -- + +/** + * @description Creates RegexpObject based on passed path, array of paths, or RegexpObject. + * Paths turns into regexps and adds to 'includeAny' property of result Object. + * Methods adds to 'excludeAny' property the next paths by default : + * 'node_modules', + * '.unique', + * '.git', + * '.svn', + * /(^|\/)\.(?!$|\/|\.)/, // any hidden paths + * /(^|\/)-(?!$|\/)/, + * @example + * let paths = + * { + * includeAny : [ 'foo/bar', 'foo2/bar2/baz', 'some.txt' ], + * includeAll : [ 'index.js' ], + * excludeAny : [ 'Gruntfile.js', 'gulpfile.js' ], + * excludeAll : [ 'package.json', 'bower.json' ] + * }; + * let regObj = regexpAllSafe( paths ); + * + * @param {string|string[]|RegexpObject} [mask] + * @returns {RegexpObject} + * @throws {Error} if passed more than one argument. + * @see {@link wTools~RegexpObject} RegexpObject + * @function regexpAllSafe + * @namespace wTools.files + * @module Tools/mid/Files + */ + +function regexpAllSafe( mask ) +{ + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + let excludeMask = _.RegexpObject + ({ + excludeAny : + [ + // /(\W|^)node_modules(\W|$)/, + // /\.unique(?:$|\/)/, + // /\.git(?:$|\/)/, + // /\.svn(?:$|\/)/, + // /\.hg(?:$|\/)/, + // /\.DS_Store(?:$|\/)/, + // /\.tmp(?:$|\/)/, + /\.(?:unique|git|svn|hg|DS_Store|tmp)(?:$|\/)/, + /(^|\/)-/, + ], + }); + + if( mask ) + { + mask = _.RegexpObject( mask || Object.create( null ), 'includeAny' ); + excludeMask = excludeMask.and( mask ); + } + + return excludeMask; +} + +// + +function regexpTerminalSafe( mask ) +{ + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + let excludeMask = _.RegexpObject + ({ + excludeAny : [], + }); + + if( mask ) + { + mask = _.RegexpObject( mask || Object.create( null ), 'includeAny' ); + excludeMask = excludeMask.and( mask ); + } + + return excludeMask; +} + +// + +function regexpDirSafe( mask ) +{ + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + let excludeMask = _.RegexpObject + ({ + excludeAny : + [ + /(^|\/)\.(?!$|\/|\.)/, + // /(^|\/)-/, + ], + }); + + if( mask ) + { + mask = _.RegexpObject( mask || Object.create( null ), 'includeAny' ); + excludeMask = excludeMask.and( mask ); + } + + return excludeMask; +} + +// + +function filterSafer( filter ) +{ + _.assert( filter === null || _.mapIs( filter ) || filter instanceof _.files.FileRecordFilter ); + + filter = filter || Object.create( null ); + + filter.maskAll = _.files.regexpAllSafe( filter.maskAll ); + filter.maskTerminal = _.files.regexpTerminalSafe( filter.maskTerminal ); + filter.maskDirectory = _.files.regexpDirSafe( filter.maskDirectory ); + filter.maskTransientAll = _.files.regexpAllSafe( filter.maskTransientAll ); + // filter.maskTransientTerminal = _.files.regexpTerminalSafe( filter.maskTransientTerminal ); + filter.maskTransientDirectory = _.files.regexpDirSafe( filter.maskTransientDirectory ); + + return filter; +} + +// -- +// etc +// -- + +/** + * Return o for file red/write. If `filePath is an object, method returns it. Method validate result option + properties by default parameters from invocation context. + * @param {string|Object} filePath + * @param {Object} [o] Object with default o parameters + * @returns {Object} Result o + * @private + * @throws {Error} If arguments is missed + * @throws {Error} If passed extra arguments + * @throws {Error} If missed `PathFiile` + * @function _fileOptionsGet + * @namespace wTools.files + * @module Tools/mid/Files + */ + +function _fileOptionsGet( filePath, o ) /* xxx : check */ +{ + o = o || Object.create( null ); + + if( _.object.isBasic( filePath ) ) + { + o = filePath; + } + else + { + o.filePath = filePath; + } + + if( !o.filePath ) + throw _.err( 'Expects "o.filePath"' ); + + _.map.assertHasOnly( o, this.defaults ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( o.sync === undefined ) + o.sync = 1; + + return o; +} + +// + +/** + * Returns path/stats associated with file with newest modified time. + * @example + * let fs = require('fs'); + + let path1 = 'tmp/sample/file1', + path2 = 'tmp/sample/file2', + buffer = BufferNode.from( [ 0x01, 0x02, 0x03, 0x04 ] ); + + wTools.fileWrite( { filePath : path1, data : buffer } ); + setTimeout( function() + { + wTools.fileWrite( { filePath : path2, data : buffer } ); + + + let newer = wTools.filesNewer( path1, path2 ); + // 'tmp/sample/file2' + }, 100); + * @param {string|File.Stats} dst first file path/stat + * @param {string|File.Stats} src second file path/stat + * @returns {string|File.Stats} + * @throws {Error} if type of one of arguments is not string/file.Stats + * @function filesNewer + * @namespace wTools.files + * @module Tools/mid/Files + */ + +function filesNewer( dst, src ) +{ + let odst = dst; + let osrc = src; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.fileStatIs( src ) ) + src = { stat : src }; + else if( _.strIs( src ) ) + src = { stat : _.fileProvider.statRead( src ) }; + else if( !_.object.isBasic( src ) ) + throw _.err( 'unknown src type' ); + + if( _.fileStatIs( dst ) ) + dst = { stat : dst }; + else if( _.strIs( dst ) ) + dst = { stat : _.fileProvider.statRead( dst ) }; + else if( !_.object.isBasic( dst ) ) + throw _.err( 'unknown dst type' ); + + + let timeSrc = _.entityMax( [ src.stat.mtime/* , src.stat.birthtime */ ] ).value; + let timeDst = _.entityMax( [ dst.stat.mtime/* , dst.stat.birthtime */ ] ).value; + + // When mtime of the file is changed by timeWrite( fs.utime ), there is difference between passed and setted value. + // if( _.number.equivalent.call( { accuracy : 500 }, timeSrc.getTime(), timeDst.getTime() ) ) + // return null; + + if( timeSrc > timeDst ) + return osrc; + else if( timeSrc < timeDst ) + return odst; + + return null; +} + +// + +/** + * Returns path/stats associated with file with older modified time. + * @example + * let fs = require('fs'); + + let path1 = 'tmp/sample/file1', + path2 = 'tmp/sample/file2', + buffer = BufferNode.from( [ 0x01, 0x02, 0x03, 0x04 ] ); + + wTools.fileWrite( { filePath : path1, data : buffer } ); + setTimeout( function() + { + wTools.fileWrite( { filePath : path2, data : buffer } ); + + let newer = wTools.filesOlder( path1, path2 ); + // 'tmp/sample/file1' + }, 100); + * @param {string|File.Stats} dst first file path/stat + * @param {string|File.Stats} src second file path/stat + * @returns {string|File.Stats} + * @throws {Error} if type of one of arguments is not string/file.Stats + * @function filesOlder + * @namespace wTools.files + * @module Tools/mid/Files + */ + +function filesOlder( dst, src ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + let result = filesNewer( dst, src ); + + if( result === dst ) + return src; + else if( result === src ) + return dst; + else + return null; + +} + +// + +/** + * Returns spectre of file content. + * @example + * let path = '/home/tmp/sample/file1', + * textData1 = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'; + * + * wTools.fileWrite( { filePath : path, data : textData1 } ); + * let spectre = wTools.filesSpectre( path ); + * //{ + * // L : 1, + * // o : 4, + * // r : 3, + * // e : 5, + * // m : 3, + * // ' ' : 7, + * // i : 6, + * // p : 2, + * // s : 4, + * // u : 2, + * // d : 2, + * // l : 2, + * // t : 5, + * // a : 2, + * // ',' : 1, + * // c : 3, + * // n : 2, + * // g : 1, + * // '.' : 1, + * // length : 56 + * // } + * @param {string|wFileRecord} src absolute path or FileRecord instance + * @returns {Object} + * @throws {Error} If count of arguments are different from one. + * @throws {Error} If `src` is not absolute path or FileRecord. + * @function filesSpectre + * @namespace wTools.files + * @module Tools/mid/Files +*/ + +function filesSpectre( src ) /* xxx : redo or remove */ +{ + + _.assert( arguments.length === 1, 'filesSpectre :', 'expect single argument' ); + + src = _.fileProvider.recordFactory().record( src ); + let read = src.read; + + if( !read ) + read = _.FileProvider.HardDrive().fileRead + ({ + filePath : src.absolute, + // silent : 1, + // returnRead : 1, + }); + + return _.strLattersSpectre( read ); +} + +// + +/** + * Compares specters of two files. Returns the rational number between 0 and 1. For the same specters returns 1. If + * specters do not have the same letters, method returns 0. + * @example + * let path1 = 'tmp/sample/file1', + * path2 = 'tmp/sample/file2', + * textData1 = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'; + * + * wTools.fileWrite( { filePath : path1, data : textData1 } ); + * wTools.fileWrite( { filePath : path2, data : textData1 } ); + * let similarity = wTools.filesSimilarity( path1, path2 ); // 1 + * @param {string} src1 path string 1 + * @param {string} src2 path string 2 + * @param {Object} [o] + * @param {Function} [onReady] + * @returns {number} + * @function filesSimilarity + * @namespace wTools.files + * @module Tools/mid/Files +*/ + +function filesSimilarity( o ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options_( filesSimilarity, o ); + + o.src1 = _.fileProvider.recordFactory().record( o.src1 ); + o.src2 = _.fileProvider.recordFactory().record( o.src2 ); + + let latters1 = _.files.filesSpectre( o.src1.absolute ); + let latters2 = _.files.filesSpectre( o.src2.absolute ); + + let result = _.strLattersSpectresSimilarity( latters1, latters2 ); + + return result; +} + +filesSimilarity.defaults = +{ + src1 : null, + src2 : null, +} + +// + +function filesShadow( shadows, owners ) /* xxx : check */ +{ + + for( let s = 0 ; s < shadows.length ; s++ ) + { + let shadow = shadows[ s ]; + shadow = _.object.isBasic( shadow ) ? shadow.relative : shadow; + + for( let o = 0 ; o < owners.length ; o++ ) + { + + let owner = owners[ o ]; + + owner = _.object.isBasic( owner ) ? owner.relative : owner; + + if( _.strBegins( shadow, _.path.prefixGet( owner ) ) ) + { + shadows.splice( s, 1 ); + s -= 1; + break; + } + + } + + } + +} + +// + +function fileReport( file ) /* xxx : rename */ +{ + let report = ''; + + file = _.files.FileRecord( file ); + + let fileTypes = {}; + + if( file.stat ) + { + fileTypes.isFile = file.stat.isFile(); + fileTypes.isDirectory = file.stat.isDirectory(); + fileTypes.isBlockDevice = file.stat.isBlockDevice(); + fileTypes.isCharacterDevice = file.stat.isCharacterDevice(); + fileTypes.isSymbolicLink = file.stat.isSymbolicLink(); + fileTypes.isFIFO = file.stat.isFIFO(); + fileTypes.isSocket = file.stat.isSocket(); + } + + report += _.entity.exportString( file, { levels : 2, wrap : 0 } ); + report += '\n'; + report += _.entity.exportString( file.stat, { levels : 2, wrap : 0 } ); + report += '\n'; + report += _.entity.exportString( fileTypes, { levels : 2, wrap : 0 } ); + + return report; +} + +// + +function hashFrom( o ) +{ + + if( !_.mapIs( arguments[ 0 ] ) ) + o = { src : arguments[ 0 ] } + _.routine.options_( hashFrom, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + return _.files.hashMd5From( o ); +} + +hashFrom.defaults = +{ + src : null, +} + +// + +function hashSzFrom( o ) +{ + + if( !_.mapIs( arguments[ 0 ] ) ) + o = { src : arguments[ 0 ] } + _.routine.options_( hashSzFrom, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( !_.streamIs( o.src ), 'not implemented' ); /* qqq : implement */ + + let result = _.files.hashMd5From( o ); + + if( !result ) + return result; + + let size = _.entity.sizeOf( o.src, 0 ); + _.assert( _.numberIs( size ) ); + result = size + '-' + result; + + return result; +} + +hashSzFrom.defaults = +{ + ... hashFrom.defaults, +} + +// + +function hashMd5From( o ) +{ + + if( !_.mapIs( arguments[ 0 ] ) ) + o = { src : arguments[ 0 ] } + _.routine.options_( hashMd5From, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( Crypto === undefined ) + Crypto = require( 'crypto' ); + let md5sum = Crypto.createHash( 'md5' ); + + /* */ + + if( _.streamIs( o.src ) ) + { + let con = new _.Consequence(); + let done = false; + + o.src.on( 'data', function( d ) + { + md5sum.update( d ); + }); + + o.src.on( 'end', function() + { + if( done ) + return; + done = true; + let hash = md5sum.digest( 'hex' ); + con.take( hash ); + }); + + o.src.on( 'error', function( err ) + { + if( done ) + return; + done = true; + con.error( _.err( err ) ); + }); + + return con; + } + else + { + let result; + try + { + o.src = _.bufferNodeFrom( o.src ); + md5sum.update( o.src ); + result = md5sum.digest( 'hex' ); + } + catch( err ) + { + _.errAttend( err ); + throw err; + } + return result; + } + + /* */ + +} + +hashMd5From.defaults = +{ + ... hashFrom.defaults, +} + +// + +function nodeJsIsSameOrNewer( src ) /* xxx : rename */ +{ + _.assert( arguments.length === 1 ); + _.assert( _.longIs( src ) ); + _.assert( src.length === 3 ); + _.assert( !!_global.process ); + + let parsed = /^v(\d+).(\d+).(\d+)/.exec( _global.process.version ); + for( let i = 1; i < 4; i++ ) + { + if( parsed[ i ] < src[ i - 1 ] ) + return false; + + if( parsed[ i ] > src[ i - 1 ] ) + return true; + } + + return true; +} + +// -- +// declaration +// -- + +let Restricts = +{ + + vectorize, + vectorizeAll, + vectorizeAny, + vectorizeNone, + + vectorizeKeysAndVals, /* zzz : required? */ + +} + +_.props.supplement( _.files._, Restricts ); + +// + +let FilesExtension = +{ + + // regexp + + regexpMakeSafe : regexpAllSafe, + regexpAllSafe, + regexpTerminalSafe, + regexpDirSafe, + filterSafer, + + // etc + + _fileOptionsGet, + + filesNewer, + filesOlder, + + filesSpectre, + filesSimilarity, + + filesShadow, + + fileReport, + + nodeJsIsSameOrNewer, + + hashFrom, /* qqq : cover */ + hashMd5From, /* qqq : cover */ + hashSzFrom, /* qqq : cover */ + + // fields + + +} + +_.props.supplement( _.files, FilesExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l1/Namespace.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Namespace_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Namespace_s */ })(); + +/* */ /* begin of file Encoder_s */ ( function Encoder_s() { function Encoder_s_naked() { ( function _Namespace_s_() +{ + +'use strict'; + +/** + * @namespace Tools.files.encoder + * @module Tools/mid/Files + */ + +const _global = _global_; +const _ = _global_.wTools; +_.files = _.files || Object.create( null ); +_.files.encoder = _.files.encoder || Object.create( null ); + +// -- +// encoder +// -- + +function is( encoder ) +{ + if( !encoder ) + return false; + if( !encoder.feature ) + return false; + if( !encoder.exts ) + return false; + return true; +} + +// + +function finit( encoder ) +{ + _.assert( _.files.encoder.is( encoder ) ); + let collectionMap = encoder.feature.reader ? _.files.ReadEncoders : _.files.WriteEncoders; + + for( let k in collectionMap ) + { + if( collectionMap[ k ] === encoder ) + delete collectionMap[ k ]; + } + + Object.freeze( encoder ); +} + +// + +function _normalize( o ) +{ + + o = _.routine.options_( _normalize, o ); + if( _.strIs( o.exts ) ) + o.exts = [ o.exts ]; + else if( o.exts === null ) + o.exts = []; + + _.assert( arguments.length === 1 ); + _.assert( _.mapIs( o.feature ) ); + _.assert( _.longIs( o.exts ) ); + _.assert( o.feature.reader || o.feature.writer ); + + let collectionMap = o.feature.reader ? _.files.ReadEncoders : _.files.WriteEncoders; + + if( o.name === null ) + { + if( o.exts.length ) + o.name = nameGenerate(); + else + o.name = o.gdf.shortName; + } + _.assert( _.strDefined( o.name ) ); + // _.assert( _.routineIs( o.onData ) ); /* xxx : implement */ + + return o; + + /* */ + + function nameGenerate() + { + let name = o.exts[ 0 ]; + let counter = 2; + while( collectionMap[ name ] !== undefined ) + { + debugger; + name = o.exts[ 0 ] + '.' + counter; + } + return name; + } + +} + +_normalize.defaults = +{ + + name : null, + exts : null, + feature : null, + gdf : null, + + onBegin : null, + onEnd : null, + onError : null, /* xxx : remove */ + onData : null, + onSelect : null, + +} + +// + +function _registerWithExt( o, ext ) +{ + + o = _.files.encoder._normalize( o ); + + let collectionMap = o.feature.reader ? _.files.ReadEncoders : _.files.WriteEncoders; + // let name = ext ? ext : o.name; + let name = ext ? ext : ( o.name || o.gdf.shortName ); + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( ext === undefined || _.strDefined( ext ) ); + _.assert( _.strDefined( name ) ); + + if( collectionMap[ name ] !== undefined ) + { + let encoder2 = collectionMap[ o.name ]; + if( encoder2 === o ) + return encoder2; + if( encoder2.gdf === o.gdf ) + return encoder2; + if( !o.feature.default ) + return encoder2; + if( encoder2.feature.default ) + { + debugger; + throw _.err( `Several ${name} GDF encoders set as default` ); + } + } + + // console.log( `Registered encoder::${name}` ); + + collectionMap[ name ] = o; + return o; +} + +_registerWithExt.defaults = +{ + + ... _normalize.defaults, + +} + +// + +function gdfRegister( gdf ) +{ + let result = Object.create( null ); + // _.assert( gdf.ext.length > 0 ); + _.assert( gdf instanceof _.gdf.Encoder ); + + if( gdf.inFormat.includes( 'structure' ) ) + result.writer = _.files.encoder.writerFromGdf( gdf ); + + if( gdf.outFormat.includes( 'structure' ) ) + result.reader = _.files.encoder.readerFromGdf( gdf ); + + if( result.reader && result.writer ) + debugger; + return result; +} + +// + +function withGdf( gdf ) +{ + let result = Object.create( null ); + // _.assert( gdf.ext.length > 0 ); + _.assert( gdf instanceof _.gdf.Encoder ); + + if( gdf.inFormat.includes( 'structure' ) ) + if( _writerFromGdfCache.has( gdf ) ) + result.writer = _writerFromGdfCache.get( gdf ); + + if( gdf.outFormat.includes( 'structure' ) ) + if( _readerFromGdfCache.has( gdf ) ) + result.reader = _readerFromGdfCache.get( gdf ); + + if( result.reader && result.writer ) + debugger; + return result; +} + +// + +function _fromGdf( gdf ) +{ + + // _.assert( gdf.ext.length > 0 ); + _.assert( gdf instanceof _.gdf.Encoder ); + + let encoder = Object.create( null ); + encoder.gdf = gdf; + encoder.exts = gdf.ext.slice(); + + encoder.feature = Object.create( null ); + if( gdf.feature.config ) /* xxx : remove the feature */ + encoder.feature.config = true; + if( gdf.feature.default ) + encoder.feature.default = true; + + return encoder; +} + +// + +let _writerFromGdfCache = new HashMap; +function writerFromGdf( gdf ) +{ + + if( _writerFromGdfCache.has( gdf ) ) + return _writerFromGdfCache.get( gdf ); + + let encoder = _.files.encoder._fromGdf( gdf ); + encoder.feature.writer = true; + + encoder.onBegin = function( op ) + { + let encoded = op.encoder.gdf.encode({ data : op.operation.data, params : op.operation }); + op.operation.data = encoded.out.data; + if( encoded.out.format === 'string' || encoded.out.format === 'string.utf8' || encoded.out.format === 'utf8.string' ) + op.operation.encoding = 'utf8'; + else + op.operation.encoding = encoded.out.format; + } + + if( !gdf.ext.length ) + { + _.files.encoder._registerWithExt( encoder ); + } + else + _.each( gdf.ext, ( ext ) => + { + _.files.encoder._registerWithExt( encoder, ext ); + }) + + _writerFromGdfCache.set( gdf, encoder ); + return encoder; +} + +// + +let _readerFromGdfCache = new HashMap; +function readerFromGdf( gdf ) +{ + + if( _readerFromGdfCache.has( gdf ) ) + return _readerFromGdfCache.get( gdf ); + + let encoder = _.files.encoder._fromGdf( gdf ); + encoder.feature.reader = true; + let expectsString = gdf.inFormatSupports( 'string' ); + + encoder.onBegin = function( op ) + { + if( expectsString ) + op.operation.encoding = 'utf8'; + else + op.operation.encoding = op.encoder.gdf.inFormat[ 0 ]; + } + + encoder.onEnd = function( op ) /* zzz : should be onData */ + { + let decoded = op.encoder.gdf.encode({ data : op.data, params : op.operation }); + op.data = decoded.out.data; + } + + if( !gdf.ext.length ) + { + _.files.encoder._registerWithExt( encoder ); + } + else + _.each( gdf.ext, ( ext ) => + { + _.files.encoder._registerWithExt( encoder, ext ); + }) + + _readerFromGdfCache.set( gdf, encoder ); + return encoder; +} + +// + +function fromGdfs() +{ + _.assert( _.routine.is( _.Gdf ), 'module::Gdf is required to generate encoders!' ); + _.assert( _.mapIs( _.gdf.inMap ) ); + _.assert( _.mapIs( _.gdf.outMap ) ); + + for( let k in _.gdf.inOutMap ) + { + if( !_.strHas( k, 'structure' ) ) + continue; + var defaults = _.filter_( null, _.gdf.inOutMap[ k ], ( c ) => c.feature.default ? c : undefined ); + if( defaults.length > 1 ) + { + debugger; + throw _.err( `Several default converters for '${k}' in-out combination:`, _.select( defaults, '*/name' ) ); + } + } + + let writeGdf = _.gdf.inMap[ 'structure' ]; + let readGdf = _.gdf.outMap[ 'structure' ]; + + let WriteEndoders = Object.create( null ); + let ReadEncoders = Object.create( null ); + + writeGdf.forEach( ( gdf ) => + { + // if( gdf.shortName === 'js.structure.exported' ) + // debugger; + let encoder = _.files.encoder.writerFromGdf( gdf ); + }) + + /* */ + + readGdf.forEach( ( gdf ) => + { + let encoder = _.files.encoder.readerFromGdf( gdf ); + _.assert( gdf.ext.length > 0 ); + }) + + /* */ + + for( let k in _.files.ReadEncoders ) + { + let gdf = _.files.ReadEncoders[ k ].gdf; + if( gdf ) + if( !_.longHas( readGdf, gdf ) || !_.longHas( gdf.ext, k ) ) + { + _.assert( 0, 'not tested' ); + delete _.files.ReadEncoders[ k ] + } + } + + for( let k in _.files.WriteEncoders ) + { + let gdf = _.files.WriteEncoders[ k ].gdf; + if( gdf ) + if( !_.longHas( writeGdf, gdf ) || ( gdf.ext.length && !_.longHas( gdf.ext, k ) ) ) + { + debugger; + delete _.files.WriteEncoders[ k ]; + } + } + + /* */ + + _.assert( _.mapIs( _.files.ReadEncoders ) ); + _.assert( _.mapIs( _.files.WriteEncoders ) ); + + Object.assign( _.files.ReadEncoders, ReadEncoders ); + Object.assign( _.files.WriteEncoders, WriteEndoders ); +} + +// + +function gdfsWatch() +{ + + _.gdf.on( 'gdf.form', ( e ) => + { + _.files.encoder.gdfRegister( e.gdf ); + }); + + _.gdf.on( 'gdf.unform', ( e ) => + { + debugger; + let r = _.files.encoder.withGdf( e.gdf ); + if( r.writer ) + _.files.encoder.finit( r.writer ); + if( r.reader ) + _.files.encoder.finit( r.reader ); + // _.assert( 0, 'not implemented' ); + }); + +} + +// + +function deduce( o ) +{ + let result = []; + + o = _.routine.options_( deduce, arguments ); + + if( o.filePath && !o.ext ) + o.ext = _.path.ext( o.filePath ); + if( o.ext ) + o.ext = o.ext.toLowerCase(); + + _.assert( _.strIs( o.ext ) || o.ext === null ); + _.assert( _.mapIs( o.feature ) ); + _.assert( o.feature.writer || o.feature.reader ); + _.assert( _.mapIs( _.gdf.inMap ) ); + _.assert( _.mapIs( _.gdf.outMap ) ); + _.assert( o.returning === 'name' || o.returning === 'encoder' ); + + let fromMethodName = o.feature.writer ? 'writerFromGdf' : 'readerFromGdf'; + let typeMap = o.feature.writer ? _.gdf.outMap : _.gdf.inMap; + let encodersMap = o.feature.writer ? _.files.WriteEncoders : _.files.ReadEncoders; + + if( o.ext ) + if( encodersMap[ o.ext ] ) + { + let encoder = encodersMap[ o.ext ]; + _.assert( _.object.isBasic( encoder ), `Write encoder ${o.ext} is missing` ); + _.assert( _.longHas( encoder.exts, o.ext ) ); + _.arrayAppendOnce( result, encoder ); + } + + result = filterAll( result ); + + if( !o.single || !result.length ) + for( let i = 0 ; i < _.files.encoder.gdfTypesForFiles.length ; i++ ) + { + let type = _.files.encoder.gdfTypesForFiles[ i ]; + if( !typeMap[ type ] ) + continue; + for( let i2 = 0 ; i2 < typeMap[ type ].length ; i2++ ) + { + let gdf = typeMap[ type ][ i2 ]; + if( gdf.ext.length === 0 ) + continue; + let o2 = _.mapBut_( null, o, [ 'single', 'returning', 'feature', 'format' ] ); + if( o.feature.reader ) + o2.inFormat = o.format; + else + o2.outFormat = o.format; + let supports = gdf.supports( o2 ); + // if( supports ) + // debugger; + if( supports ) + _.arrayAppendOnce( result, _.files.encoder[ fromMethodName ]( gdf ) ); + } + } + + result = filterAll( result ); + + if( o.single ) + { + if( result.length > 1 ) + _.entity.filter_( result, result, ( encoder ) => encoder.feature.default ? encoder : undefined ); + + _.assert + ( + result.length >= 1, + () => `Found no reader for format:${o.format} ext:${o.ext} filePath:${o.filePath}.` + ); + _.assert + ( + result.length <= 1, + () => `Found ${result.length} readers for format:${o.format} ext:${o.ext} filePath:${o.filePath}, but need only one.` + ); + if( o.returning === 'name' ) + return result[ 0 ].name; + else + return result[ 0 ]; + } + + if( o.returning === 'name' ) + return result.map( ( encoder ) => encoder.name ); + else + return result; + + function filterAll( encoders ) + { + if( o.feature === null ) + return encoders; + if( _.props.keys( o.feature ).length === 0 ) + return encoders; + return _.filter_( encoders, encoders, ( encoder ) => + { + let satisfied = _.objectSatisfy + ({ + src : encoder.feature, + template : o.feature, + levels : 1, + strict : false, + }); + if( satisfied ) + return encoder; + }); + } +} + +deduce.defaults = +{ + data : null, + format : null, + filePath : null, + ext : null, + feature : null, + single : 1, + returning : 'name', +} + +// + +function _for( o ) +{ + + _.routine.options( _for, o ); + + if( o.encoding === _.unknown ) /* qqq : cover */ + { + o.encoder = _.files.encoder.deduce + ({ + filePath : o.filePath, + ext : o.ext, + format : o.format, + data : o.data, + feature : o.feature, + returning : 'encoder', + single : 1, + }); + _.assert( _.strDefined( o.encoder.name ) ); + o.encoding = o.encoder.name; + return o; + } + + o.encoder = _.files.ReadEncoders[ o.encoding ]; + + if( !o.encoder ) + return o; + + if( o.encoder.onSelect ) + return o.encoder.onSelect( o ); + + return o; +} + +_for.defaults = +{ + encoding : null, + encoder : null, + data : null, + format : null, + filePath : null, + ext : null, + feature : null, + fileProvider : null, +} + +// -- +// declaration +// -- + +let gdfTypesForFiles = [ 'string', 'buffer.raw', 'buffer.bytes', 'buffer.node' ]; + +let Extension = +{ + + // encoder + + is, + finit, + _normalize, + _registerWithExt, + gdfRegister, + withGdf, + _fromGdf, + writerFromGdf, + readerFromGdf, + fromGdfs, + gdfsWatch, + deduce, + + for : _for, + + // fields + + gdfTypesForFiles, + +} + +_.props.supplement( _.files.encoder, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l2/Encoder.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l2' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Encoder_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Encoder_s */ })(); + +/* */ /* begin of file Encoders_s */ ( function Encoders_s() { function Encoders_s_naked() { (function _Encoders_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _global_.wTools; + +// -- +// encoders +// -- + +let readJsSmart = +{ + + name : 'js.smart', + exts : [ 'js', 's', 'ss', 'jstruct', 'jslike' ], + feature : { reader : true, config : true }, + // forConfig : 1, + + onBegin : function( e ) + { + e.operation.encoding = 'utf8'; + }, + + onEnd : function( e ) + { + _.sure( _.strIs( e.data ), 'Expects string' ); + + if( typeof process !== 'undefined' && typeof require !== 'undefined' ) + if( _.FileProvider.HardDrive && e.provider instanceof _.FileProvider.HardDrive ) + { + try + { + e.data = require( _.fileProvider.path.nativize( e.operation.filePath ) ); + return; + } + catch( err ) + { + } + } + + e.data = _.exec + ({ + code : e.data, + filePath : e.operation.filePath, + prependingReturn : 1, + }); + }, + +} + +// + +let readJsNode = +{ + + name : 'js.node', + exts : [ 'js', 's', 'ss', 'jstruct' ], + feature : { reader : true }, + // forConfig : 0, + + onBegin : function( e ) + { + e.operation.encoding = 'utf8'; + }, + + onEnd : function( e ) + { + if( !_.strIs( e.data ) ) + throw _.err( 'Expects string' ); + e.data = require( _.fileProvider.path.nativize( e.operation.filePath ) ); + }, + +} + +// + +let readBufferBytes = +{ + + name : 'buffer.bytes', + feature : { reader : true }, + + onBegin : function( e ) + { + _.assert( e.operation.encoding === 'buffer.bytes' ); + }, + + onEnd : function( e ) + { + if( e.stream ) /* xxx */ + debugger; + if( e.stream ) + return; + _.assert( _.bufferBytesIs( e.data ) ); + }, + +} + +// + +let readBufferRaw = +{ + + name : 'buffer.raw', + feature : { reader : true }, + + onBegin : function( e ) + { + _.assert( e.operation.encoding === 'buffer.raw' ); + }, + + onEnd : function( e ) + { + _.assert( _.bufferRawIs( e.data ) ); + }, + +} + +// + +// let readOriginalType = +// { +// +// name : 'meta.original', +// feature : { reader : true }, +// +// onBegin : function( e ) +// { +// }, +// +// onEnd : function( e ) +// { +// }, +// +// onSelect : function( e ) +// { +// let encoding = 'buffer.bytes'; +// if( e.fileProvider.encoding !== 'meta.original' ) +// encoding = e.encoding; +// let e2 = e; +// e2.encoding = e.fileProvider.encoding; +// return _.files.encoder.for( e2 ); +// }, +// +// } + +// -- +// declare +// -- + +_.files.ReadEncoders = _.files.ReadEncoders || Object.create( null ); +_.files.WriteEncoders = _.files.WriteEncoders || Object.create( null ); + +_.files.encoder._registerWithExt( readJsSmart ); +_.files.encoder._registerWithExt( readJsNode ); +_.files.encoder._registerWithExt( readBufferBytes ); +_.files.encoder._registerWithExt( readBufferRaw ); +// _.files.encoder._registerWithExt( readOriginalType ); +_.files.encoder.fromGdfs(); /* xxx : review and probably remove! */ +_.files.encoder.gdfsWatch(); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l2/Encoders.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l2' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Encoders_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Encoders_s */ })(); + +/* */ /* begin of file Linker_s */ ( function Linker_s() { function Linker_s_naked() { ( function _Linker_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( _.object.isBasic( _.files ) ); + +const Self = _.files.linker = _.files.linker || Object.create( null ); + +// -- +// linkingAction +// -- + +function multiple( o, link ) +{ + let self = this; + + if( o.dstPath.length < 2 ) + return o.sync ? 0 : new _.Consequence().take( 0 ); + + _.assert( !!o ); + _.assert( _.strIs( o.srcPath ) || o.srcPath === null ); + _.assert( _.strIs( o.sourceMode ) || _.longIs( o.sourceMode ) ); + _.assert( _.boolLike( o.allowingMissed ) ); + _.assert( _.boolLike( o.allowingCycled ) ); + + let needed = 0; + let factory = self.recordFactory({ allowingMissed : o.allowingMissed, allowingCycled : o.allowingCycled }); + let records = factory.records( o.dstPath ); + // Vova : should allow missing files? + // Kos : test routine? + let newestRecord, mostLinkedRecord; + + if( o.srcPath ) + { + if( !self.statResolvedRead( o.srcPath ) ) + return error( _.err( '{ o.srcPath } ', o.srcPath, ' doesn\'t exist.' ) ); + newestRecord = mostLinkedRecord = self.record( o.srcPath ); + } + else + { + let sorter = o.sourceMode; + _.assert( !!sorter, 'Expects { option.sourceMode }' ); + newestRecord = self._recordsSort( records, sorter ); + + if( !newestRecord ) + return error( _.err( 'Source file was not selected, probably provided paths { o.dstPath } do not exist.' ) ); + + let zero = self.UsingBigIntForStat ? BigInt( 0 ) : 0; + mostLinkedRecord = _.entityMax( records, ( record ) => record.stat ? record.stat.nlink : zero ).element; + } + + for( let p = 0 ; p < records.length ; p++ ) + { + let record = records[ p ]; + if( !record.stat || !_.files.stat.areHardLinked( newestRecord.stat, record.stat ) ) + { + needed = 1; + break; + } + } + + if( !needed ) + return o.sync ? 0 : new _.Consequence().take( 0 ); + + /* */ + + if( mostLinkedRecord.absolute !== newestRecord.absolute ) + { + let read = self.fileRead({ filePath : newestRecord.absolute, encoding : 'meta.original' }); + self.fileWrite( mostLinkedRecord.absolute, read ); + /* + fileCopy cant be used here + because hardlinks of most linked file with other files should be preserved + */ + } + + /* */ + + let result = { err : undefined, got : true }; + + if( o.sync ) + { + for( let p = 0 ; p < records.length ; p++ ) + { + if( !onRecord( records[ p ] ) ) + return false; + } + return true; + } + else + { + let cons = []; + // let result = { err : undefined, got : true }; + let throwing = o.throwing; + o.throwing = 1; + + for( let p = 0 ; p < records.length ; p++ ) + cons.push( onRecord( records[ p ] ).tap( handler ) ); + + let con = new _.Consequence().take( null ); + + con.andKeep( cons ) + .finally( () => + { + if( result.err ) + { + if( throwing ) + throw result.err; + else + return false; + } + return result.got; + }); + + return con; + } + + /* - */ + + function error( err ) + { + if( o.sync ) + throw err; + else + return new _.Consequence().error( err ); + } + + /* */ + + function handler( err, got ) + { + if( !err ) + { + result.got &= got; + } + else + { + _.errAttend( err ); + if( !_.definedIs( result.err ) ) + result.err = err; + } + } + + /* */ + + function onRecord( record ) + { + if( record === mostLinkedRecord ) + return o.sync ? true : new _.Consequence().take( true ); + + // if( !o.allowingDiscrepancy ) /* qqq : cover */ + // if( !self.filesCanBeSame( result.src, record.src, true ) ) + // if( result.src.stat.size !== 0 || record.src.stat.size !== 0 ) + // { + // throw _.err + // ( + // 'Cant\'t rewrite destination file by source file, because they have different content and option::allowingDiscrepancy is false\n' + // + `\ndst: ${result.dst.absolute}` + // + `\nsrc: ${result.src.absolute}` + // ); + // } + + // if( !o.allowingDiscrepancy ) + // // if( record.stat && newestRecord.stat.mtime.getTime() === record.stat.mtime.getTime() && newestRecord.stat.birthtime.getTime() === record.stat.birthtime.getTime() ) + // { + // if( _.files.stat.different( newestRecord.stat , record.stat ) ) + // { + // if( o.sync ) + // throw err; + // else + // return new _.Consequence().error( err ); + // } + // } + + if( !record.stat || !_.files.stat.areHardLinked( mostLinkedRecord.stat, record.stat ) ) + { + let linkOptions = _.props.extend( null, o ); + linkOptions.allowingMissed = 0; /* Vova : hardLink does not allow missing srcPath */ + linkOptions.dstPath = record.absolute; + linkOptions.srcPath = mostLinkedRecord.absolute; + return link.call( self, linkOptions ); + } + + return o.sync ? true : new _.Consequence().take( true ); + } + +} + +// + +function onIsLink( stat ) +{ + let self = this.provider; + + if( stat.isSoftLink() ) + return true; + + if( this.onIsLink2 ) + return this.onIsLink2.call( self, stat ); + + return false; +} + +// + +function onStat( filePath, resolving ) +{ + let c = this; + let self = c.provider; + + if( c.onStat2 ) + return c.onStat2.call( self, filePath, resolving ); + + return self.statRead + ({ + filePath, + throwing : 0, + resolvingSoftLink : resolving, + resolvingTextLink : 0, + sync : 1, + }); +} + +// + +function verify1( args ) +{ + let c = this; + let o = c.options; + + _.assert( args.length === 1, 'Expects single argument' ); + _.assert( _.routineIs( c.linkDo ), 'method', c.actMethodName, 'is not implemented' ); + _.assert( _.object.isBasic( c.linkDo.defaults ), 'method', c.actMethodName, 'does not have defaults, but should' ); + _.routine.assertOptions( c.linkBody, args ); + _.assert( _.boolLike( o.resolvingSrcSoftLink ) || _.numberIs( o.resolvingSrcSoftLink ) ); + _.assert( _.boolLike( o.resolvingSrcTextLink ) || _.numberIs( o.resolvingSrcTextLink ) ); + _.assert( _.boolLike( o.resolvingDstSoftLink ) || _.numberIs( o.resolvingDstSoftLink ) ); + _.assert( _.boolLike( o.resolvingDstTextLink ) || _.numberIs( o.resolvingDstTextLink ) ); + _.assert( _.boolLike( o.allowingMissed ) ); + _.assert( _.boolLike( o.allowingCycled ) ); + _.assert( o.originalSrcPath === undefined ); + _.assert( o.originalDstPath === undefined ); + _.assert( o.relativeSrcPath === undefined ); + _.assert( o.relativeDstPath === undefined ); + + if( c.onVerify1 ) + { + let r = c.onVerify1.call( c.provider, c ); + _.assert( r === undefined ); + } + +} + +// + +function verify1Async( args ) +{ + let c = this; + + c.con.then( () => + { + verify1.call( c, args ); + return true; + }) +} + +// + +function verify2() +{ + let c = this; + let self = this.provider; + let o = c.options; + + /* allowingMissed */ + + if( !o.allowingMissed || c.skippingMissed ) + { + if( !c.srcStat ) + { + if( !o.allowingMissed ) + { + let err = _.err( 'Source file', _.strQuote( o.srcPath ), 'does not exist' ); + c.error( err ); + return true; + } + if( c.skippingMissed ) + { + c.end( false ); + return true; + } + } + } + + /* equal paths */ + + if( c.verifyEqualPaths() ) + return true; + + /* */ + + /* xxx qqq : allowingDiscrepancy should be similar to !dstRewritingOnlyPreserving */ + if( _.boolLikeFalse( o.allowingDiscrepancy ) ) /* qqq : cover */ + if( c.srcResolvedStat ) + if( self.fileExists( c.options2.dstPath ) ) + if( !self.filesAreSameForSure( c.options2.srcPath, c.options2.dstPath, false ) ) /* qqq xxx : optimize */ + if( Number( c.srcResolvedStat.size ) !== 0 ) + { + throw _.err + ( + 'Cant\'t rewrite destination file by source file, because they have different content and option::allowingDiscrepancy is false\n' + + `\ndst: ${o.dstPath}` + + `\nsrc: ${o.srcPath}` + ); + } + + /* skipping */ + + if( c.onVerify2 ) + { + let r = c.onVerify2.call( self, c ); + _.assert( r === undefined ); + } + + return false; +} + +// + +function verifyEqualPaths() +{ + let c = this; + let self = c.provider; + let o = c.options; + + if( o.dstPath === o.srcPath ) + { + + if( c.skippingSamePath ) + { + c.end( true ); + return true; + } + + if( !o.allowingMissed ) + { + let err = _.err( 'Making link on itself is not allowed. Please enable options {-o.allowingMissed-} if that was your goal.' ); + c.error( err ); + return true; + } + } + + return false; +} + +// + +function verify2Async() +{ + let c = this; + + c.con.then( () => + { + if( c.ended ) + return c.end(); + return verify2.call( c ); + }); +} + +// + +function verifyDstSync() +{ + let c = this; + let self = this.provider; + let o = c.options; + let o2 = c.options2; + + if( !o.rewriting ) + throw _.err( 'Destination file ' + _.strQuote( o2.dstPath ) + ' exist and rewriting is off.' ); + + if( c.dstStat === undefined ) + c.dstStat = self.statRead + ({ + filePath : o2.dstPath, + sync : 1, + }); + + if( c.dstStat.isDirectory() && !o.rewritingDirs ) + throw _.err( 'Destination file ' + _.strQuote( o2.dstPath ) + ' is a directory and rewritingDirs is off.' ); + +} + +// + +function verifyDstAsync() +{ + let c = this; + let self = this.provider; + let o = c.options; + let o2 = c.options2; + + if( !o.rewriting ) + throw _.err( 'Destination file ' + _.strQuote( o2.dstPath ) + ' exist and rewriting is off.' ); + + return self.statRead + ({ + filePath : o2.dstPath, + sync : 0, + }) + .then( ( stat ) => + { + _.assert( c.dstStat === undefined ); + c.dstStat = stat; + if( c.dstStat.isDirectory() && !o.rewritingDirs ) + throw _.err( 'Destination file ' + _.strQuote( o2.dstPath ) + ' is a directory and rewritingDirs is off.' ); + return stat; + }) +} + +// + +/* qqq : implement test suite: + - system + - no default provider + - +*/ + +function pathsLocalizeSync() /* qqq : ignoring provider is temp workaround. please redo */ +{ + let c = this; + let self = c.provider; + let o = c.options; + + if( self instanceof _.FileProvider.System ) + { + return; + } + + if( self.path.isGlobal( o.dstPath ) ) + { + let dstParsed = _.uri.parse( o.dstPath ); + if( dstParsed.protocol && !_.longHas( self.protocols, dstParsed.protocol ) ) + c.error( _.err( 'File provider ' + self.qualifiedName + ' does not support protocol ' + _.strQuote( dstParsed.protocol ) ) ); + o.dstPath = dstParsed.longPath; + } + + if( self.path.isGlobal( o.srcPath ) ) + { + let srcParsed = _.uri.parse( o.srcPath ); + if( srcParsed.protocol && _.longHas( self.protocols, srcParsed.protocol ) ) + o.srcPath = srcParsed.longPath; + } + +} + +// + +function pathsLocalizeAsync() +{ + let c = this; + c.con.then( () => + { + if( c.ended ) + return c.end(); + pathsLocalizeSync.call( c ); + return null; + }); +} + +// + +function pathResolve() +{ + let c = this; + let self = c.provider; + let path = self.system ? self.system.path : self.path; + let o = c.options; + + o.relativeSrcPath = o.srcPath; + o.relativeDstPath = o.dstPath; + + if( !path.isAbsolute( o.dstPath ) ) + { + _.assert( path.isAbsolute( o.srcPath ), () => 'Expects absolute path {-o.srcPath-}, but got', _.strQuote( o.srcPath ) ); + o.dstPath = path.join( o.srcPath, o.dstPath ); + } + else if( !path.isAbsolute( o.srcPath ) ) + { + _.assert( path.isAbsolute( o.dstPath ), () => 'Expects absolute path {-o.dstPath-}, but got', _.strQuote( o.dstPath ) ); + o.srcPath = path.join( o.dstPath, o.srcPath ); + } + else + { + /* + add protocol if any + */ + if( path.isGlobal( o.srcPath ) ) + o.dstPath = path.join( o.srcPath, o.dstPath ); + else if( path.isGlobal( o.dstPath ) ) + o.srcPath = path.join( o.dstPath, o.srcPath ); + } + + _.assert( path.isAbsolute( o.srcPath ) ); + _.assert( path.isAbsolute( o.dstPath ) ); + + c.originalSrcResolvedPath = o.srcPath; + + /* check if equal early */ + + c.verifyEqualPaths(); +} + +// + +function pathResolveAsync() +{ + let c = this; + c.con.then( () => + { + if( c.ended ) + return c.end(); + pathResolve.call( c ); + return true; + }) +} + +// + +function linksResolve() +{ + let c = this; + let self = c.provider; + let path = self.system ? self.system.path : self.path; + let o = c.options; + + try + { + + _.assert( path.isAbsolute( o.srcPath ) ); + _.assert( path.isAbsolute( o.dstPath ) ); + + if( o.resolvingDstSoftLink || ( o.resolvingDstTextLink && self.usingTextLink ) ) + { + let o2 = + { + filePath : o.dstPath, + resolvingSoftLink : o.resolvingDstSoftLink, + resolvingTextLink : o.resolvingDstTextLink, + allowingCycled : 1, + allowingMissed : 1, + preservingRelative : 1, + } + let resolved = self.pathResolveLinkFull( o2 ); + o.dstPath = resolved.absolutePath; + o.relativeDstPath = resolved.relativePath; + c.dstStat = o2.stat; /* it's ok */ + } + else + { + } + + /* */ + + if( o.resolvingSrcSoftLink || ( o.resolvingSrcTextLink && self.usingTextLink ) ) + { + let o2 = + { + filePath : o.srcPath, + resolvingSoftLink : o.resolvingSrcSoftLink, + resolvingTextLink : o.resolvingSrcTextLink, + allowingCycled : o.allowingCycled, + allowingMissed : o.allowingMissed, + throwing : o.throwing, + preservingRelative : 1, + } + let resolved = self.pathResolveLinkFull( o2 ); + o.srcPath = resolved.absolutePath; + + if( ( resolved.filePath !== null && path.isRelative( resolved.filePath ) ) || path.isRelative( o.relativeSrcPath ) ) + { + o.relativeSrcPath = path.relative( o.dstPath, resolved.absolutePath ); + } + else /* xxx : qqq : ? */ + { + o.relativeSrcPath = resolved.filePath; + } + + // if( resolved.relativePath ) + // { + // if( path.isRelative( resolved.relativePath ) || path.isRelative( o.relativeSrcPath ) ) + // o.relativeSrcPath = path.relative( o.dstPath, resolved.absolutePath ); + // else + // o.relativeSrcPath = resolved.relativePath; + // } + + c.srcStat = o2.stat; + + c.srcResolvedStat = c.srcStat; + if( Config.debug ) + if( c.srcResolvedStat ) + if( c.onIsLink( c.srcResolvedStat ) ) + c.srcResolvedStat = c.onStat( o.srcPath, 1 ); + + } + else + { + /* do not read stat if possible */ + c.srcStat = c.onStat( o.srcPath, 0 ); + + c.srcResolvedStat = c.srcStat; + if( Config.debug ) + if( c.srcResolvedStat ) + if( c.onIsLink( c.srcResolvedStat ) ) + c.srcResolvedStat = c.onStat( o.srcPath, 1 ); + + } + + _.assert( _.strIs( o.relativeSrcPath ) ); + _.assert( _.strIs( o.relativeDstPath ) ); + + } + catch( err ) + { + c.error( err ); + } + +} + +// + +function linksResolveAsync() +{ + let c = this; + let self = this.provider; + let path = self.system ? self.system.path : self.path; + let o = c.options; + + c.con.then( () => + { + if( c.ended ) + return c.end(); + + _.assert( path.isAbsolute( o.srcPath ) ); + _.assert( path.isAbsolute( o.dstPath ) ); + + if( o.resolvingDstSoftLink || ( o.resolvingDstTextLink && self.usingTextLink ) ) + { + let o2 = + { + filePath : o.dstPath, + resolvingSoftLink : o.resolvingDstSoftLink, + resolvingTextLink : o.resolvingDstTextLink, + sync : 0, + allowingCycled : 1, + allowingMissed : 1, + preservingRelative : 1, + } + return self.pathResolveLinkFull( o2 ).then( ( resolved ) => + { + o.dstPath = resolved.absolutePath; + o.relativeDstPath = resolved.relativePath; + c.dstStat = o2.stat; + return true; + }) + } + + return true; + }) + + /* */ + + c.con.then( () => + { + if( c.ended ) + return c.end(); + + if( o.resolvingSrcSoftLink || ( o.resolvingSrcTextLink && self.usingTextLink ) ) + { + let o2 = + { + filePath : o.srcPath, + resolvingSoftLink : o.resolvingSrcSoftLink, + resolvingTextLink : o.resolvingSrcTextLink, + allowingCycled : o.allowingCycled, + allowingMissed : o.allowingMissed, + sync : 0, + preservingRelative : 1, + throwing : o.throwing + } + + return self.pathResolveLinkFull( o2 ) + .then( ( resolved ) => + { + o.srcPath = resolved.absolutePath; + + if( ( resolved.filePath !== null && path.isRelative( resolved.filePath ) ) || path.isRelative( o.relativeSrcPath ) ) + { + o.relativeSrcPath = path.relative( o.dstPath, resolved.absolutePath ); + } + else /* xxx : qqq : ? */ + { + o.relativeSrcPath = resolved.filePath; + } + + // if( resolved.filePath !== null && path.isRelative( resolved.filePath ) ) + // { + // o.relativeSrcPath = path.relative( o.dstPath, resolved.absolutePath ); + // } + // else /* xxx : qqq : bad */ + // { + // o.relativeSrcPath = resolved.filePath; + // } + + // if( resolved.relativePath ) + // { + // if( path.isRelative( resolved.relativePath ) || path.isRelative( o.relativeSrcPath ) ) + // o.relativeSrcPath = path.relative( o.dstPath, resolved.absolutePath ); + // else + // o.relativeSrcPath = resolved.relativePath; + // } + + c.srcStat = o2.stat; + return true; + }) + } + else + { + /* do not read stat if possible */ + return self.statRead({ filePath : o.srcPath, sync : 0 }) + .then( ( srcStat ) => + { + c.srcStat = srcStat; + return true; + }); + } + }) +} + +// + +function log() +{ + let c = this; + let self = this.provider; + let path = self.system ? self.system.path : self.path; + let o = c.options; + + if( !o.verbosity || o.verbosity < 2 ) + return; + self.logger.log( ' +', c.entryMethodName, ':', path.moveTextualReport( o.dstPath, o.srcPath ) ); +} + +// + +function tempRenameCan() +{ + let c = this; + let o = c.options; + + _.assert( _.fileStatIs( c.dstStat ) ); + + if( !c.renaming ) + return false; + + if( _.boolLike( o.breakingDstHardLink ) ) + if( !o.breakingDstHardLink && c.dstStat.isHardLink() ) + return false; + + return true; +} + +// + +function tempRenameSync() +{ + let c = this; + let self = this.provider; + let o = c.options; + let o2 = c.options2; + + c.tempPath = c.tempNameMake( o2.dstPath ); + if( self.statRead({ filePath : c.tempPath }) ) + self.filesDelete( c.tempPath ); + self.fileRenameAct + ({ + dstPath : c.tempPath, + srcPath : o.dstPath, + relativeDstPath : c.tempPath, + relativeSrcPath : o.dstPath, + sync : 1, + context : c, + }); + return true; +} + +function tempRenameAsync() +{ + let c = this; + let self = this.provider; + let o = c.options; + let o2 = c.options2; + + if( !c.tempRenameCan() ) + return false; + + c.tempPath = c.tempNameMake( o2.dstPath ); + return self.statRead + ({ + filePath : c.tempPath, + sync : 0 + }) + .then( ( tempStat ) => + { + if( tempStat ) + return self.filesDelete( c.tempPath ); + return tempStat; + }) + .then( () => + { + return self.fileRenameAct + ({ + dstPath : c.tempPath, + srcPath : o.dstPath, + relativeDstPath : c.tempPath, + relativeSrcPath : o.dstPath, + sync : 0, + context : c, + }); + }) +} + +// + +function tempRenameMaybe() +{ + let c = this; + let self = this.provider; + let o = c.options; + + if( !self.fileExists( c.options2.dstPath ) ) + return false; + if( !o.breakingDstHardLink && c.dstStat.isHardLink() ) + return false; + c.renaming = true; + return c.tempRename(); +} + +// + +function tempRenameRevertSync() +{ + let c = this; + let self = this.provider; + let o = c.options; + + if( c.tempPath ) + { + try + { + self.fileRenameAct + ({ + dstPath : o.dstPath, + srcPath : c.tempPath, + relativeDstPath : o.dstPath, + relativeSrcPath : c.tempPath, + sync : 1, + context : c, + }); + } + catch( err2 ) + { + console.error( err2 ); + } + } + +} + +// + +function tempRenameRevertAsync() +{ + let c = this; + let self = this.provider; + let o = c.options; + + if( !c.tempPath ) + return new _.Consequence().take( null ); + + return self.fileRenameAct + ({ + dstPath : o.dstPath, + srcPath : c.tempPath, + relativeDstPath : o.dstPath, + relativeSrcPath : c.tempPath, + sync : 0, + context : c, + }) + .finally( ( err2, got ) => + { + if( err2 ) + console.error( err2 ); + return got; + }) +} + +// + +function tempDelete() +{ + let c = this; + let self = this.provider; + let o = c.options; + + if( c.tempPath ) + { + let tempPath = c.tempPath; + c.tempPath = null; + return self.filesDelete + ({ + filePath : tempPath, + verbosity : 0, + sync : o.sync, + }); + } + + return null; +} + +// + +function tempNameMake( filePath ) +{ + let postfix = '-' + _.idWithGuid() + '.tmp'; + + if( _.strEnds( filePath, '/' ) ) + return _.strReplaceEnd( filePath, '/', postfix ) + + return filePath + postfix; +} + +// + +function validateSize() +{ + let c = this; + let self = this.provider; + let o = c.options; + + if( !Config.debug ) + return; + + if( o.srcPath === o.dstPath ) + return; + + let srcPath = o.srcPath; + let dstPath = o.dstPath; + + let srcStat = c.srcResolvedStat; + + if( !srcStat && o.allowingMissed ) + return; + + if( !srcStat ) + { + srcStat = c.srcStat; + if( srcStat ) + { + if( c.onSizeCheck ) + c.onSizeCheck.call( self, c ); + return; + } + } + + if( !srcStat ) + { + let err = `Failed to ${c.entryMethodName} ${o.dstPath} from ${o.srcPath}. Source file does not exist.`; + throw _.err( err ); + } + + c.dstStat = c.onStat( dstPath, 1 ); + + if( !c.dstStat ) + { + c.dstStat = c.onStat( dstPath, 0 ); + if( c.dstStat ) + return; + } + + + if( !c.dstStat ) + { + let err = `Failed to ${c.entryMethodName} ${o.dstPath} from ${o.srcPath}. Destination file does not exist.`; + throw _.err( err ); + } + + if( c.linkMaybe ) + { + let updateStat = _.strBegins( dstPath, srcPath ); + let filePath = srcStat.filePath; + + if( self instanceof _.FileProvider.System ) + { + filePath = self.providerForPath( srcPath ).path.globalFromPreferred( filePath ); + dstPath = self.providerForPath( dstPath ).path.globalFromPreferred( dstPath ) + } + + if( updateStat || _.strBegins( dstPath, filePath ) ) + srcStat = c.onStat( filePath, 0 ); + + // let updateStat = _.strBegins( dstPath, srcPath ); + // let filePath = srcStat.filePath; + // + // if( self instanceof _.FileProvider.System ) + // filePath = self.providerForPath( srcPath ).path.globalFromPreferred( filePath ); + // + // if( !updateStat ) + // updateStat = _.strBegins( dstPath, filePath ) + // + // if( _.strHas( srcPath, 'src/proto/dirLink1' ) ) + // if( updateStat ) + // srcStat = c.onStat( filePath, 0 ); + } + + /* qqq: find better solution to check text links */ + if( /* srcStat.isTextLink() && */ c.dstStat.isTextLink() ) + if( self.areTextLinked([ c.dstStat.filePath, srcStat.filePath ]) ) + return; + + let srcSize = srcStat ? srcStat.size : NaN; + let dstSize = c.dstStat ? c.dstStat.size : NaN; + + if( !( srcSize == dstSize ) ) + { + let err = + `Failed to ${c.entryMethodName} ${o.dstPath} (${dstSize}) from ${o.srcPath} (${srcSize}). ` + + `Have different size after ${c.entryMethodName} operation.`; + err = _.err( err ); + debugger; + throw err; + } + +} + +// + +function error( err ) +{ + let c = this; + let o = c.options; + + _.assert( arguments.length === 1 ); + + if( o.throwing ) + { + if( o.sync ) + throw err; + c.result = new _.Consequence().error( err ); + return c.end( c.result ); + } + else + { + _.errAttend( err ); + return c.end( null ); + } + +} + +// + +function end( r ) +{ + let c = this; + let o = c.options; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( arguments.length === 0 || r !== undefined ); + c.ended = true; + if( r !== undefined ) + if( o.sync ) + c.result = r; + else if( _.consequenceIs( r ) ) + c.result = r; + else + c.result = _.Consequence().take( r ); + _.assert( !!o.sync || _.consequenceIs( c.result ) ); + _.assert( c.result !== undefined ); + return c.result; +} + +// + +/* xxx : qqq : not optimal. optimize */ +function contextMake( o ) +{ + _.assert( arguments.length === 1 ); + _.routine.options_( contextMake, o ); + + let fop = o.fop; + let options = o.options; + let provider = o.provider; + + let c = Object.create( null ); + + c.provider = provider; + c.linkBody = undefined; + + _.assert( !!fop ); + + if( fop ) + { + c.actMethodName = fop.actMethodName; + c.onVerify1 = fop.onVerify1; + c.onVerify2 = fop.onVerify2; + c.onIsLink2 = fop.onIsLink; + c.onStat2 = fop.onStat; + c.onSizeCheck = fop.onSizeCheck; + c.renaming = fop.renaming; + c.skippingSamePath = fop.skippingSamePath; + c.skippingMissed = fop.skippingMissed; + c.linkDo = fop.onDo; + c.options2 = _.mapOnly_( null, options, c.linkDo.defaults ); + } + + c.entryMethodName = undefined; + c.onIsLink = onIsLink; + c.onStat = onStat; + c.ended = false; + c.result = undefined; + c.tempPath = undefined; + c.tempPathSrc = undefined; + c.dstStat = undefined; + c.srcStat = undefined; + c.originalSrcResolvedPath = undefined; + c.srcResolvedStat = undefined; + c.options = options; + + c.verify1 = options.sync ? verify1 : verify1Async; + c.verify2 = options.sync ? verify2 : verify2Async; + c.verifyDst = options.sync ? verifyDstSync : verifyDstAsync; + c.verifyEqualPaths = verifyEqualPaths; + c.pathsLocalize = options.sync ? pathsLocalizeSync : pathsLocalizeAsync; + c.pathResolve = options.sync ? pathResolve : pathResolveAsync; + c.linksResolve = options.sync ? linksResolve : linksResolveAsync; + c.log = log; + c.tempRenameCan = tempRenameCan; + c.tempRename = options.sync ? tempRenameSync : tempRenameAsync; + c.tempRenameMaybe = tempRenameMaybe; + c.tempRenameRevert = options.sync ? tempRenameRevertSync : tempRenameRevertAsync; + c.tempDelete = tempDelete; + c.tempNameMake = tempNameMake + c.validateSize = validateSize; + c.error = error; + c.end = end; + c.linkMaybe = fop.linkMaybe; + + if( !options.sync ) + { + c.con = new _.Consequence().take( null ); + } + + Object.preventExtensions( c ); + return c; +} + +contextMake.defaults = +{ + provider : null, + options : null, + fop : null +} + +// + +function functor_head( routine, args ) +{ + let self = this; + + let o = self._preSrcDstPathWithoutProviderDefaults.apply( self, arguments ); + self._providerDefaultsApply( o ); + + _.mapSupplementNulls( o, routine.defaults ); + return o; +} + +// + +function functor( fop ) +{ + + /* + qqq : optimize, fix consequences problem + */ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options_( functor, fop ); + + let onDo = fop.onDo; + let actMethodName = fop.actMethodName; + let entryMethodName = _.strRemoveEnd( fop.actMethodName, 'Act' ); + let onVerify1 = fop.onVerify1; + let onVerify2 = fop.onVerify2; + let onIsLink2 = fop.onIsLink; + let onStat2 = fop.onStat; + let onSizeCheck = fop.onSizeCheck; + let renaming = fop.renaming; + let skippingSamePath = fop.skippingSamePath; + let skippingMissed = fop.skippingMissed; + let hardLinking = fop.hardLinking; + + _.assert( _.routineIs( onDo ) ); + _.assert( _.object.isBasic( onDo.defaults ) ); + _.assert( onVerify1 === null || _.routineIs( onVerify1 ) ); + _.assert( onVerify2 === null || _.routineIs( onVerify2 ) ); + _.assert( onIsLink2 === null || _.routineIs( onIsLink2 ) ); + _.assert( onStat2 === null || _.routineIs( onStat2 ) ); + _.assert( onSizeCheck === null || _.routineIs( onSizeCheck ) ); + + _.routineExtend( link_body, onDo ); + link_body.defaults = _.props.extend( null, link_body.defaults ); /* xxx qqq : redundant? */ + delete link_body.defaults.originalSrcPath; + delete link_body.defaults.originalDstPath; + delete link_body.defaults.relativeSrcPath; + delete link_body.defaults.relativeDstPath; + + var having = link_body.having; + + having.driving = 0; + having.aspect = 'body'; + + let linkEntry = _.routine.uniteReplacing({ head : functor_head, body : link_body, name : entryMethodName }); + + var having = linkEntry.having = _.props.extend( null, linkEntry.having ); + having.aspect = 'entry'; + + return linkEntry; + + /* */ + + function link_body( o ) + { + let self = this; + let path = self.system ? self.system.path : self.path; + let o2; + let c = Self.contextMake({ provider : self, options : o, fop }); + + c.entryMethodName = entryMethodName; + c.linkBody = link_body; + + /* */ + + if( o.sync ) + { + + c.verify1( arguments ); + if( c.ended ) + return c.end(); + + /* + zzz : multiple should work not only for hardlinks + */ + + if( _.longIs( o.dstPath ) && hardLinking ) + return multiple.call( self, o, link_body ); + _.assert( _.strIs( o.srcPath ) && _.strIs( o.dstPath ) ); + + c.pathsLocalize(); + if( c.ended ) + return c.end(); + + c.pathResolve(); + if( c.ended ) + return c.end(); + + c.linksResolve(); + if( c.ended ) + return c.end(); + + c.verify2(); + if( c.ended ) + return c.end(); + + o2 = c.options2 = _.props.extend( c.options2, _.mapOnly_( null, o, c.linkDo.defaults ) ); + o2.context = c.options2.context = c; + + try + { + + if( self.fileExists( o2.dstPath ) ) + { + c.verifyDst() + if( c.tempRenameCan() ) + tempRenameSync.call( c ); + } + else if( o.makingDirectory ) + { + self.dirMakeForFile( o2.dstPath ); + } + + c.linkDo.call( self, c ); + c.log(); + + c.validateSize(); + c.tempDelete(); + + } + catch( err ) + { + + c.tempRenameRevert(); + return c.error( _.err( err, '\nCant', c.entryMethodName, o.dstPath, '<-', o.srcPath ) ); + + } + + return true; + } + else /* async */ + { + + /* launcher */ + + c.verify1( arguments ); + + c.con.then( () => + { + if( _.longIs( o.dstPath ) && hardLinking ) + { + c.result = multiple.call( self, o, link_body ); + return true; + } + _.assert( _.strIs( o.srcPath ) && _.strIs( o.dstPath ) ); + + c.pathsLocalize(); + c.pathResolve(); + c.linksResolve(); + c.verify2(); + + return true; + }) + + c.con.then( () => + { + /* return result if ended earlier */ + if( c.result !== undefined ) + return c.result; + /* prepare options map and launch main part */ + o2 = c.options2 = _.props.extend( c.options2, _.mapOnly_( null, o, c.linkDo.defaults ) ); + o2.context = c.options2.context = c; + /* main part */ + return mainPartAsync(); + }) + + return c.con; + } + + /* */ + + function mainPartAsync() + { + let con = new _.Consequence().take( null ); + + con.then( () => self.fileExists( o2.dstPath ) ); + con.then( ( dstExists ) => + { + if( dstExists ) + { + return c.verifyDst().then( () => tempRenameAsync.call( c ) ); + } + else if( o.makingDirectory ) + { + return self.dirMakeForFile({ filePath : o2.dstPath, sync : 0 }); + } + return dstExists; + }); + + con.then( _.routineSeal( self, c.linkDo, [ c ] ) ); + + con.then( ( got ) => + { + c.log(); + return c.tempDelete(); + }); + con.then( () => + { + c.tempPath = null; + c.validateSize(); + return true; + }); + + con.catch( ( err ) => + { + return c.tempRenameRevert() + .finally( () => + { + return c.error( _.err( err, '\nCant', c.entryMethodName, o.dstPath, '<-', o.srcPath ) ); + }) + }) + + return con; + } + + } + +} + +functor.defaults = +{ + + actMethodName : null, + onDo : null, + onVerify1 : null, + onVerify2 : null, + onIsLink : null, + onStat : null, + onSizeCheck : null, + + linkMaybe : false, + hardLinking : false, + renaming : true, + skippingSamePath : true, + skippingMissed : false, + +} + +/* + +fileCopy +fileRename +softLink +hardLink +textLink + +*/ + +// -- +// +// -- + +let LinkerExtension = +{ + + multiple, + + onIsLink, + onStat, + + verify1, + verify1Async, + verify2, + verifyEqualPaths, + verify2Async, + verifyDstSync, + verifyDstAsync, + + pathsLocalizeSync, + pathsLocalizeAsync, + + pathResolve, + pathResolveAsync, + + linksResolve, + linksResolveAsync, + + log, + + tempRenameCan, + tempRenameSync, + tempRenameAsync, + tempRenameMaybe, + tempRenameRevertSync, + tempRenameRevertAsync, + + tempDelete, + tempNameMake, + + validateSize, + + error, + end, + + contextMake, + functor, + +} + +/* _.props.extend */Object.assign( _.files.linker, LinkerExtension ) + +// + +})() + + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l2/Linker.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l2' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Linker_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Linker_s */ })(); + +/* */ /* begin of file RecordContext_s */ ( function RecordContext_s() { function RecordContext_s_naked() { ( function _RecordFactoryAbstract_s_() +{ + +'use strict'; + +/** + * @class wFileRecordContext + * @namespace wTools + * @module Tools/mid/Files +*/ + +const _global = _global_; +const _ = _global_.wTools; +const Parent = null; +const Self = wFileRecordContext; +function wFileRecordContext( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'FileRecordContext'; + +_.assert( !_.files.FileRecordContext ); + +// -- +// routine +// -- + +/** + * @summary Creates factory instance ignoring unknown options. + * @param {Object} o Options map. + * @function TolerantFrom + * @class wFileRecordContext + * @namespace wTools + * @module Tools/mid/Files +*/ + +function TolerantFrom( o ) +{ + let Cls = _.workpiece.constructorOf( this ); + _.assert( arguments.length >= 1, 'Expects at least one argument' ); + _.assert( _.object.isBasic( Cls.prototype.Composes ) ); + o = _.mapsExtend( null, arguments ); + return new Cls( _.mapOnly_( null, o, Cls.prototype.fieldsOfCopyableGroups ) ); +} + +// + +function init( o ) +{ + let factory = this; + + _.workpiece.initFields( factory ); + Object.preventExtensions( factory ); + + return factory; +} + +// + +function _formAssociations() +{ + let factory = this; + + /* find file system */ + + if( !factory.system ) + if( factory.effectiveProvider && factory.effectiveProvider instanceof _.FileProvider.System ) + { + factory.system = factory.effectiveProvider; + factory.effectiveProvider = null; + } + + if( !factory.system ) + if + ( + factory.effectiveProvider + && factory.effectiveProvider.system + && factory.effectiveProvider.system instanceof _.FileProvider.System + ) + { + factory.system = factory.effectiveProvider.system; + } + + if( !factory.system ) + if( factory.defaultProvider && factory.defaultProvider instanceof _.FileProvider.System ) + { + factory.system = factory.defaultProvider; + } + + if( !factory.system ) + if + ( + factory.defaultProvider + && factory.defaultProvider.system + && factory.defaultProvider.system instanceof _.FileProvider.System + ) + { + factory.system = factory.defaultProvider.system; + } + + if( factory.system ) + if( factory.system.system && factory.system.system !== factory.system ) + { + _.assert( !( factory.system instanceof _.FileProvider.System ) ); + if( !factory.effectiveProvider ) + factory.effectiveProvider = factory.system; + factory.system = factory.system.system; + } + + /* find effective provider */ + + if( factory.effectiveProvider && factory.effectiveProvider instanceof _.FileProvider.System ) + { + _.assert( factory.system === null || factory.system === factory.effectiveProvider ); + factory.system = factory.effectiveProvider; + factory.effectiveProvider = null; + } + + /* reset system */ + + if( factory.effectiveProvider && factory.effectiveProvider.system ) + { + _.assert( factory.system === null || factory.system === factory.effectiveProvider.system ); + factory.system = factory.effectiveProvider.system; + } + + /* find default provider */ + + if( !factory.defaultProvider ) + { + factory.defaultProvider = factory.defaultProvider || factory.effectiveProvider || factory.system; + } + + /* reset system */ + + if( factory.system && !( factory.system instanceof _.FileProvider.System ) ) + { + _.assert( factory.system === factory.defaultProvider || factory.system === factory.effectiveProvider ) + factory.system = null; + } + + // if( factory.system ) + // { + // if( factory.system.system && factory.system.system !== factory.system ) + // { + // _.assert( factory.effectiveProvider === null || factory.effectiveProvider === factory.system ); + // factory.effectiveProvider = factory.system; + // factory.system = factory.system.system; + // } + // } + // + // if( factory.effectiveProvider ) + // { + // if( factory.effectiveProvider instanceof _.FileProvider.System ) + // { + // _.assert( factory.system === null || factory.system === factory.effectiveProvider ); + // factory.system = factory.effectiveProvider; + // factory.effectiveProvider = null; + // } + // } + // + // if( factory.effectiveProvider && factory.effectiveProvider.system ) + // { + // _.assert( factory.system === null || factory.system === factory.effectiveProvider.system ); + // factory.system = factory.effectiveProvider.system; + // } + // + // if( !factory.defaultProvider ) + // { + // factory.defaultProvider = factory.defaultProvider || factory.effectiveProvider || factory.system; + // } + + /* */ + + _.assert( !factory.system || factory.system instanceof _.FileProvider.Abstract, 'Expects {- factory.system -}' ); + _.assert( factory.defaultProvider instanceof _.FileProvider.Abstract ); + _.assert( !factory.effectiveProvider || !( factory.effectiveProvider instanceof _.FileProvider.System ) ); + + /* */ + + _.assert + ( + !factory.system || factory.system instanceof _.FileProvider.System, + () => '{- factory.system -} should be instance of {- _.FileProvider.System -}, but it is ' + _.entity.exportStringDiagnosticShallow( factory.system ) + ); + _.assert + ( + !factory.effectiveProvider || !( factory.effectiveProvider instanceof _.FileProvider.System ), + () => '{- factory.effectiveProvider -} cant be instance of {- _.FileProvider.System -}, but it is' + ); + _.assert + ( + factory.defaultProvider instanceof _.FileProvider.Abstract, + () => '{- factory.system -} should be instance of {- _.FileProvider.Abstract -}, but it is ' + _.entity.exportStringDiagnosticShallow( factory.defaultProvider ) + ); + +} + +// -- +// relation +// -- + +/** + * @typedef {Object} Fields + * @class wFileRecordContext + * @namespace wTools + * @module Tools/mid/Files +*/ + +let Composes = +{ +} + +let Aggregates = +{ +} + +let Associates = +{ + system : null, + effectiveProvider : null, + defaultProvider : null, +} + +let Medials = +{ +} + +let Restricts = +{ +} + +let Statics = +{ + TolerantFrom, +} + +let Forbids = +{ +} + +let Accessors = +{ +} + +// -- +// declare +// -- + +let Extension = +{ + + TolerantFrom, + init, + _formAssociations, + + /* */ + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + Forbids, + Accessors, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Extension, +}); + +_.Copyable.mixin( Self ); +_.files[ Self.shortName ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l2/RecordContext.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l2' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, RecordContext_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file RecordContext_s */ })(); + +/* */ /* begin of file Path_s */ ( function Path_s() { function Path_s_naked() { ( function _Path_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( _.object.isBasic( _.path ) ); + +let vectorizeKeysAndVals = _.files._.vectorizeKeysAndVals; +let vectorize = _.files._.vectorize; +let vectorizeAll = _.files._.vectorizeAll; +let vectorizeAny = _.files._.vectorizeAny; +let vectorizeNone = _.files._.vectorizeNone; + +// // -- +// // functor +// // -- +// +// function _vectorizeKeysAndVals( routine, select ) +// { +// select = select || 1; +// +// let routineName = routine.name; +// +// _.assert( _.routineIs( routine ) ); +// _.assert( _.strDefined( routineName ) ); +// _.assert( arguments.length === 1 || arguments.length === 2 ); +// +// let routine2 = _.routineVectorize_functor +// ({ +// routine : [ routineName ], +// vectorizingArray : 1, +// vectorizingMapVals : 1, +// vectorizingMapKeys : 1, +// select : select, +// }); +// +// _.routineExtend( routine2, routine ); +// +// return routine2; +// } +// zzz : clean + +// -- +// implementation +// -- + +function like( path ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + if( this.is( path ) ) + return true; + if( _.files.FileRecord ) + if( path instanceof _.files.FileRecord ) + return true; + return false; +} + +// + +/** + * Returns absolute path to file. Accepts file record object. If as argument passed string, method returns it. + * @example + * let str = 'foo/bar/baz', + fileRecord = FileRecord( str ); + let path = wTools.path.from( fileRecord ); // '/home/user/foo/bar/baz'; + * @param {string|wFileRecord} src file record or path string + * @returns {string} + * @throws {Error} If missed argument, or passed more then one. + * @throws {Error} If type of argument is not string or wFileRecord. + * @function from + * @namespace wTools.path + * @module Tools/mid/Files + */ + +function from( src ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.strIs( src ) ) + return src; + else if( src instanceof _.files.FileRecord ) + return src.absolute; + else _.assert( 0, 'Expects string, but got', _.entity.strType( src ) ); + +} + +// + +/** + * @summary Converts source path `src` to platform-specific path. + * @param {String} src Source path. + * @function nativize + * @namespace wTools.path + * @module Tools/mid/Files +*/ + +function nativize( src ) +{ + _.assert( arguments.length === 1 ); + + if( this.fileProvider ) + { + _.assert( !!this.fileProvider ); + _.assert( _.routineIs( this.fileProvider.pathNativizeAct ) ); + return this.fileProvider.pathNativizeAct( src ); + } + else + { + let nativize; + if( _global.process && _global.process.platform === 'win32' ) + nativize = this._nativizeWindows; + else + nativize = this._nativizePosix; + return nativize.apply( this, arguments ); + } + +} + +// + +/** + * Returns the current working directory of the Node.js process. If as argument passed path to existing directory, + method sets current working directory to it. If passed path is an existing file, method set its parent directory + as current working directory. + * @param {string} [path] path to set current working directory. + * @returns {string} + * @throws {Error} If passed more than one argument. + * @throws {Error} If passed path to not exist directory. + * @function current + * @namespace wTools.path + * @module Tools/mid/Files + */ + +function current() +{ + let path = this; + let provider = this.fileProvider; + + _.assert( _.object.isBasic( provider ) ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.routineIs( provider.pathCurrentAct ) ); + _.assert( _.routineIs( path.isAbsolute ) ); + + if( arguments[ 0 ] ) + try + { + + let filePath = arguments[ 0 ]; + _.assert( _.strIs( filePath ), 'Expects string' ); + + if( !path.isAbsolute( filePath ) ) + filePath = path.join( provider.pathCurrentAct(), filePath ); + + if( provider.fileExists( filePath ) && provider.isTerminal( filePath ) ) + filePath = path.resolve( filePath, '..' ); + + provider.pathCurrentAct( filePath ); + + } + catch( err ) + { + throw _.err( 'File was not found : ' + arguments[ 0 ] + '\n', err ); + } + + let result = provider.pathCurrentAct(); + + _.assert( _.strIs( result ) ); + + result = path.normalize( result ); + + return result; +} + +// + +/** + * @summary Converts global path `globalPath` to local. + * @param {String} globalPath Source path. + * @function preferredFromGlobal + * @namespace wTools.path + * @module Tools/mid/Files +*/ + +function preferredFromGlobal( globalPath ) +{ + let path = this; + let provider = this.fileProvider; + return provider.preferredFromGlobalAct( globalPath ); +} + +// + +/** + * @summary Converts local path `localPath` to global. + * @param {String} localPath Source path. + * @function globalFromPreferred + * @namespace wTools.path + * @module Tools/mid/Files +*/ + +function globalFromPreferred( localPath ) +{ + let path = this; + let provider = this.fileProvider; + return provider.globalFromPreferredAct( localPath ); +} + +// + +function hasLocally( filePath ) +{ + let path = this; + let provider = this.fileProvider; + + if( !path.isGlobal( filePath ) ) + return true; + + let parsed = _.uri.parse( filePath ); + + if( !parsed.protocol ) + return true; + + if( _.longHas( provider.protocols, parsed.protocol ) ) + return true; + + return false; +} + +// -- +// declare +// -- + +let Extension = +{ + + like, + + from, + + preferredFromGlobal, + localsFromGlobals : vectorizeKeysAndVals( preferredFromGlobal ), + globalFromPreferred, + globalsFromLocals : vectorizeKeysAndVals( globalFromPreferred ), + + nativize, + current, + hasLocally, + +} + +/* _.props.extend */Object.assign( _.path, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _.path; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l3/Path.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Path_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Path_s */ })(); + +/* */ /* begin of file Path_ss */ ( function Path_ss() { function Path_ss_naked() { (function _Path_ss_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( _.object.isBasic( _.path ) ); + +// -- +// path +// -- +// +/** + * Returns path for main module (module that running directly by node). + * @returns {String} + * @function realMainFile + * @namespace wTools.path + * @module Tools/mid/Files + */ +// +// function realMainFile() +// { +// return _.process.realMainFile(); +// } +// +// // +// +/** + * Returns path dir name for main module (module that running directly by node). + * @returns {String} + * @function realMainDir + * @namespace wTools.path + * @module Tools/mid/Files + */ +// +// function realMainDir() +// { +// return _.process.realMainDir(); +// } +// +// // +// +/** + * Returns absolute path for file running directly by node + * @returns {String} + * @throws {Error} If passed any argument. + * @function effectiveMainFile + * @namespace wTools.path + * @module Tools/mid/Files + */ +// +// function effectiveMainFile() +// { +// return _.process.effectiveMainFile(); +// } +// +// // +// +/** + * Returns path dirname for file running directly by node + * @returns {String} + * @throws {Error} If passed any argument. + * @function effectiveMainDir + * @namespace wTools.path + * @module Tools/mid/Files + */ +// +// function effectiveMainDir() +// { +// _.assert( arguments.length === 0, 'Expects no arguments' ); +// +// let result = this.dir( this.effectiveMainFile() ); +// +// return result; +// } + +// + +function resolveTextLink( path ) +{ + _.assert( !!this.fileProvider ); + return this.fileProvider.pathResolveTextLink.apply( this.fileProvider, arguments ); +} + +// // +// +// function _resolveTextLink( path ) +// { +// _.assert( !!this.fileProvider ); +// return this.fileProvider._pathResolveTextLink.apply( this.fileProvider, arguments ); +// } + +// + +/** + * Returns `home` directory. On depend from OS it's will be value of 'HOME' for posix systems or 'USERPROFILE' + * for windows environment variables. + * @returns {String} + * @function userHome + * @namespace wTools.path + * @module Tools/mid/Files + */ + +function dirUserHome() +{ + const fileProvider = this.fileProvider.preferredProvider; + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( _.routineIs( fileProvider.pathDirUserHomeAct ) ); + // if( this.userHomePath ) + // return this.userHomePath; + return fileProvider.pathDirUserHomeAct(); +} + +// + +function dirTemp() +{ + const fileProvider = this.fileProvider.preferredProvider; + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( _.routineIs( fileProvider.pathDirTempAct ), () => 'Provider ' + fileProvider.qualifiedName + ' does not support temp files' ); + // if( this.tempPath ) + // return this.tempPath; + return fileProvider.pathDirTempAct(); +} + +// + +function dirTempAt( o ) +{ + + _.assert( arguments.length <= 2 ); + + if( _.mapIs( o ) ) + { + o = arguments[ 0 ]; + } + else + { + if( arguments[ 1 ] !== undefined ) + o = + { + packagePath : arguments[ 0 ], + packageName : arguments[ 1 ], + } + else + o = + { + packageName : arguments[ 0 ], + } + } + + o = _.routine.options_( dirTempAt, o ); + + if( !o.packageName ) + o.packageName = _.idWithGuid(); + else + o.packageName = o.packageName + '-' + _.idWithTime(); + + if( !o.packagePath ) + o.packagePath = this.dirTemp(); + + _.assert( this.isAbsolute( o.packagePath ) ); + _.assert( !this.isAbsolute( o.packageName ), () => 'Option {- o.packageName -} should be relative path, but is ' + o.packageName ); + + o.fullPath = this.join( o.packagePath, 'tmp.tmp', o.packageName ); + + return o.fullPath; +} + +dirTempAt.defaults = +{ + packageName : null, + packagePath : null +} + +// + +let PathDirTempForMap = Object.create( null ); +let PathDirTempCountMap = Object.create( null ); + +function tempOpen( o ) +{ + let self = this; + + if( !_.mapIs( arguments[ 0 ] ) ) + o = { filePath : arguments[ 0 ] } + if( arguments[ 1 ] !== undefined ) + o.name = arguments[ 1 ]; + + if( o.filePath === undefined || o.filePath === null ) + o.filePath = self.current(); + else + o.filePath = self.resolve( o.filePath ); + + _.routine.options( tempOpen, o ); + _.assert( arguments.length <= 2 ); + _.assert( !!self.fileProvider ); + _.assert( o.filePath === null || self.isAbsolute( o.filePath ) ); + _.assert( o.filePath === null || self.isNormalized( o.filePath ) ); + + let id = self.fileProvider.id; + + /* qqq : use single map */ + if( !PathDirTempForMap[ id ] ) + PathDirTempForMap[ id ] = Object.create( null ); + if( !PathDirTempCountMap[ id ] ) + PathDirTempCountMap[ id ] = Object.create( null ); + + /* search in cache */ + + let cache = PathDirTempForMap[ id ]; + let count = PathDirTempCountMap[ id ]; + + let result = o.filePath !== null ? cache[ o.filePath ] : null; + if( result ) + return end(); + + let trace = self.traceToRoot( o.filePath ); + + if( o.filePath !== null ) + for( let i = trace.length - 1; i >= 0; i-- ) + { + if( !cache[ trace[ i ] ] ) + continue; + + if( i !== trace.length - 1 ) + if( self.fileProvider.fileExists( trace[ i + 1 ] ) ) + { + let currentStat = self.fileProvider.statReadAct + ({ + filePath : trace[ i ], + throwing : 1, + sync : 1, + resolvingSoftLink : 0, + }); + let nextStat = self.fileProvider.statReadAct + ({ + filePath : trace[ i + 1 ], + throwing : 0, + sync : 1, + resolvingSoftLink : 0, + }); + + if( nextStat.dev !== currentStat.dev ) + break; + } + + result = cache[ trace[ i ] ]; + + return end(); + } + + /* make */ + + result = self.pathDirTempMake({ filePath : o.filePath, name : o.name }); + return end(); + + /* */ + + function end() + { + + /* qqq : for Vova : bad! : ?? */ + if( o.resolving ) + result = self.fileProvider.pathResolveLinkFull + ({ + filePath : result, + resolvingSoftLink : 1 + }).absolutePath; + + /* qqq : for Dmytro : ? */ + if( self.fileProvider instanceof _.FileProvider.Default ) /* xxx qqq : for Dmytro : find better way to fix problem */ /* Dmytro : it is hack, temporary */ + _.assert( !self.path.isGlobal( result ), 'Expects non-global path' ); + /* xxx : qqq : uncomment and fix */ + + if( count[ result ] === undefined ) + count[ result ] = []; + + count[ result ].push( o.filePath ); + + cache[ o.filePath ] = result; + + return result; + } + +} + +tempOpen.defaults = +{ + filePath : null, + name : null, + resolving : 1, + auto : 1 +} + +// + +/* + +filePath : /dir1/dir2/dir3 + +- dirMake +/Temp +/dir1/Temp +/dir1/dir2/Temp +/dir1/dir2/dir3/Temp + +- fileRename +/Temp/x +/dir1/Temp/x +/dir1/dir2/Temp/x +/dir1/dir2/dir3/Temp/x + +*/ + +/* + += /dir1 - device1, /dir1/dir2 - device2 + +open /dir1 + pathDirTempMake /dir1 + search from root + cache + /dir1 : /dir1/temp + +open /dir1/dir2 + pathDirTempMake /dir1/dir2 + search and check cache + search from root + cache + /dir1 : /dir1/temp + /dir1/dir2 : /dir1/dir2/temp + +close /dir1/dir2 + ceck cache + cache + /dir1 : /dir1/temp + ceck cache 2nd time + delete /dir1/dir2/Temp + +close /dir1 + ceck cache + cache + ceck cache 2nd time + delete /dir1/temp + +*/ + +/* + += /dir1 - device1, /dir1/dir2 - device1 + +open /dir1 + pathDirTempMake /dir1 + search from root + cache + /dir1 : /dir1/temp + +open /dir1/dir2 + pathDirTempMake /dir1/dir2 + search and check cache + cache + /dir1 : /dir1/temp + /dir1/dir2 : /dir1/temp + +close /dir1/dir2 + ceck cache + cache + /dir1 : /dir1/temp + ceck cache 2nd time + +close /dir1 + ceck cache + cache + ceck cache 2nd time + delete /dir1/temp + +*/ + +// + +function pathDirTempMake( o ) +{ + let self = this; + + _.routine.options_( pathDirTempMake, arguments ); + _.assert( arguments.length === 1 ); + _.assert( !!self.fileProvider ); + _.assert( self.isAbsolute( o.filePath ) ); + _.assert( self.isNormalized( o.filePath ) ); + + let filePath = o.filePath; + let err; + + let trace = self.traceToRoot( o.filePath ); + + if( !trace.length ) + { + _.assert( o.filePath === '/' ); + trace = [ o.filePath ]; + } + else if( trace.length > 1 ) + trace.shift(); + + if( !o.name ) + o.name = 'tmp'; + o.name = o.name + '-' + _.idWithDateAndTime() + '.tmp'; + + /* */ + + let osTempDir = self.dirTemp(); + let sameDevice = self.fileProvider.filesAreOnSameDevice( o.filePath, osTempDir ); + + if( sameDevice ) + { + filePath = self.join( osTempDir, o.name ); + self.fileProvider.dirMake( filePath ); + return end(); + } + + /* */ + + let id = self.fileProvider.id; + + if( !PathDirTempForMap[ id ] ) + PathDirTempForMap[ id ] = Object.create( null ); + + let cache = PathDirTempForMap[ id ]; + + let fileStat; + + for( let i = 0; i < trace.length; i++ ) + { + try + { + if( i !== trace.length - 1 ) + if( self.fileProvider.fileExists( trace[ i ] ) ) + { + let currentStat = self.fileProvider.statReadAct + ({ + filePath : trace[ i ], + throwing : 1, + sync : 1, + resolvingSoftLink : 0, + }); + + if( fileStat === undefined ) + fileStat = self.fileProvider.statReadAct + ({ + filePath : o.filePath, + throwing : 0, + sync : 1, + resolvingSoftLink : 0, + }); + + if( fileStat ) + if( fileStat.dev != currentStat.dev ) + continue; + } + + if( cache[ trace[ i ] ] ) + { + filePath = cache[ trace[ i ] ]; + } + else + { + filePath = self.join( trace[ i ], 'Temp', o.name ); + if( !self.fileProvider.fileExists( filePath ) ) + self.fileProvider.dirMake( filePath ); + } + + return end(); + } + catch( e ) + { + err = e; + } + } + + if( err ) + { + filePath = _.path.join( osTempDir, o.name ); + self.fileProvider.dirMake( filePath ); + } + + return end(); + + /* */ + + function end() + { + + if( o.auto ) + _.process.on( _.event.Chain( 'available', 'exit' ), () => + { + self.tempClose() + }); + + return filePath; + } +} + +pathDirTempMake.defaults = Object.create( tempOpen.defaults ); + +// + +function tempClose( filePath ) +{ + let self = this; + + _.assert( arguments.length <= 1 ); + _.assert( !!self.fileProvider ); + + let id = self.fileProvider.id; + + if( !PathDirTempForMap[ id ] ) + return; + + let cache = PathDirTempForMap[ id ]; + let count = PathDirTempCountMap[ id ]; + + if( !arguments.length ) + { + for( let path in cache ) + { + delete count[ cache[ path ] ]; + close( path ); + } + } + else + { + _.assert( self.isAbsolute( filePath ) ); + _.assert( self.isNormalized( filePath ) ); + + let currentTempPath = cache[ filePath ]; + + /* reverse search for case when filePath is a temp path */ + if( !currentTempPath ) + for( let path in cache ) + if( cache[ path ] === filePath ) + { + currentTempPath = filePath; + filePath = path; + break; + } + + if( !currentTempPath ) + throw _.err( 'Not found temp dir for path: ' + filePath ); + + _.arrayRemoveElementOnce( count[ currentTempPath ], filePath ); + + /* if temp path is still in use */ + if( count[ currentTempPath ].length ) + { + if( !_.longHas( count[ currentTempPath ], filePath ) ) + delete cache[ filePath ]; + return; + } + + _.assert( !count[ currentTempPath ].length > 0 ); + + delete count[ currentTempPath ]; + + close( filePath ); + } + + /* */ + + function close( filePath ) + { + let tempPath = cache[ filePath ]; + self.fileProvider.filesDelete + ({ + filePath : tempPath, + safe : 0, + throwing : 0, + }); + delete cache[ filePath ]; + _.assert( !self.fileProvider.fileExists( tempPath ), 'Temp dir:', _.strQuote( tempPath ), 'was closed, but still exist in file system.' ); + return tempPath; + } + +} + +// + +function forCopy_head( routine, args ) +{ + + _.assert( args.length === 1 ); + + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { filePath : o }; + + _.routine.options_( routine, o ); + _.assert( _.strIs( o.filePath ) ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + return o; +} + +// + +function forCopy_body( o ) +{ + let path = this; + const fileProvider = this.fileProvider; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let postfix = _.strPrependOnce( o.postfix, o.postfix ? '-' : '' ); + let file = fileProvider.recordFactory().record( o.filePath ); + let name = file.name; + + let parts = _.strSplitFast({ src : name, delimeter : '-', preservingEmpty : 0, preservingDelimeters : 0 }); + if( parts[ parts.length-1 ] === o.postfix ) + name = parts.slice( 0, parts.length-1 ).join( '-' ); + + // !!! this condition (first if below) is not necessary, because if it fulfilled then previous fulfiled too, and has the + // same effect as previous + + if( parts.length > 1 && parts[ parts.length-1 ] === o.postfix ) + name = parts.slice( 0, parts.length-1 ).join( '-' ); + else if( parts.length > 2 && parts[ parts.length-2 ] === o.postfix ) + name = parts.slice( 0, parts.length-2 ).join( '-' ); + + /*file.absolute = file.dir + '/' + file.name + file.extWithDot;*/ + + let filePath = path.join( file.dir, name + postfix + file.extWithDot ); + if( !fileProvider.statResolvedRead({ filePath, sync : 1 }) ) + return filePath; + + let attempts = 1 << 13; + let index = 1; + + while( attempts > 0 ) + { + + let filePath = path.join( file.dir, name + postfix + '-' + index + file.extWithDot ); + + if( !fileProvider.statResolvedRead({ filePath, sync : 1 }) ) + return filePath; + + attempts -= 1; + index += 1; + + } + + throw _.err( 'Cant make copy path for : ' + file.absolute ); +} + +forCopy_body.defaults = +{ + delimeter : '-', + postfix : 'copy', + filePath : null, +} + +var having = forCopy_body.having = Object.create( null ); +having.driving = 0; +having.aspect = 'body'; + +// + +/** + * Generate path string for copy of existing file passed into `o.path`. If file with generated path is exists now, + * method try to generate new path by adding numeric index into tail of path, before extension. + * @example + * let str = 'foo/bar/baz.txt', + let path = wTools.pathforCopy( {path : str } ); // 'foo/bar/baz-copy.txt' + * @param {Object} o options argument + * @param {string} o.path Path to file for create name for copy. + * @param {string} [o.postfix='copy'] postfix for mark file copy. + * @returns {string} path for copy. + * @throws {Error} If missed argument, or passed more then one. + * @throws {Error} If passed object has unexpected property. + * @throws {Error} If file for `o.path` is not exists. + * @function forCopy + * @namespace wTools.path + * @module Tools/mid/Files + */ + +let forCopy = _.routine.uniteCloning_replaceByUnite( forCopy_head, forCopy_body ); + +forCopy.having.aspect = 'entry'; + +function _firstAvailable_head( routine, args ) +{ + + _.assert( args.length === 1 ); + + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { paths : o } + + _.routine.options_( routine, o ); + _.assert( _.arrayIs( o.paths ) ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + return o; +} + +// + +function _firstAvailable_body( o ) +{ + let path = this; + const fileProvider = path.fileProvider; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + for( let p = 0 ; p < o.paths.length ; p++ ) + { + let path = o.paths[ p ]; + if( fileProvider.fileExists( o.onPath ? o.onPath.call( o, path, p ) : path ) ) + return path; + } + + return undefined; +} + +_firstAvailable_body.defaults = +{ + paths : null, + onPath : null, +} + +var having = _firstAvailable_body.having = Object.create( null ); +having.driving = 0; +having.aspect = 'body'; + +let firstAvailable = _.routine.uniteCloning_replaceByUnite( _firstAvailable_head, _firstAvailable_body ); +firstAvailable.having.aspect = 'entry'; + +// -- +// declare +// -- + +let Extension = +{ + + // realMainFile, + // realMainDir, + // + // effectiveMainFile, + // effectiveMainDir, + + resolveTextLink, + // _resolveTextLink, + + dirUserHome, + dirTemp, + + /* qqq merge dirTempAtOpen + tempOpen and dirTempAtClose + tempClose */ + + dirTempAt, + // dirTempAtOpen, + // dirTempAtClose, + + tempOpen, + pathDirTempMake, + tempClose, + + forCopy, + firstAvailable, + + // fields + + PathDirTempForMap, + PathDirTempCountMap, + +} + +Object.assign( _.path, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _.path; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l3/Path.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Path_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Path_ss */ })(); + +/* */ /* begin of file Record_s */ ( function Record_s() { function Record_s_naked() { ( function _Record_s_() +{ + +'use strict'; + +// -- +// declare +// -- + +/** + * @classdesc Class to create record for a file. + * @class wFileRecord + * @namespace wTools + * @module Tools/mid/Files +*/ + +const _global = _global_; +const _ = _global_.wTools; +const Parent = null; +const Self = wFileRecord; +function wFileRecord( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'FileRecord'; + +_.assert( !_.files.FileRecord ); + +// -- +// inter +// -- + +function init( o ) +{ + let record = this; + + if( _.strIs( o ) ) + o = { input : o } + + _.assert( arguments.length === 1 ); + _.assert( !( arguments[ 0 ] instanceof _.files.FileRecordFactory ) ); + _.assert( _.strIs( o.input ), () => 'Expects string {-o.input-}, but got ' + _.entity.strType( o.input ) ); + _.assert( _.object.isBasic( o.factory ) ); + + _.workpiece.initFields( record ); + + record._filterReset(); + record._statReset(); + + // if( _.strEnds( o.input, 'recordStat/file' ) ) + // debugger; + + record.copy( o ); + + let f = record.factory; + if( f.strict ) + Object.preventExtensions( record ); + + if( !f.formed ) + { + if( !f.basePath && !f.dirPath && !f.stemPath ) + { + f.basePath = _.uri.dir( o.input ); + f.stemPath = f.basePath; + } + f.form(); + } + + record.form(); + return record; +} + +// + +function form() +{ + let record = this; + + _.assert( Object.isFrozen( record.factory ) ); + _.assert( !!record.factory.formed, 'Record factory is not formed' ); + _.assert( record.factory.system instanceof _.FileProvider.Abstract ); + _.assert( record.factory.effectiveProvider instanceof _.FileProvider.Abstract ); + _.assert( _.strIs( record.input ), '{ record.input } must be a string' ); + _.assert( record.factory instanceof _.files.FileRecordFactory, 'Expects instance of { FileRecordFactory }' ); + + record._pathsForm(); + + _.assert( record.fullName.indexOf( '/' ) === -1, 'something wrong with filename' ); + + return record; +} + +// + +/** + * @summary Returns a clone of current file record. + * @function clone + * @class wFileRecord + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function clone( src ) +{ + let record = this; + let f = record.factory; + + src = src || record.input; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.strIs( src ) ); + + let result = _.files.FileRecord({ input : src, factory : f }); + + return result; +} + +// + +/** + * @summary Creates instance of FileRecord from provided entity `src`. + * @param {Object|String} src Options map or path to a file. + * @function From + * @class wFileRecord + * @namespace wTools + * @module Tools/mid/Files +*/ + +function From( src ) +{ + return Self( src ); +} + +// + +/** + * @summary Creates several instances of FileRecord from provided arguments. + * @param {Array} src Array with options or paths. + * @function FromMany + * @class wFileRecord + * @namespace wTools + * @module Tools/mid/Files +*/ + +function FromMany( src ) +{ + let result = []; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.arrayIs( src ) ); + + for( let s = 0 ; s < src.length ; s++ ) + result[ s ] = Self.From( src[ s ] ); + + return result; +} + +// + +/** + * @summary Returns absolute path to a file associated with provided `record`. + * @description Uses current instance if no argument provided. + * @param {Object} record Instance of FileRecord. + * @function toAbsolute + * @class wFileRecord + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function toAbsolute( record ) +{ + + if( record === undefined ) + record = this; + + if( _.strIs( record ) ) + return record; + + _.assert( _.object.isBasic( record ) ); + + let result = record.absolute; + + _.assert( _.strIs( result ) ); + + return result; +} + +// + +function _safeCheck() +{ + let record = this; + let path = record.path; + let f = record.factory; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( f.safe && f.stating ) + { + if( record.stat ) + if( !path.isSafe( record.absolute, f.safe ) ) + { + debugger; + throw path.ErrorNotSafe( 'Making record', record.absolute, f.safe ); + } + if( record.stat && !record.stat.isTerminal() && !record.stat.isDir() && !record.stat.isSymbolicLink() ) + { + debugger; + throw path.ErrorNotSafe( 'Making record. Unknown kind of file', record.absolute, f.safe ); + } + } + + return true; +} + +// + +function _pathsForm() +{ + let record = this; + let f = record.factory; + const fileProvider = f.effectiveProvider; + let path = record.path + let inputPath = record.input; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( _.strIs( f.basePath ) ); + _.assert( _.strIs( f.stemPath ) ); + _.assert( path.isAbsolute( f.stemPath ) ); + + /* input path */ + + inputPath = path.normalize( inputPath ); + let isAbsolute = path.isAbsolute( inputPath ); + + if( !isAbsolute ) + if( f.dirPath ) + inputPath = path.join( f.basePath, f.dirPath, f.stemPath, inputPath ); + else if( f.basePath ) + inputPath = path.join( f.basePath, f.stemPath, inputPath ); + else if( !path.isAbsolute( inputPath ) ) + _.assert( 0, 'FileRecordFactory expects defined fields {-dirPath-} or {-basePath-} or absolute path' ); + + inputPath = fileProvider.path.preferredFromGlobal( inputPath ); + + /* relative path */ + + record[ relativeSymbol ] = path.relative( f.basePath, inputPath ); + _.assert( record.relative[ 0 ] !== '/' ); + record[ relativeSymbol ] = path.dot( record.relative ); + + /* absolute path */ + + if( f.basePath ) + record[ absoluteSymbol ] = path.resolve( f.basePath, record.relative ); + else + record[ absoluteSymbol ] = inputPath; + + record[ absoluteSymbol ] = path.normalize( record[ absoluteSymbol ] ); + + /* */ + + f.system._recordFormBegin( record ); + + return record; +} + +// + +function _filterReset() +{ + let record = this; + let f = record.factory; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + record[ isTransientSymbol ] = null; + record[ isActualSymbol ] = null; + +} + +// + +function _filterApply() +{ + let record = this; + let f = record.factory; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( record[ isTransientSymbol ] === null ) + record[ isTransientSymbol ] = true; + if( record[ isActualSymbol ] === null ) + record[ isActualSymbol ] = true; + + if( f.filter ) + { + _.assert( f.filter.formed === 5, 'Expects formed filter' ); + f.filter.applyTo( record ); + } + +} + +// + +function _statReset() +{ + let record = this; + let f = record.factory; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + record[ realSymbol ] = 0; + record[ statSymbol ] = 0; + record[ isCycledSymbol ] = null; + record[ isMissedSymbol ] = null; + +} + +// + +function _statRead() +{ + let record = this; + let f = record.factory; + let stat; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + record[ realSymbol ] = record.absolute; + + if( f.resolvingSoftLink || f.resolvingTextLink ) + { + + let o2 = + { + system : f.system, + filePath : record.absolute, + resolvingSoftLink : f.resolvingSoftLink, + resolvingTextLink : f.resolvingTextLink, + resolvingHeadDirect : 1, + resolvingHeadReverse : 1, + allowingMissed : f.allowingMissed, + allowingCycled : f.allowingCycled, + throwing : 1, + } + + let resolved = f.effectiveProvider.pathResolveLinkFull( o2 ); + record[ realSymbol ] = resolved.filePath; + + record[ isCycledSymbol ] = !!resolved.isCycled; + record[ isMissedSymbol ] = !!resolved.isMissed; + + // if( _.strEnds( record.absolute, 'Cycled.txt' ) ) + // debugger; + + stat = o2.stat; + } + + /* read and set stat */ + + if( f.stating ) + { + + _.assert( _.routineIs( f.effectiveProvider.statReadAct ) ); + if( stat === undefined ) + stat = f.effectiveProvider.statReadAct + ({ + filePath : record.real, + throwing : 0, + resolvingSoftLink : 0, + sync : 1, + }); + + record[ statSymbol ] = stat; + + } + + /* analyze stat */ + + return record; +} + +// + +function _statAnalyze() +{ + let record = this; + let f = record.factory; + const fileProvider = f.effectiveProvider; + let path = record.path; + let logger = fileProvider.logger || _global.logger; + + _.assert( f instanceof _.files.FileRecordFactory, '_record expects instance of ( FileRecordFactory )' ); + _.assert( fileProvider instanceof _.FileProvider.Abstract, 'Expects file provider instance of FileProvider' ); + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( f.stating ) + { + _.assert( record.stat === null || _.fileStatIs( record.stat ) ); + record._safeCheck(); + } + + f.system._recordFormEnd( record ); + +} + +// + +/** + * @summary Resets stats and filter values of current instance. + * @function reset + * @class wFileRecord + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function reset() +{ + let record = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + record._filterReset(); + record._statReset(); + +} + +// + +/** + * @summary Changes file extension of current record. + * @param {String} ext New file extension. + * @function changeExt + * @class wFileRecord + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function changeExt( ext ) +{ + let record = this; + let path = record.path; + _.assert( arguments.length === 1, 'Expects single argument' ); + record.input = path.changeExt( record.input, ext ); +} + +// + +/** + * @summary Returns file hash of current record. + * @function hashRead + * @class wFileRecord + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function hashRead() +{ + let record = this; + let f = record.factory; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( record.hash !== null ) + return record.hash; + + record.hash = f.effectiveProvider.hashRead + ({ + filePath : record.absolute, + logger : 0, + }); + + return record.hash; +} + +// + +function _isTransientGet() +{ + let record = this; + let result = record[ isTransientSymbol ]; + if( result === null ) + { + record._filterApply(); + result = record[ isTransientSymbol ]; + } + return result; +} + +// + +function _isTransientSet( src ) +{ + let record = this; + src = !!src; + record[ isTransientSymbol ] = src; + return src; +} + +// + +function _isActualGet() +{ + let record = this; + let result = record[ isActualSymbol ]; + if( result === null ) + { + record._filterApply(); + result = record[ isActualSymbol ]; + } + return result; +} + +// + +function _isActualSet( src ) +{ + let record = this; + src = !!src; + record[ isActualSymbol ] = src; + return src; +} + +// + +function _isStemGet() +{ + let record = this; + let f = record.factory; + return f.stemPath === record.absolute; +} + +// + +function _isDirGet() +{ + let record = this; + + if( !record.stat ) + return false; + + _.assert( _.routineIs( record.stat.isDir ) ); + + return record.stat.isDir(); +} + +// + +function _isTerminalGet() +{ + let record = this; + + if( !record.stat ) + return false; + + _.assert( _.routineIs( record.stat.isTerminal ) ); + + return record.stat.isTerminal(); +} + +// + +function _isHardLinkGet() +{ + let record = this; + let f = record.factory; + + if( !record.stat ) + return false; + + return record.stat.isHardLink(); +} + +// + +function _isSoftLinkGet() +{ + let record = this; + let f = record.factory; + + if( !f.usingSoftLink ) + return false; + + if( !record.stat ) + return false; + + return record.stat.isSoftLink(); +} + +// + +function _isTextLinkGet() +{ + let record = this; + let f = record.factory; + + if( !f.usingTextLink ) + return false; + + if( f.resolvingTextLink ) + return false; + + debugger; + + if( !record.stat ) + return false; + + return record.stat.isTextLink(); +} + +// + +function _isLinkGet() +{ + let record = this; + let f = record.factory; + return record._isSoftLinkGet() || record._isTextLinkGet(); +} + +// + +function absoluteSet( src ) +{ + let record = this; + let f = record.factory; + let formed = !!record[ absoluteSymbol ]; + + record.reset(); + + if( src ) + { + record[ absoluteSymbol ] = null; + record[ relativeSymbol ] = null; + record[ inputSymbol ] = src; + if( formed ) + record._pathsForm(); + } + +} + +// + +function relativeSet( src ) +{ + let record = this; + let f = record.factory; + let formed = !!record[ absoluteSymbol ]; + + record.reset(); + + if( src ) + { + record[ absoluteSymbol ] = null; + record[ relativeSymbol ] = null; + record[ inputSymbol ] = src; + if( formed ) + record._pathsForm(); + } + +} + +// + +function inputSet( src ) +{ + let record = this; + let f = record.factory; + let formed = !!record[ absoluteSymbol ]; + + record.reset(); + + if( src ) + { + record[ absoluteSymbol ] = null; + record[ relativeSymbol ] = null; + record[ inputSymbol ] = src; + if( formed ) + record._pathsForm(); + } + +} + +// + +function _pathGet() +{ + let record = this; + let f = record.factory; + // _.assert( !!f ); + if( !f ) + return null; + const fileProvider = f.system; + return fileProvider.path; +} + +// + +function _effectiveProviderGet() +{ + let record = this; + let f = record.factory; + if( !f ) + return null; + return f.effectiveProvider; +} + +// + +function _systemGet() +{ + let record = this; + let f = record.factory; + if( !f ) + return null; + return f.effectiveProvider; +} + +// + +function _statGet() +{ + let record = this; + if( record[ statSymbol ] === 0 ) + { + record._statRead(); + record._statAnalyze(); + } + return record[ statSymbol ]; +} + +// + +function _realGet() +{ + let record = this; + if( record[ realSymbol ] === 0 ) + { + debugger; + record._statRead(); + record._statAnalyze(); + } + return record[ realSymbol ]; +} + +// + +function _absoluteGlobalGet() +{ + let record = this; + let f = record.factory; + const fileProvider = f.effectiveProvider; + return fileProvider.path.globalFromPreferred( record.absolute ); +} + +// + +function _realGlobalGet() +{ + let record = this; + let f = record.factory; + const fileProvider = f.effectiveProvider; + return fileProvider.path.globalFromPreferred( record.real ); +} + +// + +function _absolutePreferredGet() +{ + let record = this; + let f = record.factory; + const fileProvider = f.system; + return fileProvider._recordAbsoluteGlobalMaybeGet( record ); +} + +// + +function _realPreferredGet() +{ + let record = this; + let f = record.factory; + const fileProvider = f.system; + return fileProvider._recordRealGlobalMaybeGet( record ); +} + +// + +function _dirGet() +{ + let record = this; + let f = record.factory; + let path = record.path; + return path.dir( record.absolute ); +} + +// + +function _extsGet() +{ + let record = this; + let f = record.factory; + let path = record.path; + return path.exts( record.absolute ); +} + +// + +function _extGet() +{ + let record = this; + let f = record.factory; + let path = record.path; + return path.ext( record.absolute ); +} + +// + +function _extWithDotGet() +{ + let record = this; + let f = record.factory; + let ext = record.ext; + return ext ? '.' + ext : ''; +} + +// + +function _qualifiedNameGet() +{ + let record = this; + let f = record.factory; + if( f && f.path ) + return '{ ' + record.constructor.shortName + ' : ' + f.path.name( record.absolute ) + ' }'; + else + return '{ ' + record.constructor.shortName + ' }'; +} + +// + +function _nameGet() +{ + let record = this; + let f = record.factory; + let path = record.path; + return path.name( record.absolute ); +} + +// + +function _fullNameGet() +{ + let record = this; + let f = record.factory; + let path = record.path; + return path.fullName( record.absolute ); +} + +// -- +// statics +// -- + +function statCopier( it ) +{ + let record = this; + if( it.technique === 'data' ) + return _.props.fields( it.src ); + else + return it.src; +} + +// -- +// relations +// -- + +let statSymbol = Symbol.for( 'stat' ); +let realSymbol = Symbol.for( 'real' ); +let isTransientSymbol = Symbol.for( 'isTransient' ); +let isActualSymbol = Symbol.for( 'isActual' ); + +let inputSymbol = Symbol.for( 'input' ); +let relativeSymbol = Symbol.for( 'relative' ); +let absoluteSymbol = Symbol.for( 'absolute' ); + +let isCycledSymbol = Symbol.for( 'isCycled' ); +let isMissedSymbol = Symbol.for( 'isMissed' ); + +/** + * @typedef {Object} Fields + * @property {String} absolute Absolute path to a file. + * @property {String} relative Relative path to a file. + * @property {String} input Source path to a file. + * @property {String} hash Hash of a file. + * @property {Object} factory Instance of FileRecordFactory. + * @class wFileRecord + * @namespace wTools + * @module Tools/mid/Files +*/ + +let Composes = +{ + + absolute : null, + relative : null, + input : null, + hash : null, + included : null, + +} + +let Aggregates = +{ +} + +let Associates = +{ + factory : null, + associated : null, +} + +let Restricts = +{ +} + +let Statics = +{ + From, + FromMany, + toAbsolute, +} + +let Copiers = +{ + stat : statCopier, +} + +let Forbids = +{ +} + +let Accessors = +{ + + path : { writable : 0 }, + effectiveProvider : { writable : 0 }, + system : { writable : 0 }, + stat : { writable : 0 }, + + real : { writable : 0 }, + absoluteGlobal : { writable : 0 }, + realGlobal : { writable : 0 }, + absolutePreferred : { writable : 0 }, + realPreferred : { writable : 0 }, + + dir : { writable : 0 }, + exts : { writable : 0 }, + ext : { writable : 0 }, + extWithDot : { writable : 0 }, + qualifiedName : { writable : 0 }, + name : { writable : 0 }, + fullName : { writable : 0 }, + + isTransient : { writable : 1 }, + isActual : { writable : 1 }, + isStem : { writable : 0 }, + isDir : { writable : 0 }, + isTerminal : { writable : 0 }, + isHardLink : { writable : 0 }, + isSoftLink : { writable : 0 }, + isTextLink : { writable : 0 }, + isLink : { writable : 0 }, + + isCycled : { set : 0 }, + isMissed : { set : 0 }, + + absolute : { set : absoluteSet }, + relative : { set : relativeSet }, + input : { set : inputSet }, + +} + +// -- +// defined +// -- + +let Extension = +{ + + init, + form, + clone, + From, + FromMany, + toAbsolute, + + _safeCheck, + _pathsForm, + _filterReset, + _filterApply, + _statReset, + _statRead, + _statAnalyze, + + reset, + changeExt, + hashRead, + + _isTransientGet, + _isTransientSet, + _isActualGet, + _isActualSet, + _isStemGet, + _isDirGet, + _isTerminalGet, + _isHardLinkGet, + _isSoftLinkGet, + _isTextLinkGet, + _isLinkGet, + + absoluteSet, + relativeSet, + inputSet, + + _pathGet, + _effectiveProviderGet, + _systemGet, + _statGet, + + _realGet, + _absoluteGlobalGet, + _realGlobalGet, + _absolutePreferredGet, + _realPreferredGet, + + _dirGet, + _extsGet, + _extGet, + _extWithDotGet, + _qualifiedNameGet, + _nameGet, + _fullNameGet, + + // + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + Copiers, + Forbids, + Accessors, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Extension, +}); + +_.Copyable.mixin( Self ); + +_.assert( !_global_.wFileRecord && !_.files.FileRecord, 'wFileRecord already defined' ); + +_.files[ Self.shortName ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l3/Record.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Record_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Record_s */ })(); + +/* */ /* begin of file RecordFactory_s */ ( function RecordFactory_s() { function RecordFactory_s_naked() { ( function _FileRecordFactory_s_() +{ + +'use strict'; + +/** + * @class wFileRecordFactory + * @namespace wTools + * @module Tools/mid/Files +*/ + +const _global = _global_; +const _ = _global_.wTools; +const Parent = _.files.FileRecordContext; +const Self = wFileRecordFactory; +function wFileRecordFactory( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'FileRecordFactory'; + +_.assert( !_.files.FileRecordFactory ); + +// -- +// routine +// -- + +function init( o ) +{ + let factory = this; + + factory[ usingSoftLinkSymbol ] = null; + factory[ resolvingSoftLinkSymbol ] = null; + factory[ usingTextLinkSymbol ] = null; + factory[ resolvingTextLinkSymbol ] = null; + factory[ statingSymbol ] = null; + factory[ safeSymbol ] = null; + + _.assert( arguments.length === 0 || arguments.length === 1, 'Expects single argument' ); + + _.workpiece.initFields( factory ); + Object.preventExtensions( factory ); + + /* */ + + for( let a = 0 ; a < arguments.length ; a++ ) + { + let src = arguments[ a ]; + if( _.mapIs( src ) ) + Object.assign( factory, src ); + else + Object.assign( factory, _.mapOnly_( null, src, Self.prototype.fieldsOfCopyableGroups ) ); + } + + return factory; +} + +// + +function _formAssociations() +{ + let factory = this; + + _.assert( factory.formed === 0 ); + + /* */ + + if( factory.filter ) + { + factory.system = factory.system || factory.filter.system; + factory.effectiveProvider = factory.effectiveProvider || factory.filter.effectiveProvider; + factory.defaultProvider = factory.defaultProvider || factory.filter.defaultProvider; + } + + /* */ + + return Parent.prototype._formAssociations.apply( factory, arguments ); +} + +// + +function form() +{ + let factory = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( !factory.formed ); + + /* */ + + factory._formAssociations(); + + let system = factory.system || factory.effectiveProvider || factory.defaultProvider; + let path = system.path; + + /* */ + + if( factory.basePath ) + { + + _.assert( !!path ); + + factory.basePath = path.from( factory.basePath ); + factory.basePath = path.canonize( factory.basePath ); + + if( !factory.effectiveProvider ) + factory.effectiveProvider = system.providerForPath( factory.basePath ); + + if( Config.debug ) + if( _.path.isGlobal( factory.basePath ) ) + { + let url = _.uri.parse( factory.basePath ); + } + + if( factory.effectiveProvider ) + factory.basePath = factory.effectiveProvider.path.preferredFromGlobal( factory.basePath ); + + } + + /* */ + + if( factory.dirPath ) + { + factory.dirPath = path.from( factory.dirPath ); + factory.dirPath = path.canonize( factory.dirPath ); + + if( factory.effectiveProvider ) + factory.dirPath = factory.effectiveProvider.path.preferredFromGlobal( factory.dirPath ); + + if( factory.basePath ) + factory.dirPath = path.join( factory.basePath, factory.dirPath ); + + if( Config.debug ) + if( _.path.isGlobal( factory.dirPath ) ) + { + let url = _.uri.parse( factory.dirPath ); + } + } + + if( !factory.stemPath ) + { + factory.stemPath = path.canonize( path.join( factory.basePath, factory.dirPath || '' ) ); + } + else if( factory.stemPath ) + { + factory.stemPath = path.canonize( path.join( factory.basePath, factory.dirPath || '', factory.stemPath ) ); + if( factory.effectiveProvider ) + factory.stemPath = factory.effectiveProvider.path.preferredFromGlobal( factory.stemPath ); + } + + if( !factory.basePath ) + if( factory.dirPath ) + { + factory.basePath = factory.dirPath; + } + + if( !factory.basePath && factory.filter && factory.stemPath ) + { + _.assert( factory.filter.formed === 5 ); + factory.basePath = factory.filter.formedBasePath[ factory.stemPath ]; + } + + /* */ + + if( !factory.system ) + factory.system = factory.defaultProvider; + + if( !factory.effectiveProvider ) + factory.effectiveProvider = factory.defaultProvider; + + _.assert( !!factory.system ); + + factory.system._recordFactoryFormEnd( factory ); + + /* */ + + if( Config.debug ) + { + + _.assert( factory.system instanceof _.FileProvider.Abstract ); + _.assert( path.isAbsolute( factory.basePath ) ); + _.assert( factory.dirPath === null || path.is( factory.dirPath ) ); + _.assert( path.isAbsolute( factory.stemPath ) ); + + if( factory.dirPath ) + _.assert( _.path.isGlobal( factory.dirPath ) || path.isAbsolute( factory.dirPath ), () => '{-o.dirPath-} should be absolute path' + _.strQuote( factory.dirPath ) ); + + _.assert( _.strDefined( factory.basePath ) ); + _.assert( _.path.isGlobal( factory.basePath ) || path.isAbsolute( factory.basePath ), () => '{-o.basePath-} should be absolute path' + _.strQuote( factory.basePath ) ); + + _.assert( factory.filter === null || factory.filter instanceof _.files.FileRecordFilter ); + + if( factory.filter ) + { + _.assert( factory.filter.formed === 5 ); + _.assert( !!factory.filter.formedBasePath ); + _.assert( !!factory.filter.src || factory.filter.formedBasePath[ factory.stemPath ] === factory.basePath ); + _.assert( factory.filter.effectiveProvider === factory.effectiveProvider ); + _.assert( factory.filter.system === factory.system || factory.filter.system === null ); + _.assert( factory.filter.defaultProvider === factory.defaultProvider ); + } + + } + + factory.formed = 1; + Object.freeze( factory ); + return factory; +} + +// + +/** + * @summary Creates instance of FileRecord. + * @param {Object} o Options map. + * @function record + * @class wFileRecordFactory + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function record( o ) +{ + let factory = this; + + if( o instanceof _.files.FileRecord ) + { + _.assert( o.factory === factory || !!o.factory ); + return o; + } + + let op = Object.create( null ); + + if( _.strIs( o ) ) + { + o = { input : o } + } + + _.assert( arguments.length === 1 ); + _.assert( _.object.isBasic( o ) ); + _.assert( _.strIs( o.input ), () => 'Expects string {-o.input-}, but got ' + _.entity.strType( o.input ) ); + _.assert( o.factory === undefined || o.factory === factory ); + + o.factory = factory; + + return _.files.FileRecord( o ); +} + +// + +/** + * @summary Creates instances of FileRecord for provided file paths. + * @param {Array} filePaths Paths to files. + * @function records + * @class wFileRecordFactory + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +/** + * @summary Creates instances of FileRecord for provided file paths ignoring files that don't exist in file system. + * @param {Array} filePaths Paths to files. + * @function recordsFiltered + * @class wFileRecordFactory + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function recordsFiltered( filePaths ) +{ + var factory = this; + + _.assert( arguments.length === 1 ); + + var result = factory.records( filePaths ); + + for( var r = result.length-1 ; r >= 0 ; r-- ) + if( !result[ r ].stat ) + result.splice( r, 1 ); + + return result; +} + +// + +function _usingSoftLinkGet() +{ + let factory = this; + + if( factory[ usingSoftLinkSymbol ] !== null ) + return factory[ usingSoftLinkSymbol ]; + + if( factory.effectiveProvider ) + return factory.effectiveProvider.usingSoftLink; + else if( factory.system ) + return factory.system.usingSoftLink; + + return factory[ usingSoftLinkSymbol ]; +} + +// + +function _resolvingSoftLinkSet( src ) +{ + let factory = this; + factory[ resolvingSoftLinkSymbol ] = src; +} + +// + +function _resolvingSoftLinkGet() +{ + let factory = this; + + if( !factory.resolving ) + return false; + + if( factory[ resolvingSoftLinkSymbol ] !== null ) + return factory[ resolvingSoftLinkSymbol ]; + + if( factory.effectiveProvider ) + return factory.effectiveProvider.resolvingSoftLink; + else if( factory.system ) + return factory.system.resolvingSoftLink; + + return factory[ resolvingSoftLinkSymbol ]; +} + +// + +function _usingTextLinkGet() +{ + let factory = this; + + /* using knows nothing about resolving */ + // if( !factory.resolving ) + // return false; + + if( factory[ usingTextLinkSymbol ] !== null ) + return factory[ usingTextLinkSymbol ]; + + if( factory.effectiveProvider ) + return factory.effectiveProvider.usingTextLink; + else if( factory.system ) + return factory.system.usingTextLink; + + return factory[ usingTextLinkSymbol ]; +} + +// + +function _resolvingTextLinkGet() +{ + let factory = this; + + if( !factory.resolving ) + return false; + + if( factory[ resolvingTextLinkSymbol ] !== null ) + return factory[ resolvingTextLinkSymbol ]; + + if( factory.effectiveProvider ) + return factory.effectiveProvider.resolvingTextLink; + else if( factory.system ) + return factory.system.resolvingTextLink; + + return factory[ resolvingTextLinkSymbol ]; +} + +// + +function _statingGet() +{ + let factory = this; + + if( factory[ statingSymbol ] !== null ) + return factory[ statingSymbol ]; + + if( factory.effectiveProvider ) + return factory.effectiveProvider.stating; + else if( factory.system ) + return factory.system.stating; + + return factory[ statingSymbol ]; +} + +// + +function _safeGet() +{ + let factory = this; + + if( factory[ safeSymbol ] !== null ) + return factory[ safeSymbol ]; + + if( factory.effectiveProvider ) + return factory.effectiveProvider.safe; + else if( factory.system ) + return factory.system.safe; + + return factory[ safeSymbol ]; +} + +// -- +// relation +// -- + +let usingSoftLinkSymbol = Symbol.for( 'usingSoftLink' ); +let resolvingSoftLinkSymbol = Symbol.for( 'resolvingSoftLink' ); +let usingTextLinkSymbol = Symbol.for( 'usingTextLink' ); +let resolvingTextLinkSymbol = Symbol.for( 'resolvingTextLink' ); +let statingSymbol = Symbol.for( 'stating' ); +let safeSymbol = Symbol.for( 'safe' ); + +/** + * @typedef {Object} Fields + * @property {String} dirPath + * @property {String} basePath + * @property {String} stemPath + * @property {Boolean} strict=1 + * @property {Boolean} allowingMissed + * @property {Boolean} allowingCycled + * @property {Boolean} resolvingSoftLink + * @property {Boolean} resolvingTextLink + * @property {Boolean} usingTextLink + * @property {Boolean} stating + * @property {Boolean} resolving + * @property {Boolean} safe + * @class wFileRecordFactory + * @namespace wTools + * @module Tools/mid/Files +*/ + +let Composes = +{ + + dirPath : null, + basePath : null, + stemPath : null, + + strict : 1, + allowingMissed : 0, + allowingCycled : 0, + resolvingSoftLink : null, + resolvingTextLink : null, + usingSoftLink : null, + usingTextLink : null, + stating : null, + resolving : 1, + safe : null, + +} + +let Aggregates = +{ +} + +let Associates = +{ + system : null, + effectiveProvider : null, + defaultProvider : null, + filter : null, +} + +let Medials = +{ +} + +let Restricts = +{ + formed : 0, +} + +let Statics = +{ + // TolerantFrom : TolerantFrom, +} + +let Forbids = +{ + + dir : 'dir', + sync : 'sync', + relative : 'relative', + relativeIn : 'relativeIn', + relativeOut : 'relativeOut', + verbosity : 'verbosity', + maskAll : 'maskAll', + maskTerminal : 'maskTerminal', + maskDirectory : 'maskDirectory', + notOlder : 'notOlder', + notNewer : 'notNewer', + notOlderAge : 'notOlderAge', + notNewerAge : 'notNewerAge', + originPath : 'originPath', + onRecord : 'onRecord', + fileProviderEffective : 'fileProviderEffective', + fileProvider : 'fileProvider', + hubFileProvider : 'hubFileProvider', + effectiveFileProvider : 'effectiveFileProvider', + defaultFileProvider : 'defaultFileProvider', + +} + +let Accessors = +{ + + resolvingSoftLink : 'resolvingSoftLink', + usingSoftLink : 'usingSoftLink', + + resolvingTextLink : 'resolvingTextLink', + usingTextLink : 'usingTextLink', + + stating : 'stating', + safe : 'safe', + +} + +// -- +// declare +// -- + +let Extension = +{ + + init, + + _formAssociations, + form, + + record, + records : _.routineVectorize_functor( record ), + recordsFiltered, + + _usingSoftLinkGet, + _resolvingSoftLinkSet, + _resolvingSoftLinkGet, + + _usingTextLinkGet, + _resolvingTextLinkGet, + + _statingGet, + _safeGet, + + /* */ + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + Forbids, + Accessors, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Extension, +}); + +_.files[ Self.shortName ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l3/RecordFactory.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, RecordFactory_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file RecordFactory_s */ })(); + +/* */ /* begin of file RecordFilter_s */ ( function RecordFilter_s() { function RecordFilter_s_naked() { ( function _FileRecordFilter_s_() +{ + +'use strict'; + +// + +/** + * @class wFileRecordFilter + * @namespace wTools + * @module Tools/mid/Files +*/ + +const _global = _global_; +const _ = _global_.wTools; +const Parent = _.files.FileRecordContext; +const Self = wFileRecordFilter; +function wFileRecordFilter( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'FileRecordFilter'; + +_.assert( !_.files.FileRecordFilter ); +_.assert( !!_.regexpsEscape ); + +// -- +// inter +// -- + +function init( o ) +{ + let filter = this; + + _.workpiece.initFields( filter ); + Object.preventExtensions( filter ); + + if( o ) + filter.copy( o ); + + filter._formAssociations(); + + return filter; +} + +// + +function copy( src ) +{ + let filter = this; + + _.assert( arguments.length === 1 ); + + if( _.strIs( src ) || _.arrayIs( src ) ) + src = { prefixPath : src, filePath : '.' } + + let result = _.Copyable.prototype.copy.call( filter, src ); + + return result; +} + +// + +function pairedClone() +{ + let filter = this; + + let result = filter.clone(); + + if( filter.src ) + { + result.src = filter.src.clone(); + result.src.pairWithDst( result ); + result.src.pairRefineLight(); + return result; + } + + if( filter.dst ) + { + result.dst = filter.dst.clone(); + result.pairWithDst( result.dst ); + result.pairRefineLight(); + return result; + } + + return result; +} + +// -- +// former +// -- + +function form() +{ + let filter = this; + + if( filter.formed === 5 ) + return filter; + + filter._formAssociations(); + filter._formFinal(); + + _.assert( filter.formed === 5 ); + Object.freeze( filter ); + return filter; +} + +// + +function _formAssociations() +{ + let filter = this; + + let result = Parent.prototype._formAssociations.apply( filter, arguments ); + + /* */ + + filter.maskAll = _.RegexpObject( filter.maskAll ); + filter.maskTerminal = _.RegexpObject( filter.maskTerminal ); + filter.maskDirectory = _.RegexpObject( filter.maskDirectory ); + + filter.maskTransientAll = _.RegexpObject( filter.maskTransientAll ); + filter.maskTransientTerminal = _.RegexpObject( filter.maskTransientTerminal ); + filter.maskTransientDirectory = _.RegexpObject( filter.maskTransientDirectory ); + + /* */ + + filter.formed = 1; + return result; +} + +// + +function _formPre() +{ + let filter = this; + + if( filter.formed < 1 ) + filter._formAssociations(); + + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( filter.formed === 1 ); + _.assert( filter.prefixPath === null || _.strIs( filter.prefixPath ) || _.arrayIs( filter.prefixPath ) ); + _.assert( filter.postfixPath === null || _.strIs( filter.postfixPath ) || _.arrayIs( filter.postfixPath ) ); + _.assert( filter.basePath === null || _.strIs( filter.basePath ) || _.mapIs( filter.basePath ) ); + + filter.formed = 2; +} + +// + +function _formPaths() +{ + let filter = this; + + if( filter.formed > 2 ) + return; + if( filter.formed < 2 ) + filter._formPre(); + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( filter.formed === 2 ); + + filter.pathsRefine(); + filter.assertBasePath(); + + filter.formed = 3; +} + +// + +function _formMasks() +{ + let filter = this; + + if( filter.formed < 3 ) + filter._formPaths(); + + const fileProvider = filter.effectiveProvider || filter.defaultProvider || filter.system; + const path = fileProvider.path; + + if( filter.recursive === null ) + filter.recursive = 2; + + /* */ + + if( Config.debug ) + { + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( filter.formed === 3 ); + + if( filter.basePath ) + filter.assertBasePath(); + + _.assert( _.mapIs( filter.basePath ) || !!filter.src ); + _.assert( _.mapIs( filter.filePath ), 'filePath of file record filter is not defined' ); + + if( filter.basePath ) + filter.basePathEach( ( filePath, basePath ) => + { + _.assert( !!filter.src || filter.filePath[ filePath ] !== undefined, () => `Not found file path ${_.strQuote( filePath )}` ); + _.assert( path.isAbsolute( basePath ), () => `Expects absolute base path, but ${_.strQuote( basePath )} is not` ); + }); + + } + + /* */ + + filter.maskExtensionApply(); + filter.maskBeginsApply(); + filter.maskEndsApply(); + filter.masksGenerate(); + + filter.formed = 4; +} + +// + +function _formFinal() +{ + let filter = this; + + if( filter.formed < 4 ) + filter._formMasks(); + + /* + should use effectiveProvider because of option globbing of file provider + */ + + const fileProvider = filter.effectiveProvider || filter.system || filter.defaultProvider; + const path = fileProvider.path; + + /* - */ + + if( Config.debug ) + { + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( filter.formed === 4 ); + _.assert( _.strIs( filter.filePath ) || _.arrayIs( filter.filePath ) || _.mapIs( filter.filePath ) ); + _.assert( !!filter.src || _.mapIs( filter.formedBasePath ) || _.props.keys( filter.formedFilePath ).length === 0 ); + _.assert( !!filter.src || _.mapIs( filter.formedFilePath ) ); + _.assert( _.object.isBasic( filter.effectiveProvider ) ); + _.assert( filter.system === filter.effectiveProvider.system || filter.system === filter.effectiveProvider ); + _.assert( filter.system instanceof _.FileProvider.Abstract ); + _.assert( filter.defaultProvider instanceof _.FileProvider.Abstract ); + _.assert( filter.recursive === 0 || filter.recursive === 1 || filter.recursive === 2 ) + + let filePath = filter.filePathArrayGet( filter.formedFilePath ).filter( ( e ) => _.strIs( e ) && e ); + _.assert( path.s.noneAreGlob( filePath ) ); + _.assert + ( + path.s.allAreAbsolute( filePath ) || path.s.allAreGlobal( filePath ), + () => 'Expects absolute or global file path, but got\n' + _.entity.exportJson( filePath ) + ); + + if( _.mapIs( filter.formedBasePath ) ) + for( let p in filter.formedBasePath ) + { + let filePath = p; + let basePath = filter.formedBasePath[ p ]; + _.assert + ( + path.isAbsolute( filePath ) && path.isNormalized( filePath ) && !path.isGlob( filePath ) && !path.isTrailed( filePath ), + () => 'Stem path should be absolute and normalized, but not glob, neither trailed' + '\nstemPath : ' + _.entity.exportString( filePath ) + ); + _.assert + ( + path.isAbsolute( basePath ) && path.isNormalized( basePath ) && !path.isGlob( basePath ) && !path.isTrailed( basePath ), + () => 'Base path should be absolute and normalized, but not glob, neither trailed' + '\nbasePath : ' + _.entity.exportString( basePath ) + ); + } + + /* time */ + + if( filter.notOlder ) + _.assert( _.numberIs( filter.notOlder ) || _.dateIs( filter.notOlder ) ); + + if( filter.notNewer ) + _.assert( _.numberIs( filter.notNewer ) || _.dateIs( filter.notNewer ) ); + + if( filter.notOlderAge ) + _.assert( _.numberIs( filter.notOlderAge ) || _.dateIs( filter.notOlderAge ) ); + + if( filter.notNewerAge ) + _.assert( _.numberIs( filter.notNewerAge ) || _.dateIs( filter.notNewerAge ) ); + + } + + /* - */ + + if( filter.recursive === null ) + filter.recursive = 2; + + filter.applyTo = filter._recordFitNothing; + + if( filter.notOlder || filter.notNewer || filter.notOlderAge || filter.notNewerAge ) + filter.applyTo = filter._recordFitFull; + else if( filter.hasMask() ) + filter.applyTo = filter._recordFitMasks; + + filter.formed = 5; +} + +// -- +// combiner +// -- + +/** + * @descriptionNeeded + * @function And + * @class wFileRecordFilter + * @namespace wTools + * @module Tools/mid/Files +*/ + +function And() +{ + _.assert( !_.instanceIs( this ) ); + + let dst = null; + + if( arguments.length === 1 ) + return this.Self( arguments[ 0 ] ); + + for( let a = 0 ; a < arguments.length ; a++ ) + { + let src = arguments[ a ]; + + if( dst ) + dst = this.Self( dst ); + if( dst ) + dst.and( src ); + else + dst = this.Self( src ); + + } + + return dst; +} + +// + +/** + * @descriptionNeeded + * @function and + * @class wFileRecordFilter + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function and( src ) +{ + let filter = this; + + if( arguments.length > 1 ) + { + for( let a = 0 ; a < arguments.length ; a++ ) + filter.and( arguments[ a ] ); + return filter; + } + + if( src === null ) + return filter; + + const fileProvider = filter.effectiveProvider || filter.system || filter.defaultProvider; + if( !( src instanceof _.files.FileRecordFilter ) ) + src = fileProvider.recordFilter( src ); + + _.assert( filter instanceof _.files.FileRecordFilter ); + _.assert( src instanceof _.files.FileRecordFilter ); + _.assert( !filter.formed || filter.formed <= 1 ); + _.assert( !src.formed || src.formed <= 1 ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( filter.formedMasksMap === null ); + _.assert( filter.applyTo === null ); + _.assert( !filter.effectiveProvider || !src.effectiveProvider || filter.effectiveProvider === src.effectiveProvider ); + _.assert( !filter.system || !src.system || filter.system === src.system ); + + if( src === filter ) + return filter; + + /* */ + + if( src.effectiveProvider ) + filter.effectiveProvider = src.effectiveProvider + + if( src.system ) + filter.system = src.system + + /* */ + + let appending = + { + + hasExtension : null, + begins : null, + ends : null, + + } + + for( let a in appending ) + { + if( src[ a ] === null || src[ a ] === undefined ) + continue; + _.assert( _.strIs( src[ a ] ) || _.strsAreAll( src[ a ] ) ); + _.assert( filter[ a ] === null || _.strIs( filter[ a ] ) || _.strsAreAll( filter[ a ] ) ); + if( filter[ a ] === null ) + { + filter[ a ] = src[ a ]; + } + else + { + if( _.strIs( filter[ a ] ) ) + filter[ a ] = [ filter[ a ] ]; + _.arrayAppendOnce( filter[ a ], src[ a ] ); + } + } + + /* */ + + let once = + { + recursive : null, + notOlder : null, + notNewer : null, + notOlderAge : null, + notNewerAge : null, + } + + for( let n in once ) + { + _.assert + ( + !filter[ n ] || !src[ n ] || filter[ n ] === src[ n ], + `Cant "and" filter with another filter, them both have field ${n}` + ); + if( filter[ n ] === null && src[ n ] !== null ) + filter[ n ] = src[ n ]; + } + + /* */ + + filter.maskAll = _.RegexpObject.And( filter.maskAll, src.maskAll || null ); + filter.maskTerminal = _.RegexpObject.And( filter.maskTerminal, src.maskTerminal || null ); + filter.maskDirectory = _.RegexpObject.And( filter.maskDirectory, src.maskDirectory || null ); + filter.maskTransientAll = _.RegexpObject.And( filter.maskTransientAll, src.maskTransientAll || null ); + filter.maskTransientTerminal = _.RegexpObject.And( filter.maskTransientTerminal, src.maskTransientTerminal || null ); + filter.maskTransientDirectory = _.RegexpObject.And( filter.maskTransientDirectory, src.maskTransientDirectory || null ); + + return filter; +} + +// + +function _pathsAmmend( o ) +{ + let filter = this; + + if( _.arrayIs( o.src.length ) ) + { + for( let a = 0 ; a < o.src.length ; a++ ) + filter.pathsJoin({ src : o.src[ a ], joining : o.joining }); + return filter; + } + + _.routine.assertOptions( _pathsAmmend, arguments ); + _.assert( _.instanceIs( filter ) ); + _.assert( !filter.formed || filter.formed <= 1 ); + _.assert( !o.src.formed || o.src.formed <= 1 ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( filter.formedMasksMap === null ); + _.assert( filter.applyTo === null ); + _.assert( !filter.system || !o.src.system || filter.system === o.src.system ); + _.assert( o.src !== filter ); + + const fileProvider = filter.effectiveProvider + || filter.system + || filter.defaultProvider + || o.src.effectiveProvider + || o.src.system + || o.src.defaultProvider; + + const path = fileProvider.path; + + /* */ + + if( o.src.system ) + filter.system = o.src.system; + if( !( o.src instanceof Self ) ) + o.src = fileProvider.recordFilter( o.src ); + + /* fixes */ + + let dstFilePathArrayNonBool = filter.filePathArrayNonBoolGet(); + let srcFilePathArrayNonBool = o.src.filePathArrayNonBoolGet(); + let filePathDeducingFromFixes = !dstFilePathArrayNonBool.length && !srcFilePathArrayNonBool.length; + let booleanFallingBack; + if( filePathDeducingFromFixes ) + booleanFallingBack = true; + else + booleanFallingBack = false; + + filePathDeducingFromFixes = true; + booleanFallingBack = false; + + if( o.src.prefixPath && filter.prefixPath ) + { + let prefixPath = o.src.prefixPath; + o.src.prefixesApply({ filePathDeducingFromFixes, booleanFallingBack }); + filter.prefixesApply({ filePathDeducingFromFixes, booleanFallingBack }); + _.assert( !_.mapIs( filter.filePath ) || _.props.keys( filter.filePath ).length > 0 ); + } + + if( o.src.prefixPath && ( o.src.filePath || o.src.basePath ) ) + { + o.src.prefixesApply({ filePathDeducingFromFixes, booleanFallingBack }); + } + + if( filter.prefixPath && ( filter.filePath || filter.basePath ) ) + { + filter.prefixesApply({ filePathDeducingFromFixes, booleanFallingBack }); + } + + if( filter.prefixPath === '' ) + { + filter.prefixPath = null; + debugger; /* qqq : cover please */ + } + + if( filter.postfixPath === '' ) + { + filter.postfixPath = null; + debugger; /* qqq : cover please */ + } + + _.assert( o.src.prefixPath === '' || o.src.prefixPath === null || filter.prefixPath === null ); + _.assert( o.src.postfixPath === '' || o.src.postfixPath === null || filter.postfixPath === null ); + + if( o.src.prefixPath !== null ) + filter.prefixPath = o.src.prefixPath || null; + + if( o.src.postfixPath !== null ) + filter.postfixPath = o.src.postfixPath || null; + + /* base path */ + + let srcBaseMap; + let basePathReady = false; + if( o.src.basePath && filter.basePath ) + { + + srcBaseMap = o.src.basePath; + if( _.strIs( srcBaseMap ) ) + srcBaseMap = o.src.basePathMapFromString + ({ + filePath : o.src.filePath || {}, + basePath : srcBaseMap, + prefixingWithFilePath : 0, + booleanFallingBack, + }); + _.assert( _.mapIs( srcBaseMap ) || _.strIs( srcBaseMap ) ); + + if( _.strIs( filter.basePath ) ) + filter.basePath = filter.basePathMapFromString + ({ + filePath : filter.filePath || {}, + basePath : filter.basePath, + prefixingWithFilePath : 0, + booleanFallingBack, + }); + _.assert( _.mapIs( filter.basePath ) || _.strIs( filter.basePath ) ); + + if( o.joining ) + { + + if( path.isEmpty( filter.filePath ) && path.isEmpty( o.src.filePath ) ) + basePathSet(); + + } + else if( !o.joining ) + { + if( _.mapIs( filter.basePath ) && _.mapIs( srcBaseMap ) ) + { + if( o.supplementing ) + filter.basePath = _.props.supplement( filter.basePath, srcBaseMap ); + else + filter.basePath = _.props.extend( filter.basePath, srcBaseMap ); + } + else + { + + if( o.supplementing ) + filter.basePath = filter.basePath || srcBaseMap; + else + filter.basePath = srcBaseMap || filter.basePath; + + } + } + + } + else + { + basePathReady = true; + if( o.src.basePath === '' ) + filter.basePath = null; + else + filter.basePath = filter.basePath || o.src.basePath; + } + + /* file path */ + + let basePath2 = Object.create( null ); + + if( o.joining ) + { + + if( !_.mapIs( filter.filePath ) && !_.mapIs( o.src.filePath ) ) + { + if( filter.filePath || o.src.filePath ) + filter.filePath = path.filter( filter.filePath, ( dstFilePath ) => + { + return path.filter( o.src.filePath, ( srcFilePath ) => + { + return join( dstFilePath, srcFilePath ); + }); + }); + } + else + { + + let boolsMap = Object.create( null ); + let dstFilePath = path.filterPairs( filter.filePath, ( it1 ) => + { + _.assert( it1.dst !== null ); + if( !_.strIs( it1.dst ) ) + boolsMap[ it1.src ] = it1.dst; + else + return { [ it1.src ] : it1.dst } + }); + let srcFilePath = path.filterPairs( o.src.filePath, ( it2 ) => + { + _.assert( it2.dst !== null ); + if( !_.strIs( it2.dst ) ) + { + if( !o.supplementing || boolsMap[ it2.src ] === undefined ) + boolsMap[ it2.src ] = it2.dst; + } + else + return { [ it2.src ] : it2.dst } + }); + + let filePath = path.filterPairs( dstFilePath, ( it1 ) => + { + if( !_.strIs( it1.dst ) ) + return; + return path.filterPairs( srcFilePath, ( it2 ) => + { + if( !_.strIs( it2.dst ) ) + return; + let src = join( it1.src, it2.src, 'src' ); + let dst = join( it1.dst, it2.dst, 'dst' ); + return { [ src ] : dst }; + }); + }); + + if( filter.src ) + filter.src.filePath = filePath; + else + filter.filePath = filePath; + + if( Object.keys( boolsMap ).length ) + filter.filePath = path.mapExtend( filter.filePath, boolsMap ); + + } + + if( !basePathReady ) + { + basePathReady = true; + if( _.props.keys( basePath2 ).length === 0 && !filter.basePath ) + {} + else if( _.props.keys( basePath2 ).length === 1 && basePath2[ '' ] !== undefined ) + filter.basePath = basePath2[ '' ]; + else + filter.basePath = basePath2; + } + + } + else + { + + let isDst = !!filter.src || !!o.src.src; + + if( !filter.filePath || !o.src.filePath ) + { + filter.filePath = filter.filePath || o.src.filePath; + } + else if( ( _.mapIs( filter.filePath ) && _.mapIs( o.src.filePath ) ) || !isDst ) + { + if( o.supplementing ) + filter.filePath = path.mapSupplement( filter.filePath, o.src.filePath, null ); + else + filter.filePath = path.mapExtend( filter.filePath, o.src.filePath, null ); + } + else if( !_.mapIs( filter.filePath ) ) + { + _.assert( isDst ); + _.assert( _.mapIs( o.src.filePath ), 'not tested' ); /* qqq : cover it */ + if( o.supplementing ) + filter.filePath = path.mapSupplement( null, o.src.filePath, filter.filePath ); + else + filter.filePath = path.mapExtend( null, o.src.filePath, filter.filePath ); + } + + } + + /* */ + + return filter; + + /* */ + + function join( dstFilePath, srcFilePath, side ) + { + if( !side ) + side = filter.src ? 'dst' : 'src'; + let result; + + if( o.supplementing ) + result = path.join( srcFilePath, dstFilePath ); + else + result = path.join( dstFilePath, srcFilePath ); + + if( !basePathReady ) + if( side === ( filter.src ? 'dst' : 'src' ) ) + { + let dstBasePath = filter.basePathForStemPath( dstFilePath ); + let srcBasePath = o.src.basePathForStemPath( srcFilePath ); + if( srcBasePath || dstBasePath ) + if( o.supplementing ) + basePath2[ result ] = path.join( srcBasePath || '.', dstBasePath || '.' ); + else + basePath2[ result ] = path.join( dstBasePath || '.', srcBasePath || '.' ); + } + + return result; + } + + /* */ + + function basePathSet() + { + basePathReady = true; + if( !filter.basePath || !o.src.basePath ) + { + filter.basePath = filter.basePath || srcBaseMap; + } + else + { + let dstBasePath = filter.basePath; + let srcBasePath = o.src.basePath; + + filter.basePath = path.simplifyDst( filter.basePath ); + srcBaseMap = path.simplifyDst( srcBaseMap ); + + if( filter.basePath === '' ) + { + filter.basePath === srcBaseMap; + } + else if( _.mapIs( srcBaseMap ) || _.mapIs( filter.basePath ) ) + { + if( !_.mapIs( filter.basePath ) ) + filter.basePath = { '' : filter.basePath }; + if( !_.mapIs( srcBaseMap ) ) + srcBaseMap = { '' : srcBaseMap }; + + let baseMap2 = Object.create( null ); + if( o.supplementing ) + for( let filePath in filter.basePath ) + { + let basePath = filter.basePath[ filePath ]; + let basePath2 = srcBaseMap[ filePath ]; + if( !basePath2 ) + baseMap2[ filePath ] = basePath; + else + baseMap2[ filePath ] = path.join( basePath2, basePath ); + } + else + for( let filePath in srcBaseMap ) + { + let basePath = filter.basePath[ filePath ]; + let basePath2 = srcBaseMap[ filePath ]; + if( !basePath ) + baseMap2[ filePath ] = basePath2; + else + baseMap2[ filePath ] = path.join( basePath, basePath2 ); + } + + filter.basePath = path.simplifyDst( baseMap2 ); + if( filter.basePath === '' ) + filter.basePath = null; + } + else + { + + if( o.supplementing ) + filter.basePath = path.join( srcBaseMap, filter.basePath ); + else + filter.basePath = path.join( filter.basePath, srcBaseMap ); + + } + + } + + } + +} + +_pathsAmmend.defaults = +{ + src : null, + joining : 0, + supplementing : 0, +} + +// + +function pathsExtend( src ) +{ + let filter = this; + return filter._pathsAmmend + ({ + src, + joining : 0, + supplementing : 0, + }); +} + +// + +function pathsExtendJoining( src ) +{ + let filter = this; + return filter._pathsAmmend + ({ + src, + joining : 1, + supplementing : 0, + }); +} + +// + +function pathsSupplement( src ) +{ + let filter = this; + return filter._pathsAmmend + ({ + src, + joining : 0, + supplementing : 1, + }); +} + +// + +function pathsSupplementJoining( src ) +{ + let filter = this; + return filter._pathsAmmend + ({ + src, + joining : 1, + supplementing : 1, + }); +} + +// -- +// prefix path +// -- + +/** + * @descriptionNeeded + * @param {Object} o Options map. + * @param {Boolean} o.applyingToTrue=false + * @function prefixesApply + * @class wFileRecordFilter + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function prefixesApply( o ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filter.prefixPath === null && filter.postfixPath === null ) + return filter; + + let paired = filter.isPaired(); + let prefixArray = _.array.as( filter.prefixPath || '.' ); + let postfixArray = _.array.as( filter.postfixPath || '.' ); + + o = _.routine.options_( prefixesApply, arguments ); + _.assert( filter.prefixPath === null || _.strIs( filter.prefixPath ) || _.strsAreAll( filter.prefixPath ) ); + _.assert( filter.postfixPath === null || _.strIs( filter.postfixPath ) || _.strsAreAll( filter.postfixPath ) ); + _.assert( filter.postfixPath === null, 'not implemented' ); + + let dstArray = filter.filePathDstArrayGet(); + let regularPathHaving = dstArray.filter( ( e ) => !_.boolLike( e ) ).length; + if( o.booleanFallingBack ) + if( o.applyingToTrue === null ) + { + o.applyingToTrue = false; + if( filter.filePath ) + o.applyingToTrue = !regularPathHaving; + } + + /* */ + + let basePath2 = Object.create( null ); + + if( filter.filePath ) + filter.filePath = path.filterInplace( filter.filePath, filePathEach ); + + if( o.filePathDeducingFromFixes && !regularPathHaving ) + if( !o.applyingToTrue || !dstArray.length ) + filePathDeduceFromFixes(); + + basePathUpdate(); + + /* */ + + filter.prefixPath = null; + filter.postfixPath = null; + + if( !Config.debug ) + return filter; + + _.assert( !_.arrayIs( filter.basePath ) ); + _.assert( _.mapIs( filter.basePath ) || _.strIs( filter.basePath ) || filter.basePath === null ); + + if( filter.basePath && filter.filePath ) + filter.assertBasePath(); + + return filter; + + /* */ + + function basePathUpdate() + { + + if( _.props.keys( basePath2 ).length ) + { + for( let filePath in basePath2 ) + if( _.arrayIs( basePath2[ filePath ] ) ) + basePath2[ filePath ] = basePath2[ filePath ][ 0 ]; + + if( _.mapIs( filter.basePath ) ) + { + _.mapDelete( filter.basePath ); + _.props.extend( filter.basePath, basePath2 ); + } + else + { + filter.basePath = basePath2; + filter.basePath = filter.basePathSimplest(); + } + } + + } + + /* */ + + function filePathDeduceFromFixes() + { + let negatives = Object.create( null ); + if( _.mapIs( filter.filePath ) ) + for( let f in filter.filePath ) + if( _.boolLike( filter.filePath[ f ] ) && !filter.filePath[ f ] ) + negatives[ f ] = filter.filePath[ f ]; + prefixArray.forEach( ( prefixPath ) => + { + postfixArray.forEach( ( postfixPath ) => + { + let filePathFromPrefixes = path.join( prefixPath, postfixPath ); + let addedBase = basePathsForFilePaths( filePathFromPrefixes, prefixPath, postfixPath, filter.basePath ); + if( filter.src ) + filter.filePath = path.mapExtend( filter.filePath, { '' : filePathFromPrefixes } ); + else + filter.filePath = path.mapExtend( filter.filePath, filePathFromPrefixes ); + }); + }); + if( Object.keys( negatives ).length ) + { + for( let src in negatives ) + { + let dst = negatives[ src ]; + if( basePath2[ src ] ) + delete basePath2[ src ]; + filter.filePath[ src ] = dst; + } + } + filter.filePath = path.simplify( filter.filePath ); + } + + /* */ + + function filePathEach( element, it ) + { + + _.assert( it.value === null || _.strIs( it.value ) || _.boolLike( it.value ) || _.arrayIs( it.value ) ); + + if( filter.src ) + { + if( it.side === 'src' ) + return it.value; + } + else if( filter.dst || filter.src === null ) + { + if( it.side === 'dst' ) + { + if( o.applyingToTrue && _.boolLike( it.value ) && it.value ) + { + return ''; + } + return it.value; + } + } + + let value = it.value; + let result = []; + + if( it.side === 'dst' && _.strIs( it.value ) ) + it.value = path.fromGlob( it.value ); + + prefixArray.forEach( ( prefixPath ) => + { + postfixArray.forEach( ( postfixPath ) => + { + let currentValue = it.value; + + if( _.boolLike( it.value ) && it.side === 'dst' ) + if( !it.value || !o.applyingToTrue ) + { + result.push( !!it.value ); + return; + } + + if( it.value === null || it.value === '' || _.boolLike( it.value ) ) + { + currentValue = path.s.join( prefixPath, postfixPath ); + } + else + { + _.assert( _.strIs( it.value ) ); + currentValue = path.s.join( prefixPath, it.value, postfixPath ); + } + + _.arrayAppendOnce( result, currentValue ); + + if( !_.boolLike( it.dst ) || ( it.dst && o.applyingToTrue ) ) + { + if( _.mapIs( filter.basePath ) && _.strIs( value ) ) + { + let basePath = filter.basePath[ value ]; + if( basePath ) + { + _.assert( !!basePath, 'No base path for ' + value ); + delete filter.basePath[ value ]; + filter.basePath[ currentValue ] = basePath; + } + } + basePathsForFilePaths( currentValue, prefixPath, postfixPath, _.mapIs( filter.basePath ) ); + } + else if( !o.filePathDeducingFromFixes && _.mapIs( filter.basePath ) && _.strIs( value ) && filter.basePath[ value ] ) + { + let basePath = filter.basePath[ value ]; + delete filter.basePath[ value ]; + filter.basePath[ currentValue ] = basePath; + basePathsForFilePaths( currentValue, prefixPath, postfixPath, _.mapIs( filter.basePath ) ); + } + + }); + }); + + it.value = result; + return it.value; + } + + /* */ + + function basePathsForFilePaths( /* filePath, prefixPath, postfixPath, addingAnyway */ ) + { + let filePath = arguments[ 0 ]; + let prefixPath = arguments[ 1 ]; + let postfixPath = arguments[ 2 ]; + let addingAnyway = arguments[ 3 ]; + + _.assert( arguments.length === 4 ); + + if( _.arrayIs( filePath ) ) + { + let any = []; + filePath.forEach( ( filePath ) => any.push( basePathsForFilePaths( filePath, prefixPath, postfixPath, addingAnyway ) ) ); + return any.some( ( e ) => e ); + } + + _.assert( _.strIs( filePath ) ); + + let basePath = filter.basePathForStemPath( filePath ); + if( basePath ) + { + let extend = basePathEach( filePath, basePath, prefixPath, postfixPath ); + return true; + } + if( addingAnyway ) + { + let extend = basePathEach( filePath, path.fromGlob( filePath ), '.', '.' ); + return true; + } + + } + + /* */ + + function basePathEach( /* filePath, basePath, prefixPath, postfixPath */ ) + { + let filePath = arguments[ 0 ]; + let basePath = arguments[ 1 ]; + let prefixPath = arguments[ 2 ]; + let postfixPath = arguments[ 3 ]; + + _.assert( _.strIs( filePath ) ); + + let prefixPath2 = prefixPath; + if( prefixPath2 ) + prefixPath2 = path.s.fromGlob( prefixPath2 ); + + let postfixPath2 = postfixPath; + if( postfixPath2 ) + postfixPath2 = path.s.fromGlob( postfixPath2 ); + + let r = Object.create( null ); + + basePath = path.s.join( prefixPath2 || '.', basePath, postfixPath2 || '.' ); + + _.assert( !_.boolLike( filePath ) ); + + if( _.arrayIs( filePath ) ) + { + for( let f = 0 ; f < filePath.length ; f++ ) + r[ filePath[ f ] ] = basePath; + } + else + { + r[ filePath ] = basePath; + } + + path.mapSupplement( basePath2, r ); + + return r; + } + +} + +prefixesApply.defaults = +{ + filePathDeducingFromFixes : 1, + booleanFallingBack : 0, + applyingToTrue : null, +} + +// + +/** + * @descriptionNeeded + * @param {String} prefixPath + * @function prefixesRelative + * @class wFileRecordFilter + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function prefixesRelative( prefixPath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + prefixPath = prefixPath || filter.prefixPath; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( !prefixPath || filter.prefixPath === null || filter.prefixPath === prefixPath ); + + if( filter.filePath && !prefixPath ) + { + prefixPath = filter.prefixPathFromFilePath({ usingBools : 1 }); + } + + if( prefixPath ) + { + + if( filter.basePath ) + filter.basePath = path.filter( filter.basePath, relative_functor() ); + + if( filter.filePath ) + { + if( filter.src ) + filter.filePath = path.filterDstInplace( filter.filePath, relative_functor( 'dst' ) ); + else if( filter.dst ) + filter.filePath = path.filterSrcInplace( filter.filePath, relative_functor( 'src' ) ); + else + filter.filePath = path.filterInplace( filter.filePath, relative_functor() ); + } + + filter.prefixPath = prefixPath; + } + + return prefixPath; + + /* */ + + function relative_functor( side ) + { + return function relative( filePath, it ) + { + + if( !side || it.side === side || it.side === undefined ) + { + if( !_.strIs( filePath ) || filePath === '' ) + return filePath; + + // _.assert( path.isGlobal( prefixPath ) ^ path.isGlobal( filePath ) ^ true ); + // + // if( path.isAbsolute( prefixPath ) ^ path.isAbsolute( filePath ) ) + // return filePath; + + _.assert( path.isGlobal( prefixPath ) === path.isGlobal( filePath ) ); + + if( path.isAbsolute( prefixPath ) !== path.isAbsolute( filePath ) ) + return filePath; + + return path.relative( prefixPath, filePath ); + } + + return filePath; + } + } + +} + +// + +function prefixPathFromFilePath( o ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + _.routine.options_( prefixPathFromFilePath, arguments ); + + if( o.filePath === null ) + o.filePath = filter.filePath; + + let result = o.filePath || filter.filePath; + + if( result === null || result === '' ) + return null; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( !!result ); + + if( o.usingBools ) + result = filter.filePathArrayGet( result ); + else + result = filter.filePathArrayNonBoolGet( result, 1 ); + + if( result ) + { + result = result.filter( ( filePath ) => _.strIs( filePath ) && filePath ); + if( path.s.anyAreAbsolute( result ) ) + result = result.filter( ( filePath ) => path.isAbsolute( filePath ) ); + } + + if( result && result.length ) + { + result = path.fromGlob( path.detrail( path.common( result ) ) ); + } + else + { + result = null; + } + + return result; +} + +prefixPathFromFilePath.defaults = +{ + filePath : null, + usingBools : 1, /* zzz : default to false */ +} + +// + +function prefixPathAbsoluteFrom( o ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + o = _.routine.options_( prefixPathAbsoluteFrom, arguments ); + + if( o.filePath === null ) + o.filePath = filter.filePath; + if( o.basePath === null ) + o.basePath = filter.basePath; + + let result = o.filePath || filter.filePath; + + if( result === null || result === '' ) + return null; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( !!result ); + + if( o.usingBools ) + result = filter.filePathArrayGet( result ); + else + result = filter.filePathArrayNonBoolGet( result, 1 ); + + result = result.filter( ( filePath ) => _.strIs( filePath ) && filePath ); + result = result.filter( ( filePath ) => path.isAbsolute( filePath ) ); + + if( result && result.length ) + { + result = path.common( result ); + } + else if( o.basePath ) + { + + result = o.basePath; + + if( _.mapIs( result ) ) + { + result = _.props.vals( result ); + } + else + { + result = [ o.basePath ]; + } + + result = result.filter( ( filePath ) => path.isAbsolute( filePath ) ); + + if( result && result.length ) + { + result = path.common( result ); + } + else + { + result = null; + } + + _.assert( result === null || _.strIs( result ) ); + } + else result = null; + + if( _.strIs( result ) ) + result = path.fromGlob( path.detrail( result ) ); + + _.assert( result === null || path.isAbsolute( result ) ); + + return result; +} + +prefixPathAbsoluteFrom.defaults = +{ + filePath : null, + basePath : null, + usingBools : 0, +} + +// -- +// base path +// -- + +/** + * @summary Returns relative path for provided path `filePath`. + * @function relativeFor + * @class wFileRecordFilter + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function relativeFor( filePath ) +{ + let filter = this; + let basePath = filter.basePathForStemPath( filePath ); + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + relativePath = path.relative( basePath, filePath ); + + return relativePath; +} + +// + +function basePathSet( src ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + + _.assert + ( + src === null || _.strIs( src ) || _.mapIs( src ), + () => 'Base path can be null, string or map, but not ' + _.entity.strType( src ) + ) + + if( 0 ) + if( Config.debug ) + if( src && fileProvider ) + { + const path = fileProvider.path; + path.filter( src, ( basePath, it ) => + { + if( it.side === 'src' ) + return; + _.assert( !path.isGlob( basePath ), () => 'Base path should be non-glob, but ' + _.strQuote( basePath ) + ' is glob' ); + }); + } + + if( _.mapIs( src ) ) + src = _.props.extend( null, src ); + + return filter[ basePathSymbol ] = src; +} + +// + +/** + * @summary Returns base path for provided path `filePath`. + * @param {String|Boolean} filePath Source file path. + * @function basePathForStemPath + * @class wFileRecordFilter + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function basePathForStemPath( filePath ) +{ + let filter = this; + let result = null; + + _.assert( _.strIs( filePath ), 'Expects string' ); + _.assert( arguments.length === 1 ); + + if( !filter.basePath ) + return; + + if( _.strIs( filter.basePath ) ) + return filter.basePath; + + if( _.boolLike( filePath ) ) + { + if( _.strIs( filter.basePath ) ) + return filter.basePath; + _.assert( _.mapIs( filter.basePath ) && _.props.keys( filter.basePath ).length === 1 ); + return _.props.vals( filter.basePath )[ 0 ]; + } + + _.assert( _.mapIs( filter.basePath ) ); + + result = filter.basePath[ filePath ]; + + return result; +} + +// + +/** + * @summary Returns base path for provided path `filePath`. + * @param {String|Boolean} filePath Source file path. + * @function basePathForFilePath + * @class wFileRecordFilter + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function basePathForFilePath( filePath ) +{ + let filter = this; + let result = null; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + _.assert( _.strIs( filePath ), 'Expects string' ); + _.assert( arguments.length === 1 ); + + if( !filter.basePath ) + return; + + if( _.boolLike( filePath ) ) + { + if( _.strIs( filter.basePath ) ) + return filter.basePath; + _.assert( _.mapIs( filter.basePath ) && _.props.keys( filter.basePath ).length === 1 ); + return _.props.vals( filter.basePath )[ 0 ]; + } + + _.assert( _.strIs( filePath ), 'Expects string' ); + _.assert( arguments.length === 1 ); + + if( _.strIs( filter.basePath ) ) + return filter.basePath; + + _.assert( _.mapIs( filter.basePath ) ); + + result = filter.basePath[ filePath ]; + + if( result ) + return result; + + let basePath = _.props.extend( null, filter.basePath ); + for( let f in basePath ) + { + let b = basePath[ f ]; + delete basePath[ f ]; + basePath[ path.fromGlob( f ) ] = b; + } + + result = basePath[ filePath ]; + + if( !result && !_.strBegins( filePath, '..' ) && !_.strBegins( filePath, '/..' ) ) + { + + let filePath2 = path.join( filePath, '..' ); + while( filePath2 !== '..' && filePath2 !== '/..' ) + { + result = basePath[ filePath2 ]; + if( result ) + break; + filePath2 = path.join( filePath2, '..' ); + } + + } + + return result; +} + +// + +function basePathsGet() +{ + let filter = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( filter.basePath === null || _.strIs( filter.basePath ) || _.mapIs( filter.basePath ) ); + + if( _.object.isBasic( filter.basePath ) ) + return _./*longOnce*/arrayAppendArrayOnce( null, _.props.vals( filter.basePath ) ) + else if( _.strIs( filter.basePath ) ) + return [ filter.basePath ]; + else + return []; +} + +// + +function basePathMapFromString( o ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + o = _.routine.options_( basePathMapFromString, arguments ); + _.assert( o.basePath === null || _.strIs( o.basePath ) ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( o.basePath === null ) + o.basePath = filter.basePath + if( o.filePath === null ) + o.filePath = filter.prefixPath || filter.filePath; + + o.filePath = filter.filePathArrayNonBoolGet( o.filePath, o.booleanFallingBack ).filter( ( e ) => _.strIs( e ) && e ); + + let basePath2 = Object.create( null ); + + if( o.basePath ) + { + for( let s = 0 ; s < o.filePath.length ; s++ ) + { + let thisFilePath = o.filePath[ s ]; + if( o.prefixingWithFilePath && path.isRelative( o.basePath ) ) + basePath2[ thisFilePath ] = path.detrail( path.join( path.fromGlob( thisFilePath ), o.basePath ) ); + else + basePath2[ thisFilePath ] = o.basePath; + } + } + else if( !o.optimal ) + { + for( let s = 0 ; s < o.filePath.length ; s++ ) + { + let thisFilePath = o.filePath[ s ]; + basePath2[ thisFilePath ] = path.fromGlob( thisFilePath ); + } + } + else + { + let pairs = o.filePath.map( ( fileGlob ) => + { + let filePath = path.fromGlob( fileGlob ); + if( path.hasSymbolBase( fileGlob ) ) + return [ filePath, fileGlob, fileGlob ]; + else + return [ filePath, filePath, fileGlob ]; + }); + pairs.sort( ( a, b ) => + { + if( a[ 1 ] === b[ 1 ] ) + return 0; + else if( a[ 1 ] < b[ 1 ] ) + return -1; + else + return +1; + }); + for( let s1 = 0 ; s1 < pairs.length ; s1++ ) + { + let fileGlob1 = pairs[ s1 ][ 2 ]; + let filePath1 = pairs[ s1 ][ 1 ]; + basePath2[ fileGlob1 ] = pairs[ s1 ][ 0 ]; + for( let s2 = s1+1 ; s2 < pairs.length ; s2++ ) + { + let fileGlob2 = pairs[ s2 ][ 2 ]; + let filePath2 = pairs[ s2 ][ 1 ]; + if( !path.begins( filePath2, filePath1 ) ) + break; + basePath2[ fileGlob2 ] = pairs[ s1 ][ 0 ]; + pairs.splice( s2, 1 ); + s2 -= 1; + } + } + } + + if( !o.basePath || _.props.keys( basePath2 ).length ) + return basePath2; + else + return o.basePath; +} + +basePathMapFromString.defaults = +{ + filePath : null, + basePath : null, + booleanFallingBack : 1, + prefixingWithFilePath : 0, + optimal : 1, +} + +// + +function basePathMapLocalize( basePathMap ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + let basePathMap2 = Object.create( null ); + basePathMap = basePathMap || filter.basePath; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + for( let filePath in basePathMap ) + { + let basePath = basePathMap[ filePath ]; + _.assert( _.strIs( basePath ) ); + _.assert( _.strIs( filePath ) ); + _.assert( !path.isGlob( basePath ), () => 'Base path should be not glob, but ' + _.strQuote( basePath ) ); + filePath = filter.pathLocalize( filePath ); + basePath = filter.pathLocalize( basePath ); + basePathMap2[ filePath ] = basePath; + } + + return basePathMap2; +} + +// + +function basePathFromDecoratedFilePath( filePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + let basePath = Object.create( null ); + + if( filePath === undefined ) + filePath = filter.filePath; + + /* */ + + path.filterPairs( filePath, ( it ) => + { + + if( filter.src ) + { + if( !_.strIs( it.dst ) ) + return; + if( !_.strHas( it.dst, '()' ) && !_.strHas( it.dst, '\0' ) ) + return; + basePath[ path.undot( path.canonize( it.dst ) ) ] = path.fromGlob( it.dst ); + } + else + { + if( !_.strIs( it.src ) ) + return; + if( !_.strHas( it.src, '()' ) && !_.strHas( it.src, '\0' ) ) + return; + basePath[ path.undot( path.canonize( it.src ) ) ] = path.fromGlob( it.src ); + } + + }); + + return basePath; +} + +// + +function basePathNormalize( filePath, basePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + if( basePath === undefined ) + basePath = filter.basePath; + + _.assert( !_.arrayIs( basePath ) ); + _.assert( arguments.length === 0 || arguments.length === 2 ); + + /* */ + + if( basePath === null || _.strIs( basePath ) ) + { + if( basePath ) + basePath = filter.pathLocalize( basePath ); + basePath = filter.basePathMapFromString + ({ + filePath, + basePath, + prefixingWithFilePath : 1, + }); + } + else if( _.mapIs( basePath ) ) + { + basePath = filter.basePathMapLocalize( basePath ); + } + else _.assert( 0 ); + + _.assert + ( + basePath === null + || _.mapIs( basePath ) + || filter.filePathArrayNonBoolGet( filePath, 1 ).filter( ( e ) => e !== null ).length === 0 + ); + + return basePath; +} + +// + +function basePathSimplest( basePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( basePath === undefined ) + basePath = filter.basePath; + + if( !basePath || _.strIs( basePath ) ) + return basePath; + + let vals = _.arrayAppendArrayOnce( [], _.props.vals( basePath ) ); + + if( vals.length !== 1 ) + return basePath; + else if( vals.length === 0 ) + return null; + + basePath = vals[ 0 ]; + + return basePath; +} + +// + +/* zzz : remove maybe? */ + +function basePathDotUnwrap() +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( !filter.basePath ) + return; + + if( _.strIs( filter.basePath ) && filter.basePath !== '.' ) + return; + + if( _.mapIs( filter.basePath ) && !_.map.identical( filter.basePath, { '.' : '.' } ) ) + return; + + debugger; + let filePath = filter.filePathArrayNonBoolGet(); /* zzz : booleanFallingBack? */ + + let basePath = _.mapIs( filter.basePath ) ? filter.basePath : Object.create( null ); + delete basePath[ '.' ]; + filter.basePath = basePath; + + filePath.forEach( ( fp ) => basePath[ fp ] = fp ); + +} + +// + +function basePathEach( onEach ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + _.assert( filter.basePath === null || _.strIs( filter.basePath ) || _.mapIs( filter.basePath ) ); + _.assert( arguments.length === 1 ); + + /* + don't use file path neither prefix path instead of base path here + */ + + let basePath = filter.basePath; + + basePath = path.filterPairs( basePath, handleEach ); + + return basePath; + + function handleEach( it ) + { + if( _.mapIs( basePath ) ) + { + return onEach( it.src, it.dst ); + } + else + { + _.assert( it.dst === '' ); + return onEach( it.dst, it.src ); + } + } + +} + +// + +function basePathUse( basePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + _.assert( arguments.length === 1 ); + + filter = fileProvider.recordFilter( filter ); + + if( filter.basePath || basePath ) + filter.basePath = path.join( basePath || '.', filter.basePath || '.' ); + + if( basePath ) + filter.prefixPath = path.s.join( basePath, filter.prefixPath || '.' ) + + filter.prefixesApply(); + + if( !filter.basePath ) + filter.basePath = filter.basePathMapFromString(); + filter.basePath = filter.basePath || path.current(); + filter.prefixPath = path.current(); + filter.prefixesApply(); + + basePath = path.resolve( basePath || filter.basePaths[ 0 ] ); + + return basePath; +} + +// -- +// file path +// -- + +function filePathMove( o ) +{ + + _.routine.assertOptions( filePathMove, arguments ); + + /* get */ + + if( o.value === null ) + if( _.instanceIs( o.srcInstance ) ) + { + o.value = o.srcInstance[ filePathSymbol ]; + } + else if( o.srcInstance ) + { + debugger; + o.value = o.srcInstance.filePath; + } + + if( o.srcInstance && o.dstInstance ) + { + o.value = _.entity.make( o.value ); + } + + /* set */ + + if( _.instanceIs( o.dstInstance ) ) + { + + _.assert( o.value === null || _.strIs( o.value ) || _.arrayIs( o.value ) || _.mapIs( o.value ) ); + + if( _.object.isBasic( o.dstInstance.src ) ) + { + const fileProvider = o.dstInstance.system || o.dstInstance.effectiveProvider || o.dstInstance.defaultProvider; + const path = fileProvider.path; + if( _.strIs( o.value ) || _.arrayIs( o.value ) || _.boolLike( o.value ) ) + o.value = path.mapsPair( o.value, null ); + _.assert( o.value === null || _.mapIs( o.value ), () => 'Paired filter could have only path map as file path, not ' + _.entity.strType( o.value ) ); + if( o.dstInstance.src[ filePathSymbol ] !== o.value ) + { + _.assert( o.dstInstance.src.formed < 5, 'Paired source filter is formed and cant be modified' ); + o.dstInstance.src[ filePathSymbol ] = o.value; + } + } + else if( _.object.isBasic( o.dstInstance.dst ) ) + { + const fileProvider = o.dstInstance.system || o.dstInstance.effectiveProvider || o.dstInstance.defaultProvider; + const path = fileProvider.path; + if( _.strIs( o.value ) || _.arrayIs( o.value ) || _.boolLike( o.value ) ) + o.value = path.mapsPair( null, o.value ); + _.assert( o.value === null || _.mapIs( o.value ), () => 'Paired filter could have only path map as file path, not ' + _.entity.strType( o.value ) ); + if( o.dstInstance.dst[ filePathSymbol ] !== o.value ) + { + _.assert( o.dstInstance.dst.formed < 5, 'Paired destination filter is formed and cant be modified' ); + o.dstInstance.dst[ filePathSymbol ] = o.value; + } + } + + o.dstInstance[ filePathSymbol ] = o.value; + } + else if( o.dstInstance ) + { + debugger; + o.dstInstance.filePath = o.value; + } + + /* */ + + return o; +} + +filePathMove.defaults = +{ + ... _.accessor._moveItMake.defaults, +} + +// + +/** + * @descriptionNeeded + * @param {String} srcPath + * @param {String} dstPath + * @function filePathSelect + * @class wFileRecordFilter + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function filePathSelect( srcPath, dstPath ) +{ + let src = this; + let dst = src.dst; + const fileProvider = src.system || src.effectiveProvider || src.defaultProvider; + const path = fileProvider.path; + + _.assert( arguments.length === 2 ); + _.assert( _.mapIs( srcPath ) ); + _.assert( _.strIs( dstPath ) ); + + let filePath = path.mapExtend( null, srcPath, dstPath ); + + if( dst ) + try + { + + if( _.mapIs( dst.basePath ) ) + for( let dstPath2 in dst.basePath ) + { + if( dstPath !== dstPath2 ) + { + _.assert( _.strIs( dst.basePath[ dstPath2 ] ), () => 'No base path for ' + dstPath2 ); + delete dst.basePath[ dstPath2 ]; + } + } + + dst.filePath = filePath; + dst._formPaths(); + dstPath = dst.filePathSimplest(); + _.assert( _.strIs( dstPath ) ); + filePath = dst.filePath; + } + catch( err ) + { + debugger; + throw _.err( 'Failed to form destination filter\n', err ); + } + + try + { + + if( _.mapIs( src.basePath ) ) + for( let srcPath2 in src.basePath ) + { + if( filePath[ srcPath2 ] === undefined ) + { + _.assert( _.strIs( src.basePath[ srcPath2 ] ), () => 'No base path for ' + srcPath2 ); + delete src.basePath[ srcPath2 ]; + } + } + + src.filePath = filePath; + _.assert( dst === null || src.filePath === dst.filePath ); + src._formPaths(); + _.assert( dst === null || src.filePath === dst.filePath ); + } + catch( err ) + { + debugger; + throw _.err( 'Failed to form source filter\n', err ); + } + +} + +// + +function filePathNormalize( filePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + _.assert( arguments.length === 1 ); + + if( !_.mapIs( filePath ) ) + filePath = path.mapExtend( null, filePath ); + + filePath = path.filterPairsInplace( filePath, ( it ) => + { + if( filter.src ) + { + if( !_.boolLike( it.dst ) ) + { + it.dst = path.normalize( it.dst ); + it.dst = filter.pathLocalize( it.dst ); + } + } + else + { + it.src = path.normalize( it.src ); + it.src = filter.pathLocalize( it.src ); + // it.src = path.globNormalize( it.src ); + } + return { [ it.src ] : it.dst } + }); + + _.assert( _.mapIs( filePath ) ); + + return filePath; +} + +// + +function filePathPrependByBasePath( filePath, basePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + _.assert( arguments.length === 2 ); + _.assert( _.mapIs( filePath ) ); + _.assert( _.mapIs( basePath ) || basePath === null ); + + if( basePath === null ) + return; + + if( filter.src ) + { + debugger; + + for( let srcPath in filePath ) + { + + let dstPath = filePath[ srcPath ]; + let b = basePath[ dstPath ]; + + if( path.isAbsolute( dstPath ) ) + continue; + if( !b ) + continue; + if( !path.isAbsolute( b ) ) + continue; + + _.assert( path.isAbsolute( b ) ); + + let joinedPath = path.join( b, dstPath ); + if( joinedPath !== dstPath ) + { + delete basePath[ dstPath ]; + basePath[ joinedPath ] = b; + delete filePath[ srcPath ]; + path.mapExtend( filePath, srcPath, joinedPath ); + } + + } + + debugger; + } + else + { + + for( let srcPath in filePath ) + { + + let dstPath = filePath[ srcPath ]; + let b = basePath[ srcPath ]; + + if( path.isAbsolute( srcPath ) ) + continue; + if( !b ) + continue; + if( !path.isAbsolute( b ) ) + continue; + + _.assert( path.isAbsolute( b ) ); + + let joinedPath = path.join( b, srcPath ); + if( joinedPath !== srcPath ) + { + delete basePath[ srcPath ]; + basePath[ joinedPath ] = b; + delete filePath[ srcPath ]; + path.mapExtend( filePath, joinedPath, dstPath ); + } + + } + + } + +} + +// + +function filePathMultiplyRelatives( filePath, basePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + _.assert( arguments.length === 2 ); + _.assert( _.mapIs( filePath ) ); + _.assert( _.mapIs( basePath ) ); + + let relativePath = _.props.extend( null, filePath ); + + for( let r in relativePath ) + if( path.isRelative( r ) ) + { + delete basePath[ r ]; + delete filePath[ r ]; + } + else + { + delete relativePath[ r ]; + } + + let basePath2 = _.props.extend( null, basePath ); + + for( let b in basePath2 ) + { + let currentBasePath = basePath[ b ]; + let normalizedFilePath = path.fromGlob( b ); + for( let r in relativePath ) + { + let dstPath = relativePath[ r ]; + let srcPath = path.join( normalizedFilePath, r ); + _.assert( filePath[ srcPath ] === undefined || filePath[ srcPath ] === dstPath ); + filePath[ srcPath ] = dstPath; + _.assert( basePath[ srcPath ] === undefined || basePath[ srcPath ] === currentBasePath ); + if( !_.boolLike( dstPath ) ) + basePath[ srcPath ] = currentBasePath; + } + } + +} + +// + +function filePathFromBasePath( basePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + let result = Object.create( null ); + + _.assert( basePath === '' || basePath === null || _.mapIs( basePath ) || _.strIs( basePath ) ); + + if( !basePath ) + return result; + + if( _.strIs( basePath ) ) + { + if( filter.src ) + result[ '' ] = basePath; + else + result[ basePath ] = ''; + } + else + { + if( filter.src ) + { + for( let f in basePath ) + result[ '' ] = _.scalarAppend( result[ '' ], f ); + } + else + { + for( let f in basePath ) + result[ f ] = ''; + } + } + + return result; +} + +// + +function filePathAbsolutize( prefixPath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + _.assert( _.mapIs( filter.filePath ) ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( !prefixPath || path.isAbsolute( prefixPath ) ) + + if( prefixPath ) + { + if( filter.prefixPath ) + filter.prefixesApply({ applyingToTrue : 0, filePathDeducingFromFixes : 0 }); + filter.prefixPath = prefixPath; + filter.prefixesApply({ applyingToTrue : 0, filePathDeducingFromFixes : 0 }); + return; + } + + if( _.props.keys( filter.filePath ).length === 0 ) + return; + + let filePath = filter.filePathArrayGet().filter( ( e ) => _.strIs( e ) && e ); + + if( path.s.anyAreRelative( filePath ) ) + { + if( path.s.anyAreAbsolute( filePath ) ) + filter.filePathMultiplyRelatives( filter.filePath, filter.basePath ); + else + filter.filePathPrependByBasePath( filter.filePath, filter.basePath ); + } + +} + +// + +/* +Easy optimization. No need to enable slower glob searching if glob is "**". +Result of such glob is equivalent to result of recursive searching. +*/ + +function filePathGlobSimplify( filePath, basePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + if( basePath === undefined ) + basePath = filter.basePath; + + _.assert( arguments.length === 0 || arguments.length === 2 ); + _.assert( _.mapIs( filePath ) ); + _.assert( !filter.src, 'Not applicable to destination filter, only to source filter' ); + + /**/ + + let dst = filter.filePathDstArrayGet(); + + if( _.any( dst, ( e ) => _.boolLike( e ) ) ) + return filePath + + for( let src in filePath ) + { + if( _.strEnds( src, '/**' ) || src === '**' ) + simplify( src, '**' ) + } + + return filePath; + + /* */ + + function simplify( src, what ) + { + let src2 = path.canonize( _.strRemoveEnd( src, what ) ); + if( !path.isGlob( src2 ) ) + { + _.assert( filePath[ src2 ] === undefined ) + filePath[ src2 ] = filePath[ src ]; + delete filePath[ src ]; + + if( _.mapIs( basePath ) ) + { + _.assert( basePath[ src2 ] === undefined || basePath[ src2 ] === basePath[ src ], () => 'Base path for file path ' + _.strQuote( src2 ) + ' is already defined and has value ' + _.strQuote( basePath[ src2 ] ) ); + _.assert( basePath[ src ] !== undefined, () => 'No base path for file path ' + _.strQuote( src ) ); + basePath[ src2 ] = basePath[ src ]; + delete basePath[ src ]; + } + + } + } + +} + +// + +function filePathFromFixes() +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( !filter.filePath ) + { + filter.filePath = path.s.join( filter.prefixPath || '.', filter.postfixPath || '.' ); + _.assert( path.s.allAreAbsolute( filter.filePath ), 'Can deduce file path' ); + } + + return filter.filePath; +} + +// + +function filePathSimplest( filePath ) +{ + let filter = this; + + filePath = filePath || filter.filePathArrayNonBoolGet(); + + _.assert( !_.mapIs( filePath ) ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( _.arrayIs( filePath ) && filePath.length === 1 ) + return filePath[ 0 ]; + + if( _.arrayIs( filePath ) && filePath.length === 0 ) + return null; + + return filePath; +} + +// + +function filePathNullizeMaybe( filePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + let filePath2 = filter.filePathDstArrayGet( filePath ); + if( _.any( filePath2, ( e ) => !_.boolLike( e ) ) ) + return filePath; + + return path.filterInplace( filePath, ( e ) => _.boolLike( e ) && e ? '' : e ); +} + +// + +function filePathIsComplex( filePath ) +{ + let filter = this; + const fileProvider = filter.effectiveProvider || filter.system || filter.defaultProvider; + const path = fileProvider.path; + + /* + should use effectiveProvider because of option globbing of file provider + */ + + if( filePath === undefined ) + filePath = filter.filePath; + + if( filePath === '' || filePath === null ) + return false; + + let globFound = true; + if( _.none( path.s.areGlob( filePath ) ) ) + if( !filter.filePathDstArrayGet( filePath ).filter( ( e ) => _.boolLike( e ) ).length ) + globFound = false; + + return globFound; +} + +// + +function filePathHasGlob( filePath ) +{ + let filter = this; + const fileProvider = filter.effectiveProvider || filter.system || filter.defaultProvider; + const path = fileProvider.path; + + /* + should use effectiveProvider because of option globbing of file provider + */ + + if( filePath === undefined ) + { + filePath = filter.filePath; + if( filePath === null ) + filePath = filter.prefixPath; + } + + if( filePath === '' || filePath === null ) + return false; + + let globFound = true; + if( _.none( path.s.areGlob( filePath ) ) ) + globFound = false; + + return globFound; +} + +// + +function filePathDstHasAllBools( filePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + filePath = filter.filePathDstArrayGet( filePath ); + + if( !filePath.length ) + return true; + + return !filePath.filter( ( e ) => !_.boolLike( e ) ).length; +} + +// + +function filePathDstHasAnyBools( filePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + filePath = filter.filePathDstArrayGet( filePath ); + + return !!filePath.filter( ( e ) => _.boolLike( e ) ).length; +} + +// + +function filePathMapOnlyBools( filePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + if( filePath === null || _.strIs( filePath ) || _.arrayIs( filePath ) ) + return {}; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.mapIs( filePath ) ); + + let result = Object.create( null ); + for( let src in filePath ) + { + if( _.boolLike( filePath[ src ] ) ) + result[ src ] = filePath[ src ]; + } + + return result; +} + +// + +function filePathMap( filePath, booleanFallingBack ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + if( filter.src ) + filePath = path.mapsPair( null, filePath ); + else + filePath = path.mapsPair( filePath, null ); + + if( !booleanFallingBack ) + return filePath; + + if( !filter.filePathDstHasAllBools( filePath ) ) + return filePath; + + for( let src in filePath ) + { + if( _.boolLike( filePath[ src ] ) && filePath[ src ] ) + filePath[ src ] = ''; + } + + return filePath; +} + +// + +function filePathDstArrayGet( filePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + if( filePath === null ) + return []; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( filter.src ) + { + return path.mapDstFromDst( filePath ); + } + else + { + return path.mapDstFromSrc( filePath ); + } + + _.assert( _.arrayIs( filePath ) ); + + return filePath; +} + +// + +function filePathSrcArrayGet( filePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + if( filePath === null ) + return []; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( filter.src ) + { + return path.mapSrcFromDst( filePath ); + } + else + { + return path.mapSrcFromSrc( filePath ); + } + + _.assert( _.arrayIs( filePath ) ); + + return filePath; +} + +// + +function filePathArrayGet( filePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + if( filePath === null ) + return []; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( filter.src ) + { + filePath = path.mapDstFromDst( filePath ); + } + else + { + filePath = path.mapSrcFromSrc( filePath ); + } + + _.assert( _.arrayIs( filePath ) ); + + return filePath; +} + +// + +function filePathDstArrayNonBoolGet( filePath, booleanFallingBack ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + if( booleanFallingBack === undefined ) + booleanFallingBack = false; + + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + + if( filter.src ) + { + filePath = path.mapDstFromDst( filePath ); + } + else + { + filePath = path.mapDstFromSrc( filePath ); + } + + let filePath2 = filePath.filter( ( e ) => !_.boolLike( e ) ); + if( filePath2.length || !booleanFallingBack ) + { + filePath = filePath2; + } + else + { + filePath = _.filter_( null, filePath, ( e ) => + { + if( !_.boolLike( e ) ) + return e; + if( e ) + return null; + return undefined; + }); + } + + _.assert( _.arrayIs( filePath ) ); + + return filePath; +} + +// + +function filePathSrcArrayNonBoolGet( filePath, booleanFallingBack ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + if( booleanFallingBack === undefined ) + booleanFallingBack = false; + + if( filePath === null ) + return []; + + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + + if( _.mapIs( filePath ) ) + { + let r = []; + for( let src in filePath ) + { + if( _.boolLike( filePath[ src ] ) ) + continue; + r.push( src ); + } + if( !r.length && booleanFallingBack ) + { + for( let src in filePath ) + { + if( !filePath[ src ] ) + continue; + r.push( src ); + } + } + filePath = r; + } + else + { + if( filter.src ) + { + filePath = path.mapSrcFromDst( filePath ); + } + else + { + filePath = path.mapSrcFromSrc( filePath ); + } + } + + _.assert( _.arrayIs( filePath ) ); + _.longOnce( filePath ); + + return filePath; +} + +// + +function filePathArrayNonBoolGet( filePath, booleanFallingBack ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + if( filePath === null ) + return []; + + _.assert( arguments.length === 0 || arguments.length === 1 || arguments.length === 2 ); + + if( filter.src ) + return filter.filePathDstArrayNonBoolGet( filePath, booleanFallingBack ); + else + return filter.filePathSrcArrayNonBoolGet( filePath, booleanFallingBack ); + +} + +// + +function filePathDstArrayBoolGet( filePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( filter.src ) + { + filePath = path.mapDstFromDst( filePath ); + } + else + { + filePath = path.mapDstFromSrc( filePath ); + } + + let filePath2 = _.filter_( null, filePath, ( e ) => _.boolLike( e ) ? !!e : undefined ); + filePath = _./*longOnce*/arrayAppendArrayOnce( null, filePath2 ); + + _.assert( _.arrayIs( filePath ) ); + + return filePath; +} + +// + +function filePathSrcArrayBoolGet( filePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + if( filePath === null ) + return []; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( _.mapIs( filePath ) ) + { + let r = []; + + for( let src in filePath ) + { + if( !_.boolLike( filePath[ src ] ) ) + continue; + r.push( src ); + } + + filePath = r; + + } + else + { + filePath = []; + } + + _.assert( _.arrayIs( filePath ) ); + + return filePath; +} + +// + +function filePathArrayBoolGet( filePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + if( filePath === null ) + return []; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( filter.src ) + { + return filter.filePathDstArrayBoolGet( filePath ); + } + else + { + return filter.filePathSrcArrayBoolGet( filePath ); + } + +} + +// + +function filePathDstNormalizedGet( filePath ) +{ + let filter = this; + let dstFilter = filter.dst || filter; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + _.assert( filePath !== undefined ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + + /* zzz : use non-inplace version */ + let result = []; + filePath = _.entity.cloneShallow( filePath ); + filePath = path.filterPairsInplace( filePath, ( it ) => + { + if( _.boolLike( it.dst ) ) + return; + if( !it.dst ) + return; + _.assert( _.strIs( it.src ) ); + result.push( it.dst ); + }); + + result = _.longOnce( result ); + + if( dstFilter.prefixPath || dstFilter.postfixPath ) + result = path.s.join( dstFilter.prefixPath || '.', result, dstFilter.postfixPath || '.' ); + + return result; +} + +// + +function filePathSrcNormalizedGet( filePath ) +{ + let filter = this; + let srcFilter = filter.src || filter; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + + _.assert( filePath !== undefined ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + + /* zzz : use non-inplace version */ + let result = []; + filePath = _.entity.cloneShallow( filePath ); + filePath = path.filterPairsInplace( filePath, ( it ) => + { + if( _.boolLike( it.dst ) ) + return; + _.assert( _.strIs( it.src ) ); + result.push( it.src ); + }); + + result = _.longOnce( result ); + + if( srcFilter.prefixPath || srcFilter.postfixPath ) + result = path.s.join( srcFilter.prefixPath || '.', result, srcFilter.postfixPath || '.' ); + + return result +} + +// + +function filePathNormalizedGet( filePath ) +{ + let filter = this; + if( filter.src ) + return filter.filePathDstNormalizedGet( filePath ); + else + return filter.filePathSrcNormalizedGet( filePath ); +} + +// + +function filePathCommon( filePath ) +{ + let filter = this; + if( filter.src ) + return filter.filePathDstCommon( filePath ); + else + return filter.filePathSrcCommon( filePath ); +} + +// + +function filePathDstCommon() +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + let filePath = filter.filePathDstNormalizedGet(); + + return path.common.apply( path, filePath ); +} + +// + +function filePathSrcCommon() +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + let filePath = filter.filePathSrcNormalizedGet(); + + return path.common.apply( path, filePath ); +} + +// -- +// pair +// -- + +function pairedFilterGet() +{ + let filter = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + if( filter.src ) + return filter.src + else + return filter.dst; +} + +// + +function pairWithDst( dst ) +{ + let filter = this; + + _.assert( dst instanceof Self ); + _.assert( filter instanceof Self ); + _.assert( filter.dst === null || filter.dst === dst ); + _.assert( dst.src === null || dst.src === filter ); + + if( filter.dst !== dst ) + filter.dst = dst; + if( dst.src !== filter ) + dst.src = filter; + + return filter; +} + +// + +function pairRefineLight() +{ + let src = this; + let dst = src.dst; + const fileProvider = src.system || src.effectiveProvider || src.defaultProvider; + const path = fileProvider.path; + + _.assert( dst instanceof Self ); + _.assert( src instanceof Self ); + _.assert( dst.src === src ); + _.assert( src.dst === dst ); + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( _.mapIs( src.filePath ) && src.filePath === dst.filePath ) + return; + + src.filePath = dst.filePath = path.mapsPair( dst.filePath, src.filePath ); + + _.assert( src.filePath !== undefined ); + _.assert( _.mapIs( src.filePath ) || src.filePath === null ); + _.assert( src.filePath === dst.filePath ); + +} + +// + +function isPaired( aFilter ) +{ + let src = this; + let dst = src.dst; + + aFilter = aFilter || src.dst || src.src; + + if( src.src ) + { + dst = src; + src = src.src; + if( aFilter !== src ) + return false; + } + else + { + if( aFilter !== dst || !dst ) + return false; + } + + _.assert( !!dst ); + _.assert( src.dst === dst ); + _.assert( dst.src === src ); + _.assert( src.src === null ); + _.assert( dst.dst === null ); + + return true; +} + +// -- +// etc +// -- + +function providersNormalize() +{ + let filter = this; + + if( !filter.effectiveProvider ) + filter.effectiveProvider = filter.defaultProvider; + if( !filter.system ) + filter.system = filter.effectiveProvider; + if( filter.system.system ) + filter.system = filter.system.system; + +} + +// + +function providerForPath( filePath ) +{ + let filter = this; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( filter.effectiveProvider ) + return filter.effectiveProvider; + + if( !filePath ) + filePath = filter.filePath; + + if( !filePath ) + filePath = filter.prefixPath; + + if( !filePath ) + filePath = filter.basePath + + _.assert( _.strIs( filePath ), 'Expects string' ); + + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + + filter.effectiveProvider = fileProvider.providerForPath( filePath ); + + return filter.effectiveProvider; +} + +// + +/** + * @summary Converts global path into local. + * @param {String} filePath Input file path. + * @function pathLocalize + * @class wFileRecordFilter + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function pathLocalize( filePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + let isGlobal = path.isGlobal( filePath ); + + _.assert( _.strIs( filePath ) ); + + filePath = path.canonize( filePath ); + + if( filter.effectiveProvider && !isGlobal ) + return filePath; + + let effectiveProvider2; + + if( !isGlobal && filter.defaultProvider && !( filter.defaultProvider instanceof _.FileProvider.System ) ) + { + effectiveProvider2 = filter.defaultProvider + } + else + { + effectiveProvider2 = fileProvider.providerForPath( filePath ); + } + + _.assert + ( + filter.effectiveProvider === null || effectiveProvider2 === null || filter.effectiveProvider === effectiveProvider2, + 'Record filter should have paths of single file provider' + ); + + filter.effectiveProvider = filter.effectiveProvider || effectiveProvider2; + + if( filter.effectiveProvider ) + { + + if( !filter.system ) + filter.system = filter.effectiveProvider.system; + _.assert( filter.effectiveProvider.system === null || filter.system === filter.effectiveProvider.system ); + _.assert( filter.effectiveProvider.system === null || filter.system instanceof _.FileProvider.System ); + + } + + if( !isGlobal ) + return filePath; + + _.assert( !path.isTrailed( filePath ) ); + + let provider = filter.effectiveProvider || filter.system || filter.defaultProvider; + let result = provider.path.preferredFromGlobal( filePath ); + return result; +} + +// + +/** + * @summary Normalizes path properties of the filter. + * @function pathsRefine + * @class wFileRecordFilter + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function pathsRefine() +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + let originalFilePath = filter.filePath; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( filter.formed === 2 ); + _.assert( filter.basePath === null || _.strIs( filter.basePath ) || _.mapIs( filter.basePath ) ); + + filter.prefixesApply({ booleanFallingBack : 1 }); + + _.assert( filter.prefixPath === null, 'Prefixes should be applied so far' ); + _.assert( filter.postfixPath === null, 'Posftixes should be applied so far' ); + + let prefix = filter.prefixPathAbsoluteFrom(); + if( prefix ) + prefix = filter.pathLocalize( prefix ); + + let basePath = filter.basePathFromDecoratedFilePath( filter.filePath ); + + filter.filePath = filter.filePathNormalize( filter.filePath ); + _.assert( _.mapIs( filter.filePath ) ); + if( _.props.keys( filter.filePath ).length === 0 ) + { + let filePath = filter.filePathFromBasePath( filter.basePath ); + _.assert( _.mapIs( filePath ) ) + if( _.props.keys( filePath ).length !== 0 ) + filter.filePath = filePath; + } + + if( !filter.src || filter.basePath ) + filter.basePath = filter.basePathNormalize( filter.filePath, filter.basePath ); + + if( _.props.keys( basePath ).length ) + { + _.assert( filter.basePath === null || _.mapIs( filter.basePath ) ); + basePath = path.filterPairs( basePath, ( it ) => + { + let b = path.join( filter.basePathForStemPath( it.src ) || '', it.dst ); + return { [ it.src ] : b } + }); + filter.basePath = _.props.extend( filter.basePath, basePath ); + } + + filter.filePathAbsolutize( prefix ); + filter.providersNormalize(); + +} + +// + +/** + * @summary Converts local paths of filter into global. + * @function globalsFromLocals + * @class wFileRecordFilter + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function globalsFromLocals() +{ + let filter = this; + + if( !filter.effectiveProvider ) + return; + + if( filter.basePath ) + filter.basePath = filter.effectiveProvider.globalsFromLocals( filter.basePath ); + + if( filter.filePath ) + filter.filePath = filter.effectiveProvider.globalsFromLocals( filter.filePath ); + +} + +// -- +// iterative +// -- + +function allPaths( o ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + let thePath; + + if( _.routineIs( o ) ) + o = { onEach : o } + o = _.routine.options_( allPaths, o ); + _.assert( arguments.length === 1 ); + + if( o.fixes ) + if( !each( filter.prefixPath, 'prefixPath' ) ) + return false; + + if( o.fixes ) + if( !each( filter.postfix, 'postfix' ) ) + return false; + + if( o.basePath ) + if( !each( filter.basePath, 'basePath' ) ) + return false; + + if( o.filePath ) + if( !each( filter.filePath, 'filePath' ) ) + return false; + + return true; + + /* - */ + + function each( thePath, propName ) + { + let result = o.inplace ? path.filterInplace( thePath, o.onEach ) : path.filter( thePath, o.onEach ); + if( o.inplace ) + filter[ propName ] = result; + return result; + } + +} + +allPaths.defaults = +{ + onEach : null, + fixes : 1, + basePath : 1, + filePath : 1, + inplace : 1, +} + +// + +function sureRelativeOrGlobal( o ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + o = _.routine.options_( sureRelativeOrGlobal, arguments ); + + let o2 = _.props.extend( null, o ); + o2.onEach = onEach; + o2.inplace = 0; + + let result = filter.allPaths( o2 ); + + return result; + + /* - */ + + function onEach( element, it ) + { + _.sure + ( + it.value === null || _.boolLike( it.value ) || path.s.allAreRelative( it.value ) || path.s.allAreGlobal( it.value ), + () => 'Filter should have relative ' + it.propName + ', but has ' + _.entity.exportString( it.value ) + ); + } + +} + +sureRelativeOrGlobal.defaults = +{ + fixes : 1, + basePath : 1, + filePath : 1, +} + +// + +function sureBasePath( filePath, basePath ) +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + if( filePath === undefined ) + filePath = filter.filePath; + if( basePath === undefined ) + basePath = filter.basePath; + + _.assert( arguments.length === 0 || arguments.length === 2 ); + _.assert( !_.arrayIs( basePath ) ); + + if( !basePath || _.strIs( basePath ) ) + return; + + basePath = _.props.keys( basePath ); + let originalBasePath = basePath.slice(); + basePath = path.s.join( filter.prefixPath || '', basePath ); + basePath = path.s.fromGlob( basePath ); + + let originalFilePath = _.entity.make( filePath ); + filePath = filter.filePathArrayNonBoolGet( filePath, 0 ); + filePath = filePath.filter( ( e ) => _.strIs( e ) && e ); + filePath = path.s.join( filter.prefixPath || '', filePath ); + if( !filePath.length && basePath.length && filter.prefixPath ) + filePath = _.array.as( filter.prefixPath || '' ); + + if( !filePath.length ) + { + filePath = filePathFromPrefix(); + } + + filePath = path.s.fromGlob( filePath ); + + let diff = _.arraySetDiff_( null, basePath, filePath ); + if( diff.length !== 0 ) + { + debugger; /* yyy */ + let fileWithoutBasePath = _.arraySetBut_( null, filePath.slice(), basePath ); + let baseWithoutFilePath = _.arraySetBut_( null, basePath.slice(), filePath ); + let err = 'Each file path should have base path'; + if( fileWithoutBasePath.length ) + err += '\nFile path without base path : ' + _.strQuote( fileWithoutBasePath ); + if( baseWithoutFilePath.length ) + err += '\nBase path without file path : ' + _.strQuote( baseWithoutFilePath ); + err += '\nBase path : ' + _.strQuote( basePath ); + err += '\nFile path : ' + _.strQuote( filePath ); + debugger; + throw _.err( err ); + } + + _.sure( diff.length === 0, () => 'Some file paths do not have base paths or opposite : ' + _.strQuote( diff ) ); + + for( let g in basePath ) + { + _.sure + ( + !path.isGlob( basePath[ g ] ), + () => 'Base path should not be glob, but base path ' + _.strQuote( basePath[ g ] ) + ' for file path ' + _.strQuote( g ) + ' is glob' + ); + } + + function filePathFromPrefix() + { + let filePath = filter.filePathArrayNonBoolGet( originalFilePath, 1 ); + filePath = filePath.filter( ( e ) => _.strIs( e ) && e ); + filePath = path.s.join( filter.prefixPath || '', filePath ); + return filePath; + } + +} + +// + +function assertBasePath( filePath, basePath ) +{ + let filter = this; + + if( !Config.debug ) + return; + + _.assert( arguments.length === 0 || arguments.length === 2 ); + + return filter.sureBasePath( filePath, basePath ); +} + +// + +function filteringClear() +{ + let filter = this; + + filter.maskAll = null; + filter.maskTerminal = null; + filter.maskDirectory = null; + filter.maskTransientAll = null; + filter.maskTransientTerminal = null; + filter.maskTransientDirectory = null; + + filter.hasExtension = null; + filter.begins = null; + filter.ends = null; + + filter.notOlder = null; + filter.notNewer = null; + filter.notOlderAge = null; + filter.notNewerAge = null; + + return filter; +} + +// -- +// exporter +// -- + +function moveTextualReport() +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + _.assert( filter.isPaired() ); + + filter = filter.pairedClone(); + filter._formPaths(); + filter.pairedFilter._formPaths(); + + let srcFilter = filter.src ? filter.src : filter; + let dstFilter = srcFilter.dst; + + let srcPath = srcFilter.filePathSrcCommon(); + let dstPath = dstFilter.filePathDstCommon(); + let result = path.moveTextualReport( dstPath, srcPath ); + + return result; +} + +// + +function compactField( it ) +{ + let filter = this; + + if( it.dst === null ) + return; + + if( it.dst && it.dst instanceof _.RegexpObject ) + if( !it.dst.hasData() ) + return; + + if( _.object.isBasic( it.dst ) && _.props.keys( it.dst ).length === 0 ) + return; + + return it.dst; +} + +// + +function toStr() +{ + let filter = this; + let result = ''; + + result += 'Filter'; + + for( let m in filter.MaskNames ) + { + let maskName = filter.MaskNames[ m ]; + if( filter[ maskName ] !== null ) + { + if( !filter[ maskName ].isEmpty ) + result += '\n' + ' ' + maskName + ' : ' + true; + } + } + + let FieldNames = + [ + 'prefixPath', 'postfixPath', + 'filePath', + 'basePath', + 'hasExtension', 'begins', 'ends', + 'notOlder', 'notNewer', 'notOlderAge', 'notNewerAge', + ]; + + for( let f in FieldNames ) + { + let propName = FieldNames[ f ]; + if( filter[ propName ] !== null ) + result += '\n' + ' ' + propName + ' :\n' + _.entity.exportJs( filter[ propName ], { levels : 2 } ); + } + + return result; +} + +// -- +// dichotomy +// -- + +function hasMask() +{ + let filter = this; + + if( filter.formedMasksMap ) + return true; + + let hasMask = false; + + hasMask = hasMask || ( filter.maskAll && !filter.maskAll.isEmpty() ); + hasMask = hasMask || ( filter.maskTerminal && !filter.maskTerminal.isEmpty() ); + hasMask = hasMask || ( filter.maskDirectory && !filter.maskDirectory.isEmpty() ); + hasMask = hasMask || ( filter.maskTransientAll && !filter.maskTransientAll.isEmpty() ); + hasMask = hasMask || ( filter.maskTransientTerminal && !filter.maskTransientTerminal.isEmpty() ); + hasMask = hasMask || ( filter.maskTransientDirectory && !filter.maskTransientDirectory.isEmpty() ); + + hasMask = hasMask || !!filter.hasExtension; + hasMask = hasMask || !!filter.begins; + hasMask = hasMask || !!filter.ends; + + return hasMask; +} + +// + +function hasFiltering() +{ + let filter = this; + + if( filter.hasMask() ) + return true; + + if( filter.notOlder !== null ) + return true; + if( filter.notNewer !== null ) + return true; + if( filter.notOlderAge !== null ) + return true; + if( filter.notNewerAge !== null ) + return true; + + return false; +} + +// + +function hasAnyPath() +{ + let filter = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( filter.basePath === null || _.strIs( filter.basePath ) || _.mapIs( filter.basePath ) ); + _.assert( filter.prefixPath === null || _.strIs( filter.prefixPath ) || _.strsAreAll( filter.prefixPath ) ); + _.assert( filter.postfixPath === null || _.strIs( filter.postfixPath ) ); + _.assert + ( + filter.filePath === null + || _.strIs( filter.filePath ) + || _.arrayIs( filter.filePath ) + || _.mapIs( filter.filePath ) + ); + + if( _.strIs( filter.basePath ) || _.map.isPopulated( filter.basePath ) ) + return true; + + if( _.any( filter.prefixPath, ( e ) => _.strIs( e ) && e ) ) + return true; + + if( _.any( filter.postfixPath, ( e ) => _.strIs( e ) && e ) ) + return true; + + let filePath = filter.filePathArrayNonBoolGet(); + + if( filePath.length === 1 ) + if( filePath[ 0 ] === '' || filePath[ 0 ] === null ) + { + return false; + } + + if( filePath.length ) + return true; + + return false; +} + +// + +function hasData() +{ + let filter = this; + + if( filter.hasAnyPath() ) + return true; + + if( filter.hasFiltering() ) + return true; + + return false; +} + +// -- +// mask +// -- + +/** + * @summary Applies file extension mask to the filter. + * @function maskExtensionApply + * @class wFileRecordFilter + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function maskExtensionApply() +{ + let filter = this; + + if( filter.hasExtension ) + { + _.assert( _.strIs( filter.hasExtension ) || _.strsAreAll( filter.hasExtension ) ); + + filter.hasExtension = _.array.as( filter.hasExtension ); + filter.hasExtension = new RegExp( '^.*\\.(' + _.regexpsEscape( filter.hasExtension ).join( '|' ) + ')(\\.|$)(?!.*\/.+)', 'i' ); + + filter.maskAll = _.RegexpObject.And( filter.maskAll, { includeAll : filter.hasExtension } ); + filter.hasExtension = null; + } + +} + +// + +/** + * @summary Applies file begins mask to the filter. + * @function maskBeginsApply + * @class wFileRecordFilter + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function maskBeginsApply() +{ + let filter = this; + + if( filter.begins ) + { + _.assert( _.strIs( filter.begins ) || _.strsAreAll( filter.begins ) ); + + filter.begins = _.array.as( filter.begins ); + filter.begins = new RegExp( '^(\\.\\/)?(' + _.regexpsEscape( filter.begins ).join( '|' ) + ')' ); + + filter.maskAll = _.RegexpObject.And( filter.maskAll, { includeAll : filter.begins } ); + filter.begins = null; + } + +} + +/** + * @summary Applies file ends mask to the filter. + * @function maskEndsApply + * @class wFileRecordFilter + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +// + +function maskEndsApply() +{ + let filter = this; + + if( filter.ends ) + { + _.assert( _.strIs( filter.ends ) || _.strsAreAll( filter.ends ) ); + + filter.ends = _.array.as( filter.ends ); + filter.ends = new RegExp( '(' + '^\.|' + _.regexpsEscape( filter.ends ).join( '|' ) + ')$' ); + + filter.maskAll = _.RegexpObject.And( filter.maskAll, { includeAll : filter.ends } ); + filter.ends = null; + } + +} + +// + +/** + * @descriptionNeeded + * @function masksGenerate + * @class wFileRecordFilter + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function masksGenerate() +{ + let filter = this; + const fileProvider = filter.system || filter.effectiveProvider || filter.defaultProvider; + const path = fileProvider.path; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( filter.formed === 3 ); + _.assert( filter.recursive === 0 || filter.recursive === 1 || filter.recursive === 2 ) + + if( filter.src ) + { + copy( path.s.fromGlob( filter.filePath ), path.s.fromGlob( filter.basePath || {} ) ); + return end(); + } + + let filePath = filter.filePath; + let basePath = filter.basePath; + let globFound = filter.filePathIsComplex( filePath ); + if( !globFound ) + { + copy( filePath, basePath ); + if( filter.recursive === 2 ) + filter.formedFilePath = path.mapOptimize( filter.formedFilePath, filter.formedBasePath ); + return end(); + } + + _.assert( !filter.src ); + let filePath2 = _.props.extend( null, filePath ); + let basePath2 = _.props.extend( null, basePath ); + if( !_.path.map.identical( filePath2, filePath ) ) + { + globFound = filter.filePathIsComplex( filePath2 ); + } + + if( !globFound ) + { + copy( filePath2, basePath2 ); + return end(); + } + + let _processed = path.pathMapToRegexps( filePath2, basePath2 ); + + if( filter.recursive === 2 ) + { + filter.formedBasePath = _processed.optimizedUnglobedBasePath; + filter.formedFilePath = _processed.optimizedUnglobedFilePath; + } + else + { + filter.formedBasePath = _processed.unglobedBasePath; + filter.formedFilePath = _processed.unglobedFilePath; + } + + filter.assertBasePath( filter.formedFilePath, filter.formedBasePath ); + + _.assert( !filter.src ); + _.assert( filter.formedMasksMap === null ); + filter.formedMasksMap = Object.create( null ); + + let regexpsMap = filter.recursive === 2 ? _processed.optimalRegexpsMap : _processed.regexpsMap; + for( let stemPath in regexpsMap ) + masksSet( stemPath, regexpsMap[ stemPath ], filter.formedMasksMap ); + + end(); + + /* */ + + function masksSet( stemPath, regexps, masksMap ) + { + + _.assert( _.mapIs( _processed.groupsMap[ stemPath ] ) ); + + if( _.props.keys( _processed.groupsMap[ stemPath ] ).length === 0 ) + return; + + let basePath = filter.formedBasePath[ stemPath ]; + _.assert( _.strDefined( basePath ), 'No base path for', stemPath ); + _.assert( !masksMap[ stemPath ] ); + let subfilter = masksMap[ stemPath ] = Object.create( null ); + + subfilter.maskAll = filter.maskAll.clone().extend + ({ + includeAll : regexps.actualAll, + includeAny : regexps.actualAny, + excludeAny : regexps.actualNone, + }); + subfilter.maskTerminal = filter.maskTerminal.clone(); + subfilter.maskDirectory = filter.maskDirectory.clone(); + + subfilter.maskTransientAll = filter.maskTransientAll.clone(); + subfilter.maskTransientTerminal = filter.maskTransientTerminal.clone().extend + ({ + includeAny : /$_^/ + }); + subfilter.maskTransientDirectory = filter.maskTransientDirectory.clone().extend + ({ + includeAny : regexps.transient + }); + + regexps.actualNone.forEach( ( none ) => + { + let certainly = regexps.certainlyHash.get( none ); + if( certainly ) + subfilter.maskTransientDirectory.excludeAny.push( certainly ); + }); + + _.assert( subfilter.maskAll !== filter.maskAll ); + + } + + /* */ + + function copy( filePath, basePath ) + { + + /* if base path is redundant then return empty map */ + if( _.mapIs( basePath ) ) + filter.formedBasePath = _.entity.make( basePath ); + else + filter.formedBasePath = Object.create( null ); + filter.formedFilePath = _.entity.make( filePath ); + + } + + /* */ + + function end() + { + if( filter.src && filter.src.formed < 5 && filter.src.formedFilePath ) + filter.src.formedFilePath = filter.formedFilePath; + if( filter.dst && filter.dst.formed < 5 && filter.dst.formedFilePath ) + filter.dst.formedFilePath = filter.formedFilePath; + if( filter.formedMasksMap && _.props.keys( filter.formedMasksMap ).length === 0 ) + filter.formedMasksMap = null; + } + +} + +// -- +// applier +// -- + +function _recordFitNothing( record ) +{ + let filter = this; + return record.isActual; +} + +// + +function _recordFitMasks( record ) +{ + let filter = this; + let relative = record.relative; + let f = record.factory; + let path = record.path; + let masks = filter; + masks = filter; + if( filter.formedMasksMap && filter.formedMasksMap[ f.stemPath ] ) + masks = filter.formedMasksMap[ f.stemPath ]; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( !!masks, 'Cant resolve filter map for stem path', () => _.strQuote( f.stemPath ) ); + _.assert( !!f.formed, 'Record factor was not formed!' ); + + // if( _global_.debugger ) + // if( _.strHas( record.absolute, '.module' ) ) + // debugger; + + /* */ + + if( record.isDir ) + { + + if( record.isTransient && masks.maskTransientAll ) + record[ isTransientSymbol ] = masks.maskTransientAll.test( relative ); + if( record.isTransient && masks.maskTransientDirectory ) + record[ isTransientSymbol ] = masks.maskTransientDirectory.test( relative ); + + if( record.isActual && masks.maskAll ) + record[ isActualSymbol ] = masks.maskAll.test( relative ); + if( record.isActual && masks.maskDirectory ) + record[ isActualSymbol ] = masks.maskDirectory.test( relative ); + + } + else + { + + if( record.isActual && masks.maskAll ) + record[ isActualSymbol ] = masks.maskAll.test( relative ); + if( record.isActual && masks.maskTerminal ) + record[ isActualSymbol ] = masks.maskTerminal.test( relative ); + + if( record.isTransient && masks.maskTransientAll ) + record[ isTransientSymbol ] = masks.maskTransientAll.test( relative ); + if( record.isTransient && masks.maskTransientTerminal ) + record[ isTransientSymbol ] = masks.maskTransientTerminal.test( relative ); + + } + + /* */ + + return record.isActual; +} + +// + +function _recordFitTime( record ) +{ + let filter = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( record.isActual === false ) + return record.isActual; + + if( !record.isDir ) + { + let time; + if( record.isActual === true ) + { + time = record.stat.mtime; + if( record.stat.birthtime > record.stat.mtime ) + time = record.stat.birthtime; + } + + if( record.isActual === true ) + if( filter.notOlder !== null ) + { + record[ isActualSymbol ] = time >= filter.notOlder; + } + + if( record.isActual === true ) + if( filter.notNewer !== null ) + { + record[ isActualSymbol ] = time <= filter.notNewer; + } + + if( record.isActual === true ) + if( filter.notOlderAge !== null ) + { + record[ isActualSymbol ] = _.time.now() - filter.notOlderAge - time <= 0; + } + + if( record.isActual === true ) + if( filter.notNewerAge !== null ) + { + record[ isActualSymbol ] = _.time.now() - filter.notNewerAge - time >= 0; + } + } + + return record.isActual; +} + +// + +function _recordFitFull( record ) +{ + let filter = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( record.isActual === false ) + return record.isActual; + + filter._recordFitMasks( record ); + filter._recordFitTime( record ); + + return record.isActual; +} + +// -- +// relations +// -- + +/** + * @typedef {Object} Fields + * @property {String} filePath + * @property {String} basePath + * @property {String} prefixPath + * @property {String} postfixPath + * + * @property {String} hasExtension + * @property {String} begins + * @property {String} ends + * + * @property {String|Array|RegExp} maskTransientAll + * @property {String|Array|RegExp} maskTransientTerminal, + * @property {String|Array|RegExp} maskTransientDirectory + * @property {String|Array|RegExp} maskAll + * @property {String|Array|RegExp} maskTerminal + * @property {String|Array|RegExp} maskDirectory + * + * @property {Date} notOlder + * @property {Date} notNewer + * @property {Date} notOlderAge + * @property {Date} notNewerAge + * @class wFileRecordFilter + * @namespace wTools + * @module Tools/mid/Files +*/ + +let isTransientSymbol = Symbol.for( 'isTransient' ); +let isActualSymbol = Symbol.for( 'isActual' ); +let filePathSymbol = Symbol.for( 'filePath' ); +let basePathSymbol = Symbol.for( 'basePath' ); + +let MaskNames = +[ + 'maskAll', + 'maskTerminal', + 'maskDirectory', + 'maskTransientAll', + 'maskTransientTerminal', + 'maskTransientDirectory', +] + +let Composes = +{ + + filePath : null, + basePath : null, + prefixPath : null, + postfixPath : null, + + hasExtension : null, + begins : null, + ends : null, + recursive : null, + + maskTransientAll : null, + maskTransientTerminal : null, + maskTransientDirectory : null, + maskAll : null, + maskTerminal : null, + maskDirectory : null, + + notOlder : null, + notNewer : null, + notOlderAge : null, + notNewerAge : null, + +} + +let Aggregates = +{ + +} + +let Associates = +{ + effectiveProvider : null, + defaultProvider : null, + system : null, +} + +let Restricts = +{ + + formedFilePath : null, + formedBasePath : null, + formedMasksMap : null, + + applyTo : null, + formed : 0, + + src : null, + dst : null, + +} + +let Medials = +{ +} + +let Statics = +{ + And, + MaskNames, +} + +let Forbids = +{ + + options : 'options', + glob : 'glob', + recipe : 'recipe', + globOut : 'globOut', + inPrefixPath : 'inPrefixPath', + inPostfixPath : 'inPostfixPath', + fixedFilePath : 'fixedFilePath', + fileProvider : 'fileProvider', + fileProviderEffective : 'fileProviderEffective', + isEmpty : 'isEmpty', + globMap : 'globMap', + _processed : '_processed', + test : 'test', + inFilePath : 'inFilePath', + stemPath : 'stemPath', + distinct : 'distinct', + globFound : 'globFound', + hubFileProvider : 'hubFileProvider', + effectiveFileProvider : 'effectiveFileProvider', + defaultFileProvider : 'defaultFileProvider', + +} + +let Accessors = +{ + + filePath : {}, + basePath : { set : basePathSet }, + basePaths : { get : basePathsGet, writable : 0 }, + pairedFilter : { get : pairedFilterGet, writable : 0 }, + +} + +// -- +// declare +// -- + +let Extension = +{ + + init, + copy, + pairedClone, + + // former + + form, + _formAssociations, + _formPre, + _formPaths, + _formMasks, + _formFinal, + + // combiner + + And, + and, + + _pathsAmmend, + + pathsExtend, + pathsExtendJoining, + pathsSupplement, + pathsSupplementJoining, + + // prefix path + + prefixesApply, + prefixesRelative, + prefixPathFromFilePath, + prefixPathAbsoluteFrom, + + // base path + + relativeFor, + basePathSet, + basePathForStemPath, + basePathForFilePath, + basePathsGet, + basePathMapFromString, + basePathMapLocalize, + basePathFromDecoratedFilePath, + basePathNormalize, + basePathSimplest, /* qqq : cover routine basePathSimplest */ + basePathDotUnwrap, + basePathEach, /* qqq : cover routine basePathEach */ + basePathUse, + + // file path + + filePathMove, + + filePathSelect, + filePathNormalize, + filePathPrependByBasePath, /* qqq : cover it */ + filePathMultiplyRelatives, + filePathFromBasePath, + filePathAbsolutize, /* qqq : cover it */ + filePathGlobSimplify, + filePathFromFixes, + filePathSimplest, + filePathNullizeMaybe, + filePathIsComplex, /* qqq : good coverage needed */ + filePathHasGlob, /* qqq : simple coverage needed */ + + filePathDstHasAllBools, + filePathDstHasAnyBools, + filePathMapOnlyBools, + filePathMap, + + filePathDstArrayGet, + filePathSrcArrayGet, + filePathArrayGet, + + filePathDstArrayNonBoolGet, + filePathSrcArrayNonBoolGet, + filePathArrayNonBoolGet, + + filePathDstArrayBoolGet, + filePathSrcArrayBoolGet, + filePathArrayBoolGet, + + filePathDstNormalizedGet, /* zzz : remove maybe? */ + filePathSrcNormalizedGet, /* zzz : remove maybe? */ + filePathNormalizedGet, /* zzz : remove maybe? */ + + filePathCommon, + filePathDstCommon, + filePathSrcCommon, + + // pair + + pairedFilterGet, + pairWithDst, + pairRefineLight, + isPaired, + + // etc + + filteringClear, + providersNormalize, + providerForPath, + + pathLocalize, + pathsRefine, + globalsFromLocals, + + // iterative + + allPaths, + sureRelativeOrGlobal, + sureBasePath, + assertBasePath, + + // exporter + + moveTextualReport, + compactField, + toStr, + + // dichotomy + + hasMask, + hasFiltering, + hasAnyPath, + hasData, + + // mask + + maskExtensionApply, + maskBeginsApply, + maskEndsApply, + masksGenerate, + + // applier + + _recordFitNothing, + _recordFitMasks, + _recordFitTime, + _recordFitFull, + + // relations + + Composes, + Aggregates, + Associates, + Restricts, + Medials, + Statics, + Forbids, + Accessors, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Extension, +}); + +_.files[ Self.shortName ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l3/RecordFilter.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, RecordFilter_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file RecordFilter_s */ })(); + +/* */ /* begin of file StatClass_s */ ( function StatClass_s() { function StatClass_s_naked() { ( function _StatClass_s_() +{ + +'use strict'; + +// + +/** + * @class wFileStat + * @namespace wTools + * @module Tools/mid/Files +*/ + +const _global = _global_; +const _ = _global_.wTools; +const Parent = null; +const Self = wFileStat; +function wFileStat( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'FileStat'; + +// -- +// implementation +// -- + +function init( o ) +{ + let self = this; + + _.workpiece.initFields( self ); + + if( o ) + self.copy( o ); + + Object.preventExtensions( self ); + +} + +// + +/** + * @summary Returns true if current stats object refers to soft or text link. + * @function isLink + * @class wFileStat + * @namespace wTools + * @module Tools/mid/Files +*/ + +function isLink() +{ + let stat = this; + let result = false; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( !result ) + result = stat.isSoftLink(); + + if( !result ) + result = stat.isTextLink(); + + return result; +} + +// + +function returnFalse() +{ + return false; +} + +/** + * @typedef {Object} Fields + * @property {Number} dev + * @property {Number} mode + * @property {Number} nlink + * @property {Number} uid + * @property {Number} gid + * @property {Number} rdev + * @property {Number} blksize + * @property {Number} ino + * @property {Number} size + * @property {Number} blocks + * @property {Date} atime + * @property {Date} mtime + * @property {Date} ctime + * @property {Date} birthtime + * @property {String} filePath + * @class wFileStat + * @namespace wTools + * @module Tools/mid/Files +*/ + +// -- +// relation +// -- + +let Composes = +{ + dev : null, + mode : null, + nlink : null, + uid : null, + gid : null, + rdev : null, + blksize : null, + ino : null, + size : null, + blocks : null, + atime : null, + mtime : null, + ctime : null, + birthtime : null, +} + +let Aggregates = +{ +} + +let Associates = +{ + associated : null, + filePath : null, +} + +let Restricts = +{ + + isDir : null, + isTerminal : null, + isTextLink : null, + isSoftLink : null, + isHardLink : null, + + isDirectory : null, /* alias */ + isFile : null, /* alias */ + isSymbolicLink : null, /* alias */ + + isBlockDevice : returnFalse, + isCharacterDevice : returnFalse, + isFIFO : returnFalse, + isSocket : returnFalse, + +} + +let Statics = +{ +} + +let Forbids = +{ +} + +// -- +// declare +// -- + +let Extension = +{ + + init, + + isDir : null, + isTerminal : null, + isTextLink : null, + isSoftLink : null, + isHardLink : null, + isLink, + + isDirectory : null, /* alias */ + isFile : null, /* alias */ + isSymbolicLink : null, /* alias */ + + isBlockDevice : returnFalse, + isCharacterDevice : returnFalse, + isFIFO : returnFalse, + isSocket : returnFalse, + + // + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + Forbids, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Extension, +}); + +if( _global_.wCopyable ) +_.Copyable.mixin( Self ); +_.files[ Self.shortName ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l3/StatClass.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, StatClass_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file StatClass_s */ })(); + +/* */ /* begin of file StatNamespace_s */ ( function StatNamespace_s() { function StatNamespace_s_naked() { ( function _StatNamespace_s_() +{ + +'use strict'; + +let File; + +if( typeof module !== 'undefined' ) +{ + + try + { + if( Config.interpreter === 'njs' ) + File = require( 'fs' ); + } + catch( err ) + { + } + +} + +/** + * @namespace wTools.files.stat + * @module Tools/mid/Files + */ + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.files.stat = _.files.stat || Object.create( null ); + +// -- +// +// -- + +/** + * @summary Returns true if entity `src` is a file stats object. + * @param {Object} src Entity to check. + * @function fileStatIs + * @namespace wTools/files + * @module Tools/mid/Files + */ + +function fileStatIs( src ) +{ + if( File ) + if( src instanceof File.Stats ) + return true; + if( _.files.FileStat ) + if( src instanceof _.files.FileStat ) + return true; + let proto = Object.getPrototypeOf( File.Stats ); + if( proto.name && src instanceof proto ) + return true; + return false; +} + +// + +/** + * @summary Determines if two files have different content by comparing their stat object. + * @description Returns `true` if files have different concents, `false` if files have same concent and `null` if result is not precise. + * @param {Object} stat1 Stat object of first file. + * @param {Object} stat2 Stat object of second file. + * @function different + * @namespace wTools/files + * @module Tools/mid/Files + */ + +function different( stat1, stat2 ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( _.bigIntIs( stat1.ino ) ) + if( stat1.ino === stat2.ino ) + return false; + + if( stat1.size !== stat2.size ) + return true; + + if( stat1.size === 0 || stat2.size === 0 ) + return null; + + return null; +} + +// + +/** + * @summary Determines if two files are hard linked by comparing their stat object. + * @description Returns `true` if files have different concents, `false` if files have same concent and `null` if result is not precise. + * @param {Object} stat1 Stat object of first file. + * @param {Object} stat2 Stat object of second file. + * @function areHardLinked + * @namespace wTools/files + * @module Tools/mid/Files + */ + +function areHardLinked( stat1, stat2 ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.fileStatIs( stat1 ) ); + _.assert( _.fileStatIs( stat2 ) ); + + /* + ino comparison is not reliable test on nodejs below 10.5 + it's reliable only if ino is BigNumber + */ + + if( _.bigIntIs( stat1.ino ) ) + return stat1.ino === stat2.ino; + + if( stat1.ino !== stat2.ino ) + return false; + + /* + try to make a good guess if ino comprison is not possible + */ + + /* notes : + should return true for comparing file with itself + so nlink could be 1 + */ + + if( stat1.nlink !== stat2.nlink ) + return false; + + if( stat1.mode !== stat2.mode ) + return false; + + if( stat1.size !== stat2.size ) + return false; + + if( stat1.mtime && stat2.mtime ) + if( stat1.mtime.getTime() !== stat2.mtime.getTime() ) + return false; + + if( stat1.ctime && stat2.ctime ) + if( stat1.ctime.getTime() !== stat2.ctime.getTime() ) + return false; + + if( stat1.birthtime && stat2.birthtime ) + if( stat1.birthtime.getTime() !== stat2.birthtime.getTime() ) + return false; + + return _.maybe; +} + +// + +/** + * @summary Generates hash from stat object. + * @param {Object} stat Stat object. + * @function hashStatFrom + * @namespace wTools/files + * @module Tools/mid/Files + */ + +function hashStatFrom( stat ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.bigIntIs( stat.ino ) ) + return stat.ino; + + let ino = stat.ino || 0; + let mtime = stat.mtime.getTime(); + let ctime = stat.ctime.getTime(); + + _.assert( _.numberIs( mtime ) ); + _.assert( _.numberIs( ctime ) ); + _.assert( _.numberIs( stat.nlink ) ); + + let result = ino + '' + mtime + '' + ctime + '' + stat.size; + + _.assert( _.strIs( result ) ); + + return result; +} + +// -- +// +// -- + +let Tools = +{ + fileStatIs, + // different, + // areHardLinked, + // hashStatFrom, +} + +/* zzz : clean */ + +_.props.extend( _, Tools ); + +// + +let StatExtension = +{ + + is : fileStatIs, + different, + areHardLinked, + hashStatFrom, + +} + +/* _.props.extend */Object.assign( _.files.stat, StatExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l3/StatNamespace.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, StatNamespace_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file StatNamespace_s */ })(); + +/* */ /* begin of file Abstract_s */ ( function Abstract_s() { function Abstract_s_naked() { ( function _Abstract_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +var FileRecord = _.files.FileRecord; +var FileRecordFilter = _.files.FileRecordFilter; +var FileRecordFactory = _.files.FileRecordFactory; + +_.assert( !_.FileProvider.Abstract ); +_.assert( _.routineIs( _.files.FileRecord ) ); +_.assert( _.routineIs( FileRecordFilter ) ); +_.assert( _.routineIs( FileRecordFactory ) ); + +/** + * @class wFileProviderAbstract + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +const Parent = null; +const Self = wFileProviderAbstract; +function wFileProviderAbstract( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'Abstract'; + +// + +function init( o ) +{ +} + +// -- +// relations +// -- + +var Composes = +{ +} + +var Aggregates = +{ +} + +var Associates = +{ +} + +var Restricts = +{ +} + +var Statics = +{ + Record : FileRecord, + RecordFilter : FileRecordFilter, + RecordFactory : FileRecordFactory, +} + +// -- +// declare +// -- + +var Extension = +{ + + init, + + // relations + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Extension, +}); + +// + +_.FileProvider = _.FileProvider || Object.create( null ); +_.FileProvider[ Self.shortName ] = Self; + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l4/Abstract.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l4' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Abstract_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Abstract_s */ })(); + +/* */ /* begin of file Carriage_s */ ( function Carriage_s() { function Carriage_s_naked() { // ( function _StatCarriage_s_() +// { +// +// 'use strict'; +// +// const _global = _global_; +// const _ = _global_.wTools; +// const Parent = null; +// const Self = wStatsStatCarriage; +// function wStatsStatCarriage( o ) +// { +// return _.workpiece.construct( Self, this, arguments ); +// } +// +// Self.shortName = 'StatCarriage'; +// +// // +// +// function init( o ) +// { +// var self = this; +// +// _.assert( arguments.length === 0, 'Expects no arguments' ); +// _.workpiece.initFields( self ); +// +// if( self.Self === Self ) +// Object.preventExtensions( self ); +// +// return self; +// } +// +// // -- +// // relations +// // -- +// +// var Composes = +// { +// } +// +// var Aggregates = +// { +// } +// +// var Associates = +// { +// } +// +// var Restricts = +// { +// } +// +// var Statics = +// { +// } +// +// // -- +// // declare +// // -- +// +// var Extension = +// { +// +// init, +// +// // relations +// +// Composes, +// Aggregates, +// Associates, +// Restricts, +// Statics, +// +// } +// +// // +// +// _.classDeclare +// ({ +// cls : Self, +// parent : Parent, +// extend : Extension, +// }); +// +// _.Copyable.mixin( Self ); +// +// // +// +// // _.[ Self.shortName ] = Self; +// _[ Self.shortName ] = Self; +// +// // -- +// // export +// // -- +// +// if( typeof module !== 'undefined' ) +// module[ 'exports' ] = Self; +// +// })(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l4/Carriage.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l4' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Carriage_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Carriage_s */ })(); + +/* */ /* begin of file Carrier_s */ ( function Carrier_s() { function Carrier_s_naked() { // ( function _Carrier_s_() +// { +// +// 'use strict'; +// +// const _global = _global_; +// const _ = _global_.wTools; +// const Parent = null; +// const Self = wStatsCarrier; +// function wStatsCarrier( o ) +// { +// return _.workpiece.construct( Self, this, arguments ); +// } +// +// Self.shortName = 'StatCarrier'; +// +// // +// +// function init( o ) +// { +// var self = this; +// +// _.assert( arguments.length === 0, 'Expects no arguments' ); +// _.workpiece.initFields( self ); +// +// if( self.Self === Self ) +// Object.preventExtensions( self ); +// +// return self; +// } +// +// // -- +// // relations +// // -- +// +// var Composes = +// { +// } +// +// var Aggregates = +// { +// } +// +// var Associates = +// { +// } +// +// var Restricts = +// { +// } +// +// var Statics = +// { +// } +// +// // -- +// // declare +// // -- +// +// var Extension = +// { +// +// init, +// +// // relations +// +// Composes, +// Aggregates, +// Associates, +// Restricts, +// Statics, +// +// } +// +// // +// +// _.classDeclare +// ({ +// cls : Self, +// parent : Parent, +// extend : Extension, +// }); +// +// _.Copyable.mixin( Self ); +// +// // +// +// // _.[ Self.shortName ] = Self; +// _[ Self.shortName ] = Self; +// +// // -- +// // export +// // -- +// +// if( typeof module !== 'undefined' ) +// module[ 'exports' ] = Self; +// +// })(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l4/Carrier.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l4' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Carrier_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Carrier_s */ })(); + +/* */ /* begin of file Partial_s */ ( function Partial_s() { function Partial_s_naked() { ( function _Partial_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( !!_.FileProvider.Abstract ); +_.assert( !_.FileProvider.Partial ); +_.assert( _.routineIs( _.routineVectorize_functor ) ); +_.assert( _.routineIs( _.path.join ) ); + +// + +/** + * Definitions : + * Terminal file :: leaf of files sysytem, contains series of bytes. Terminal file cant contain other files. + * Directory :: non-leaf node of files sysytem, contains other dirs and terminal file(s). + * File :: any node of files sysytem, could be leaf( terminal file ) or non-leaf( directory ). + * Only terminal files contains series of bytes, function of directory to organize logical space for terminal files. + * self :: pathCurrent object. + * Self :: pathCurrent class. + * Parent :: parent class. + * Statics :: static fields. + */ + +/* + Act version of method : + +- should assert that path is absolute +- should not extend or delete fields of options map, no _providerDefaultsApply, routineOptions +- should path.nativize all paths in options map if needed by its own means +- should expect normalized path, but not nativized +- should expect ready options map, no complex arguments preprocessing +- should not create folders structure for path + +*/ + +/* + +qqq : implement routines fileLockAct, fileUnlockAct, fileIsLockedAct and corresponding fileLock, fileUnlock, fileIsLocked. +qqq : cover it and add jsdoc + +fileLockAct.defaults = +{ + filePath : null, + sync : 1, + waiting : 0, + throwing : 1, + timeOut : 5000, + id : null, +} + +fileUnlockAct.defaults = +{ + filePath : null, + sync : 1, + throwing : 1, + timeOut : 5000, + id : null, +} + +fileIsLockedAct.defaults = +{ + filePath : null, + sync : 1, + timeOut : 5000, + throwing : 1, + id : null, +} + +*/ + +// + +/** + @classdesc Defines single interface, called ( FileProvider ) to perform file operations in the same manner with different sources/destinations. + @class wFileProviderPartial + @namespace wTools.FileProvider + @module Tools/mid/Files +*/ + +const Parent = _.FileProvider.Abstract; +const Self = wFileProviderPartial; +function wFileProviderPartial( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'Partial'; + +// -- +// meta +// -- + +let vectorizeKeysAndVals = _.files._.vectorizeKeysAndVals; +let vectorize = _.files._.vectorize; +let vectorizeAll = _.files._.vectorizeAll; +let vectorizeAny = _.files._.vectorizeAny; +let vectorizeNone = _.files._.vectorizeNone; + +// -- +// inter +// -- + +function init( o ) +{ + let self = this; + + Parent.prototype.init.call( self ); + + _.workpiece.initFields( self ); + + _.assert( _.arrayIs( self.protocols ) ); + _.assert( self.protocol !== undefined ); + + if( self.Self === Self ) + Object.preventExtensions( self ); + + if( o && o.path ) + self.path = o.path; + if( self.path === null ) + self.path = self.Path.CloneExtending({ fileProvider : self }); + + if( o ) + { + if( o.logger ) + self.logger = o.logger; + else + self.logger = new _.Logger({ output : console, verbosity : self.verbosity }); + self.copy( o ); + } + else + { + self.logger = new _.Logger({ output : console, verbosity : self.verbosity }); + } + + Self.Counter += 1; + self.id = Self.Counter; + + if( self.logger === null ) + self.logger = _.logger.fromStrictly( self.verbosity ); + + if( o ) + if( o.protocol !== undefined || o.originPath !== undefined ) + { + if( o.protocol !== undefined ) + self.protocol = o.protocol; + else if( o.originPath !== undefined ) + self.originPath = o.originPath; + } + + if( self.verbosity >= 2 ) + self.logger.log( 'new', _.entity.strType( self ) ); + + // _.process._exitHandlerOnce( () => + // { + // self.path.tempClose() + // }); + +} + +// + +function finit() +{ + let self = this; + if( self.system ) + self.system.providerUnregister( self ); + _.Copyable.prototype.finit.call( self ); +} + +// + +function MakeDefault() +{ + + _.assert( !!_.FileProvider.Default ); + _.assert( !_.fileProvider ); + _.fileProvider = new _.FileProvider.Default(); + _.assert( _.path.fileProvider === null ); + _.path.fileProvider = _.fileProvider; + _.assert( _.path.fileProvider === _.fileProvider ); + _.assert( _.uri.fileProvider === _.fileProvider ); + + _.assert( !_.fileSystem ); + _.fileSystem = _.FileProvider.System({ empty : 1 }); + _.fileSystem.providerRegister( _.fileProvider ); + _.fileSystem.defaultProvider = _.fileProvider; + + /* xxx : qqq : problem if HardDrive have protocol in order [ 'file', 'hd' ] instead of [ 'hd', 'file' ] + then system calls with path hd://... does fails + introduce and use field defaultProtocols for system + */ + + return _.fileProvider; +} + +// -- +// helper +// -- + +/** + * Return options for file read/write. If `filePath is an object, method returns it. Method validate result option + properties by default parameters from invocation context. + * @param {string|Object} filePath + * @param {Object} [o] Object with default options parameters + * @returns {Object} Result options + * @private + * @throws {Error} If arguments is missed + * @throws {Error} If passed extra arguments + * @throws {Error} If missed `PathFiile` + * @method _fileOptionsGet + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function _fileOptionsGet( filePath, o ) +{ + let self = this; + o = o || Object.create( null ); + + if( _.object.isBasic( filePath ) ) + { + o = filePath; + } + else + { + o.filePath = filePath; + } + + if( !o.filePath ) + throw _.err( '_fileOptionsGet :', 'Expects (-o.filePath-)' ); + + _.map.assertHasOnly( o, this.defaults ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( o.sync === undefined ) + o.sync = 1; + + return o; +} + +// + +function _providerDefaultsApply( o ) +{ + let self = this; + + _.assert( _.object.isBasic( o ), 'Expects map { o }' ); + + if( o.verbosity === null && self.verbosity !== null ) + o.verbosity = _.numberClamp( self.verbosity - 4, 0, 9 ); + + for( let k in self.ProviderDefaults ) + { + if( o[ k ] === null ) + if( self[ k ] !== undefined && self[ k ] !== null ) + o[ k ] = self[ k ]; + } + + if( o.verbosity !== undefined && o.verbosity !== null ) + { + if( !_.numberIs( o.verbosity ) ) + o.verbosity = o.verbosity ? 1 : 0; + if( o.verbosity < 0 ) + o.verbosity = 0; + } + + if( o.logger !== undefined ) + o.logger = _.logger.maybe( o.logger ); +} + +// + +function assertProviderDefaults( o ) +{ + let self = this; + + _.assert( _.mapIs( o ), 'Expects options map { o }' ); + _.assert( o.verbosity !== null, 'Verbosity was not set to provider default' ); + + for( let k in self.ProviderDefaults ) + { + if( o[ k ] === null ) + if( self[ k ] !== undefined && self[ k ] !== null ) + _.assert( 0, k, 'was not set to provider default' ); + } + +} + +// + +function _preFilePathScalarWithoutProviderDefaults( routine, args ) +{ + let self = this; + // let path = self.system ? self.system.path : self.path; + /* + Dmytro : the provider should know about its paths, + the system provider handle several different providers and for some path can return wrong result + */ + + let path = self.path; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.object.isBasic( args[ 0 ] ) || path.is( args[ 0 ] ), 'Expects options map or path' ); + _.assert( args && args.length === 1, `Routine ${ routine.name } expects exactly one argument` ); + + let o = args[ 0 ]; + + if( path.like( o ) ) + o = { filePath : path.from( o ) }; + + _.routine.optionsWithoutUndefined( routine, o ); /* xxx : qqq : repalce by _.routine.options */ + + o.filePath = path.normalize( o.filePath ); + + _.assert( path.isAbsolute( o.filePath ), () => `Expects absolute path {-o.filePath-}, but got ${ _.strQuote( o.filePath ) }` ); + + return o; +} + +// + +function _preFilePathScalarWithProviderDefaults( routine, args ) +{ + let self = this; + + if( _.object.isBasic( args[ 0 ] ) ) + if( args[ 0 ].verbosity !== undefined ) + if( routine.defaults.logger !== undefined ) + { + _global_.logger.styleSet( 'negative' ); + _global_.logger.warn( 'Option verbosity will be deprecated. Please use option logger.' ) + _global_.logger.styleSet( 'default' ); + args[ 0 ].logger = args[ 0 ].verbosity; + delete args[ 0 ].verbosity; + } + + let o = self._preFilePathScalarWithoutProviderDefaults.apply( self, arguments ); + self._providerDefaultsApply( o ); + + return o; +} + +// + +function _preFilePathVectorWithoutProviderDefaults( routine, args ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args && args.length === 1, `Routine ${ routine.name } expects exactly one argument` ); + + let o = args[ 0 ]; + + if( path.like( o ) ) + o = { filePath : args[ 0 ] }; + else if( _.arrayIs( o ) ) + o = { filePath : args[ 0 ] }; + + if( _.arrayIs( o.filePath ) ) + o.filePath = path.s.from( o.filePath ); + else + o.filePath = path.from( o.filePath ); + + _.routine.options_( routine, o ); + _.assert( path.s.allAreAbsolute( o.filePath ), () => `Expects absolute path {-o.filePath-}, but got "${ o.filePath }"` ); + + o.filePath = path.s.normalize( o.filePath ); + + return o; +} + +// + +function _preFilePathVectorWithProviderDefaults( routine, args ) +{ + let self = this; + + let o = self._preFilePathVectorWithoutProviderDefaults.apply( self, arguments ); + self._providerDefaultsApply( o ); + + return o; +} + +// + +function _preFileFilterWithoutProviderDefaults( routine, args ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args && args.length === 1, 'Routine ' + routine.name + ' expects exactly one argument' ); + + let o = args[ 0 ]; + + _.routine.options_( routine, o ); + + o.src = self.recordFilter( o.src ); + + if( o.dst !== undefined && o.dst !== null ) + { + o.dst = self.recordFilter( o.dst ); + o.src.pairWithDst( o.dst ); + if( o.dst.recursive === null ) + { + _.assert( o.dst.formed < 5 ); + o.dst.recursive = 2; + } + } + + if( o.src.recursive === null && o.recursive !== null && o.recursive !== undefined ) + o.src.recursive = o.recursive; + if( o.recursive === null ) + o.src.recursive = o.recursive; + + o.src._formPaths(); + if( o.dst ) + o.dst._formPaths(); + o.src.effectiveProvider._providerDefaultsApply( o ); + + return o; +} + +// + +function _preFileFilterWithProviderDefaults( routine, args ) +{ + let self = this; + let o = self._preFileFilterWithoutProviderDefaults.apply( self, arguments ); + self._providerDefaultsApply( o ); + return o; +} + +// + +function _preSrcDstPathWithoutProviderDefaults( routine, args ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 || args.length === 2, 'Routine ' + routine.name + ' expects one or two arguments' ); + + let o = args[ 0 ]; + + if( path.like( args[ 0 ] ) || path.like( args[ 1 ] ) ) + o = { dstPath : args[ 0 ], srcPath : ( args.length > 1 ? args[ 1 ] : null ) } + + _.routine.options_( routine, o ); + + if( o.dstPath !== null ) + { + o.dstPath = path.s.from( o.dstPath ); + o.dstPath = path.s.canonize( o.dstPath ); + } + + if( o.srcPath !== null ) + { + o.srcPath = path.s.from( o.srcPath ); + o.srcPath = path.s.canonize( o.srcPath ); + } + + return o; +} + +// + +function _preSrcDstPathWithProviderDefaults( routine, args ) +{ + let self = this; + + let o = self._preSrcDstPathWithoutProviderDefaults.apply( self, arguments ); + self._providerDefaultsApply( o ); + + return o; +} + +// + +function protocolsForOrigins( origins ) +{ + if( origins === null ) + return origins; + + if( _.arrayIs( origins ) ) + return origins.map( ( origin ) => self.protocolsForOrigins( origin ) ); + _.assert( _.strIs( origins ) ); + return _.strRemoveEnd( _.strRemoveEnd( origins, '//' ), ':' ); +} + +// + +function originsForProtocols( protocols ) +{ + if( _.arrayIs( protocols ) ) + return protocols.map( ( protocol ) => self.originsForProtocols( protocol ) ); + _.assert( _.strIs( protocols ) ); + return protocols + '://'; +} + +// + +function providerForPath( path ) +{ + let self = this; + _.assert( _.strIs( path ), 'Expects string' ); + _.assert( !self.path.isGlobal( path ), () => 'Path for the file provider should be local, but is ' + _.strQuote( path ) ); + return self; +} + +// + +function providerRegisterTo( system ) +{ + let self = this; + system.providerRegister( self ); + return self; +} + +// + +function providerUnregister() +{ + let self = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + if( self.system ) + self.system.providerUnregister( self ); + return self; +} + +// + +function hasProvider( provider ) +{ + let self = this; + _.assert( arguments.length === 1 ); + return self === provider; +} + +// -- +// path +// -- + +function preferredFromGlobalAct( globalPath ) +{ + let self = this; + + if( _.boolLike( globalPath ) ) + return globalPath; + + if( _.strIs( globalPath ) ) + { + if( !_.path.isGlobal( globalPath ) ) + return globalPath; + globalPath = _.uri.parse( globalPath ); + } + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.mapIs( globalPath ) ) ; + _.assert( _.strIs( globalPath.longPath ) ); + _.assert + ( + !self.protocols || !globalPath.protocol || _.longHas( self.protocols, globalPath.protocol ), + () => 'File provider ' + self.qualifiedName + ' does not support protocol ' + _.strQuote( globalPath.protocol ) + ); + + if( self.usingGlobalPath ) + return globalPath.full; + else + return globalPath.postfixedPath; +} + +// + +function globalFromPreferredAct( localPath ) +{ + let self = this; + let path = self.system ? self.system.path : self.path; + // let path = self.path.parse ? self.path : _.uri; /* yyy */ + + if( _.boolLike( localPath ) ) + return localPath; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( localPath ) ) + _.assert( !self.protocols.length || _.strIs( self.originPath ) ); + + if( self.originPath ) + { + if( path.parse ) + return path.join( self.originPath, localPath ); + else if( _.uri ) + return _.uri.join( self.originPath, localPath ); + else + return self.originPath + localPath; + } + else + { + return localPath; + } + + // if( self.originPath && path.parse ) + // return path.join( self.originPath, localPath ); + // else if( self.originPath ) + // return self.originPath + localPath; + // else + // return localPath; + + // if( self.originPath ) + // return path.join( self.originPath, localPath ); + // else + // return localPath; +} + +// + +function pathNativizeAct( filePath ) +{ + let self = this; + _.assert( _.strIs( filePath ), 'Expects string' ) ; + return filePath; +} + +var having = pathNativizeAct.having = Object.create( null ); +having.writing = 0; +having.reading = 0; +having.driving = 1; +having.kind = 'path'; + +// + +let pathCurrentAct = null; + +// + +function pathDirTempAct() +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + return '/temp'; +} + +// + +function pathAllowedAct( filePath ) +{ + _.assert( _.strIs( filePath ), 'Expects string' ) ; + return true; +} + +// + +function pathForCopy_head( routine, args ) +{ + let self = this; + + _.assert( args.length === 1 ); + + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { path : o }; + + _.routine.options_( routine, o ); + _.assert( self instanceof _.FileProvider.Abstract ); + _.assert( _.strIs( o.path ) ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + return o; +} + +// + +function pathForCopy_body( o ) +{ + const fileProvider = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let postfix = _.strPrependOnce( o.postfix, o.postfix ? '-' : '' ); + let file = fileProvider.recordFactory().record( o.path ); + let name = file.name; + + let splits = _.strSplitFast({ src : name, delimeter : '-', preservingEmpty : 0, preservingDelimeters : 0 }); + if( splits[ splits.length-1 ] === o.postfix ) + name = splits.slice( 0, splits.length-1 ).join( '-' ); + + // !!! this condition (first if below) is not necessary, because if it fulfilled then previous fulfiled too, and has the + // same effect as previous + + if( splits.length > 1 && splits[ splits.length-1 ] === o.postfix ) + name = splits.slice( 0, splits.length-1 ).join( '-' ); + else if( splits.length > 2 && splits[ splits.length-2 ] === o.postfix ) + name = splits.slice( 0, splits.length-2 ).join( '-' ); + + /*file.absolute = file.dir + '/' + file.name + file.extWithDot;*/ + + const path = fileProvider.path.join( file.dir, name + postfix + file.extWithDot ); + if( !fileProvider.statResolvedRead({ filePath : path, sync : 1 }) ) + return path; + + let attempts = 1 << 13; + let index = 1; + + while( attempts > 0 ) + { + + const path = fileProvider.path.join( file.dir, name + postfix + '-' + index + file.extWithDot ); + + if( !fileProvider.statResolvedRead({ filePath : path, sync : 1 }) ) + return path; + + attempts -= 1; + index += 1; + + } + + throw _.err( 'Cant make copy path for : ' + file.absolute ); +} + +pathForCopy_body.defaults = +{ + delimeter : '-', + postfix : 'copy', + path : null, +} + +var having = pathForCopy_body.having = Object.create( null ); +having.driving = 0; +having.aspect = 'body'; + +// + +let pathResolveSoftLinkAct = Object.create( null ); +pathResolveSoftLinkAct.name = 'pathResolveSoftLinkAct'; + +var defaults = pathResolveSoftLinkAct.defaults = Object.create( null ); +defaults.filePath = null; + +var having = pathResolveSoftLinkAct.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 1; + +var operates = pathResolveSoftLinkAct.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 }; + +// + +function pathResolveSoftLink_body( o ) +{ + let self = this; + + _.assert( _.routineIs( self.pathResolveSoftLinkAct ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( !!o.filePath ); + + if( o.resolvingIntermediateDirectories ) + return resolvingIntermediateDirectories(); + + if( !self.fileExists( o.filePath ) ) + { + if( o.allowingMissed ) + return o.filePath; + else + return handleError( 'o.filePath:', o.filePath, 'doesn\`t exist.' ); + } + + if( !o.resolvingMultiple ) + return o.filePath; + + if( !o.results ) + o.results = [ o.filePath ]; + if( !o.found ) + o.found = [ o.filePath ]; + + let actOptions = _.mapOnly_( null, o, pathResolveSoftLinkAct.defaults ); + + let result = self.pathResolveSoftLinkAct( actOptions ); + result = self.path.normalize( result ); + + o.found.push( result ); + + result = self.path.join( o.filePath, result ); + + if( !self.fileExists( result ) ) + { + if( o.allowingMissed ) + return end(); + else + return handleError( 'FilePath:', result, 'doesn\`t exist.' ); + } + + if( !self.isSoftLink( result ) ) + { + if( o.resolvingMultiple === 2 ) + return end2(); + return end(); + } + + if( o.results.length ) + { + if( _.longHas( o.results, result ) ) + { + if( !o.allowingCycled ) + return handleError( 'Cycle at:', o.results[ o.results.length - 1 ], 'doesn\`t exist.' ); + if( o.resolvingMultiple === 1 ) + return end(); + return end2(); + } + } + + if( o.resolvingMultiple === 1 ) + return end(); + + o.results.push( result ); + + o.filePath = result; + + return pathResolveSoftLink_body.call( self, o ); + + /* */ + + function end() + { + let found = o.found[ o.found.length - 1 ]; + if( self.path.isRelative( found ) ) + { + if( o.results[ 0 ] !== result ) + result = self.path.relative( o.results[ 0 ], result ); + else + result = found; + } + return result; + } + + function end2() + { + let found = o.found[ o.found.length - 2 ]; + if( self.path.isRelative( found ) ) + { + result = found; + if( o.results[ 0 ] !== o.filePath ) + result = self.path.relative( o.results[ 0 ], o.filePath ); + } + else + { + result = o.results[ o.results.length - 1 ]; + } + return result; + } + + function resolvingIntermediateDirectories() + { + let splits = self.path.split( o.filePath ); + let o2 = _.props.extend( null, o ); + + o2.resolvingIntermediateDirectories = 0; + o2.filePath = '/'; + + for( let i = 1 ; i < splits.length ; i++ ) + { + o2.filePath = self.path.join( o2.filePath, splits[ i ] ); + let result = pathResolveSoftLink_body.call( self, _.mapOnly_( null, o2, pathResolveSoftLink_body.defaults ) ); + o2.filePath = self.path.join( o2.filePath, result ); + } + return o2.filePath; + } + + function handleError() + { + if( o.throwing ) + throw _.err.apply( _, arguments ); + return null; + } +} + +_.routineExtend( pathResolveSoftLink_body, pathResolveSoftLinkAct ); + +var defaults = pathResolveSoftLink_body.defaults; + +defaults.allowingMissed = 1; +defaults.allowingCycled = 1; +defaults.resolvingIntermediateDirectories = 0; +defaults.resolvingMultiple = 1; +defaults.throwing = 0; + +var having = pathResolveSoftLink_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let pathResolveSoftLink = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, pathResolveSoftLink_body ); + +var having = pathResolveSoftLink.having; +having.aspect = 'entry'; + +// + +let pathResolveTextLinkAct = Object.create( null ); +pathResolveTextLinkAct.name = 'pathResolveTextLinkAct'; + +var defaults = pathResolveTextLinkAct.defaults = Object.create( null ); +defaults.filePath = null; + +var having = pathResolveTextLinkAct.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 1; + +var operates = pathResolveTextLinkAct.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 }; + +// + +function pathResolveTextLink_head( routine, args ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { filePath : o }; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1, 'Expects single argument for', routine.name ); + _.routine.options_( routine, o ); + _.assert( _.strIs( o.filePath ), 'Expects string' ); + + return o; +} + +// + +function pathResolveTextLink_body( o ) +{ + let self = this; + + _.assert( _.routineIs( self.pathResolveTextLinkAct ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( !!o.filePath ); + + if( !self.usingTextLink ) + return o.filePath; + + if( o.resolvingIntermediateDirectories ) + return resolvingIntermediateDirectories(); + + if( !self.fileExists( o.filePath ) ) + { + if( o.allowingMissed ) + return o.filePath; + else + return handleError( 'o.filePath:', o.filePath, 'doesn\`t exist.' ); + } + + if( !o.resolvingMultiple ) + return o.filePath; + + if( !o.results ) + o.results = [ o.filePath ]; + if( !o.found ) + o.found = [ o.filePath ]; + + let actOptions = _.mapOnly_( null, o, pathResolveTextLinkAct.defaults ); + + let result = self.pathResolveTextLinkAct( actOptions ); + + if( !result ) + result = o.filePath; + + result = self.path.normalize( result ); + + o.found.push( result ); + + result = self.path.join( o.filePath, result ); + + if( !self.fileExists( result ) ) + { + if( o.allowingMissed ) + return end(); + else + return handleError( 'FilePath:', result, 'doesn\`t exist.' ); + } + + if( !self.isTextLink( result ) ) + { + if( o.resolvingMultiple === 2 ) + return end2(); + return end(); + } + + if( o.results.length ) + { + if( _.longHas( o.results, result ) ) + { + if( !o.allowingCycled ) + return handleError( 'Cycle at:', o.results[ o.results.length - 1 ], 'doesn\`t exist.' ); + if( o.resolvingMultiple === 1 ) + return end(); + return end2(); + } + } + + if( o.resolvingMultiple === 1 ) + return end(); + + o.results.push( result ); + + o.filePath = result; + + return pathResolveTextLink_body.call( self, o ); + + /* */ + + function end() + { + let found = o.found[ o.found.length - 1 ]; + if( self.path.isRelative( found ) ) + { + if( o.results[ 0 ] !== result ) + result = self.path.relative( o.results[ 0 ], result ); + else + result = found; + } + return result; + } + + function end2() + { + let found = o.found[ o.found.length - 2 ]; + if( self.path.isRelative( found ) ) + { + result = found; + if( o.results[ 0 ] !== o.filePath ) + result = self.path.relative( o.results[ 0 ], o.filePath ); + } + else + { + result = o.results[ o.results.length - 1 ]; + } + return result; + } + + function resolvingIntermediateDirectories() + { + let splits = self.path.split( o.filePath ); + let o2 = _.props.extend( null, o ); + + o2.resolvingIntermediateDirectories = 0; + o2.filePath = '/'; + + for( let i = 1 ; i < splits.length ; i++ ) + { + o2.filePath = self.path.join( o2.filePath, splits[ i ] ); + if( self.isTextLink( o2.filePath ) ) + { + let result = pathResolveTextLink_body.call( self, _.mapOnly_( null, o2, pathResolveTextLink_body.defaults ) ); + o2.filePath = self.path.join( o2.filePath, result ); + } + } + return o2.filePath; + } + + function handleError() + { + if( o.throwing ) + throw _.err.apply( _, arguments ); + return null; + } +} + +_.routineExtend( pathResolveTextLink_body, pathResolveTextLinkAct ); + +var defaults = pathResolveTextLink_body.defaults; + +defaults.allowingMissed = 1; +defaults.allowingCycled = 1; +defaults.resolvingMultiple = 1; +defaults.resolvingIntermediateDirectories = 0; +defaults.throwing = 0; + +var having = pathResolveTextLink_body.having; +having.driving = 0; +having.aspect = 'body'; + +let pathResolveTextLink = _.routine.uniteCloning_replaceByUnite( pathResolveTextLink_head, pathResolveTextLink_body ); + +// + +let _pathResolveLink = Object.create( null ); + +var defaults = _pathResolveLink.defaults = Object.create( null ); +defaults.filePath = null; +defaults.resolvingSoftLink = null; +defaults.resolvingTextLink = null; +defaults.throwing = 1; +defaults.allowingMissed = 1; +defaults.allowingCycled = 1; + +var having = _pathResolveLink.having = Object.create( null ); +having.driving = 0; +having.aspect = 'body'; +having.hubRedirecting = 0; + +var operates = _pathResolveLink.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 }; + +// + +function pathResolveLinkStep_head() +{ + let self = this; + let o = self._preFilePathScalarWithProviderDefaults.apply( self, arguments ); + return o; +} + +function pathResolveLinkStep_body( o ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + + if( o.resolvingSoftLink ) + { + let o2 = o2From( o ); + let filePath = o2.filePath; + let result = self.pathResolveSoftLink( o2 ); + + if( o.resolvingTextLink ) + if( result === filePath ) + { + let o2 = o2From( o ); + result = self.pathResolveTextLink( o2 ); + } + + return handleResult( result ); + } + else if( o.resolvingTextLink ) + { + let o2 = o2From( o ); + let result = self.pathResolveTextLink( o2 ); + return handleResult( result ); + } + + return handleResult( o.filePath ); + + function o2From( o ) + { + let o2 = _.props.extend( null, o ); + delete o2.resolvingTextLink; + delete o2.resolvingSoftLink; + delete o2.relativeOriginalFile; + delete o2.preservingRelative; + /* qqq : enable options "throwing", "allowingMissed", "allowingCycled" */ + // delete o2.throwing; + // delete o2.allowingMissed; + // delete o2.allowingCycled; + /* qqq */ + return o2; + } + + function handleResult( result ) + { + result = + { + filePath : result, + relativePath : result, + absolutePath : result + } + + if( result.relativePath ) + if( self.path.isRelative( result.relativePath ) ) + { + result.absolutePath = self.path.join( o.filePath, result.relativePath ) + if( o.relativeOriginalFile ) + if( o.filePath !== result.absolutePath ) + result.filePath = result.relativePath = self.path.relative( o.filePath, result.absolutePath ); + if( !o.preservingRelative ) + result.filePath = result.relativePath = result.absolutePath; + } + + return result; + } + +} + +_.routineExtend( pathResolveLinkStep_body, _pathResolveLink ); + +var defaults = pathResolveLinkStep_body.defaults; + +defaults.relativeOriginalFile = 0; +defaults.preservingRelative = 0; + +let pathResolveLinkStep = _.routine.uniteCloning_replaceByUnite( pathResolveLinkStep_head, pathResolveLinkStep_body ); +pathResolveLinkStep.having.aspect = 'entry'; + +// + +function pathResolveLinkFull_head() +{ + let self = this; + let o = self._preFilePathScalarWithProviderDefaults.apply( self, arguments ); + return o; +} + +function pathResolveLinkFull_body( o ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + let result = Object.create( null ); + result.filePath = o.filePath; + result.absolutePath = o.filePath; + result.relativePath = o.filePath; + + _.assert( _.routineIs( self.pathResolveLinkTailChain.body ) ); + _.assert( path.isAbsolute( o.filePath ) ); + _.assert( !!o.resolvingHeadDirect ); + _.assert( !!o.resolvingHeadReverse ); + _.assert( _.boolLike( o.throwing ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( pathResolveLinkFull_body, arguments ); + + let system = o.system || self.system; + if( system && system !== self && path.isGlobal( o.filePath ) ) + return system.pathResolveLinkFull.body.call( system, o ); + + if( o.sync ) + return _pathResolveLinkFullSync(); + else + return _pathResolveLinkFullAsync(); + + /* */ + + function _resolve() + { + + try + { + + if( !o.resolvingSoftLink && ( !o.resolvingTextLink || !self.usingTextLink ) ) + { + + if( o.stat ) + return result; + + if( !o.allowingMissed ) + { + result.relativePath = result.filePath = result.absolutePath = null; + result.isMissed = true; + if( o.throwing ) + { + throw _.err( 'File does not exist', _.strQuote( o.filePath ) ); + } + } + + return result; + } + + if( o.resolvingHeadDirect ) + { + + let o2 = + { + system, + filePath : result.absolutePath, + resolvingSoftLink : o.resolvingSoftLink, + resolvingTextLink : o.resolvingTextLink, + allowingMissed : o.allowingMissed, + allowingCycled : o.allowingCycled, + throwing : o.throwing, + recursive : o.recursive, + stat : null, + } + + result.relativePath = result.filePath = result.absolutePath = self.pathResolveLinkHeadDirect.body.call( self, o2 ); + + } + + if( result ) + { + + let o2 = + { + stat : o.stat, + system, + filePath : result.absolutePath, + resolvingSoftLink : o.resolvingSoftLink, + resolvingTextLink : o.resolvingTextLink, + preservingRelative : true, + allowingMissed : o.allowingMissed, + allowingCycled : o.allowingCycled, + recursive : o.recursive, + throwing : o.throwing, + } + + let r = self.pathResolveLinkTail.body.call( self, o2 ); + if( r.relativePath && o.relativeOriginalFile ) + { + if( path.isRelative( r.relativePath ) ) + r.relativePath = path.relative( o.filePath, r.absolutePath ); + if( path.isRelative( r.filePath ) ) + r.filePath = r.relativePath; + } + + if( !o.preservingRelative ) + r.filePath = r.absolutePath; + + result = r; + o.stat = o2.stat; + _.assert( o.stat !== undefined ); + + } + else + { + if( !o.allowingMissed ) + { + result.relativePath = result.filePath = result.absolutePath = null; + result.isMissed = true; + if( o.throwing ) + { + throw _.err( 'File does not exist', _.strQuote( o.filePath ) ); + } + return result; + } + } + + if( o.stat && o.resolvingHeadReverse ) + { + + let o2 = + { + system, + filePath : result.absolutePath, + resolvingSoftLink : o.resolvingSoftLink, + resolvingTextLink : o.resolvingTextLink, + allowingMissed : o.allowingMissed, + allowingCycled : o.allowingCycled, + recursive : o.recursive, + throwing : o.throwing, + } + + let r = self.pathResolveLinkHeadReverse.body.call( self, o2 ); + if( r !== result.absolutePath ) + { + result.filePath = result.absolutePath = r; + + if( r.relativePath && o.relativeOriginalFile ) + { + if( path.isRelative( result.relativePath ) ) + result.relativePath = path.relative( o.filePath, result.absolutePath ); + if( path.isRelative( result.filePath ) ) + result.filePath = r.relativePath; + } + + if( !path.isRelative( result.relativePath ) ) + result.relativePath = result.absolutePath; + else if( o.preservingRelative ) + result.filePath = result.relativePath; + } + } + + if( result.relativePath !== null && !path.isRelative( result.relativePath ) ) + result.relativePath = path.relative( o.filePath, result.relativePath ); + return result; + } + catch( err ) + { + throw _.err( `Failed to resolve ${o.filePath}\n`, err ); + } + } + + /* */ + + function _statRead() + { + try + { + + /* + statRead should be before resolving + because resolving does not guarantee reading stat + */ + + if( !o.stat ) + o.stat = self.statReadAct + ({ + filePath : result.absolutePath, + throwing : 0, + resolvingSoftLink : 0, + sync : 1, + }); + + return o.stat; + } + catch( err ) + { + result.relativePath = result.filePath = result.absolutePath = null; + result.isMissed = true; + throw _.err( `Failed to resolve ${o.filePath}\n`, err ); + } + + } + + /* */ + + function _pathResolveLinkFullSync() + { + _statRead(); + return _resolve(); + } + + /* */ + + function _pathResolveLinkFullAsync() + { + let con = new _.Consequence().take( null ); + + if( !o.stat ) + con.then( () => + { + return _statRead(); + }) + + con.then( ( stat ) => + { + o.stat = stat; + return _resolve(); + }) + + return con; + } + +} + +_.routineExtend( pathResolveLinkFull_body, _pathResolveLink ); + +var defaults = pathResolveLinkFull_body.defaults; + +defaults.system = null; +defaults.stat = null; +defaults.sync = null; +defaults.resolvingHeadDirect = 1; +defaults.resolvingHeadReverse = 1; +defaults.preservingRelative = 0; /* xxx : qqq : set to 1 */ +defaults.relativeOriginalFile = 0; +defaults.recursive = 3; /* 0, 1, 2, 3 */ + +/* +qqq : cover option relativeOriginalFile + +qqq : cover pathResolveLinkFull preservingRelative:1 + all routines having option preservingRelative should return map with 3 paths + not string! +qqq : even if preservingRelative:1 result.relativePath should be relative ( if link was relative ) + otherwise result.relativePath is absolute +*/ + +// + +let pathResolveLinkFull = _.routine.uniteCloning_replaceByUnite( pathResolveLinkFull_head, pathResolveLinkFull_body ); +pathResolveLinkFull.having.aspect = 'entry'; + +// + +function pathResolveLinkTail_head() +{ + let self = this; + let o = self._preFilePathScalarWithProviderDefaults.apply( self, arguments ); + + return o; +} + +// + +function pathResolveLinkTail_body( o ) +{ + let self = this; + + _.assert( _.routineIs( self.pathResolveLinkTailChain.body ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( pathResolveLinkTail_body, arguments ); + + let o2 = _.props.extend( null, o ); + o2.found = []; + o2.result = [ o.filePath ]; + let r = self.pathResolveLinkTailChain.body.call( self, o2 ); + o.stat = o2.stat; + + let result = Object.create( null ); + + result.filePath = o2.result[ o2.result.length-1 ]; + result.relativePath = o2.result[ o2.result.length-1 ]; + result.absolutePath = o2.found[ o2.found.length-1 ]; + + if( result.filePath === null ) + { + let cycle = false; + if( o2.found.length > 2 ) + cycle = _.longRightIndex( o2.found, o2.found[ o2.found.length-2 ], o2.found.length-3 ) !== -1; + if( cycle && o.allowingCycled || !cycle && o.allowingMissed ) + { + result.filePath = o2.result[ o2.result.length-2 ]; + result.relativePath = o2.result[ o2.result.length-2 ]; + result.absolutePath = o2.found[ o2.found.length-2 ]; + result.isCycled = !!cycle; + } + } + + _.assert( result.filePath === null || _.strIs( result.filePath ) ); + _.assert( result.relativePath === null || _.strIs( result.relativePath ) ); + _.assert( result.absolutePath === null || _.strIs( result.absolutePath ) ); + + return result; +} + +_.routineExtend( pathResolveLinkTail_body, _pathResolveLink ); + +var defaults = pathResolveLinkTail_body.defaults; + +defaults.system = null; +defaults.stat = null; +defaults.preservingRelative = 0; +defaults.recursive = 3; + +// + +let pathResolveLinkTail = _.routine.uniteCloning_replaceByUnite( pathResolveLinkTail_head, pathResolveLinkTail_body ); +pathResolveLinkTail.having.aspect = 'entry'; + +// + +function pathResolveLinkTailChain_head() +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + let o = self._preFilePathScalarWithProviderDefaults.apply( self, arguments ); + + _.assert( path.isAbsolute( o.filePath ) ); + + if( o.found === null ) + o.found = []; + + if( o.result === null ) + o.result = [ o.filePath ]; + + return o; +} + +// + +/* + - both o.found and o.result have no duplicates, except case when link is cycled + - o.found has only absolute paths, always + - o.result has corresponding element before the iteration starts, the iteration check o.found and put new element ot o.found +*/ + +function pathResolveLinkTailChain_body( o ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.boolLike( o.resolvingSoftLink ) || _.numberIs( o.resolvingSoftLink ) ); + _.assert( _.boolLike( o.resolvingTextLink ) || _.numberIs( o.resolvingTextLink ) ); + _.assert( _.boolLike( o.allowingMissed ) ); + _.assert( _.boolLike( o.allowingCycled ) ); + _.assert( _.boolLike( o.throwing ) ); + _.assert( _.arrayIs( o.found ) ); + _.assert( _.arrayIs( o.result ) ); + _.assert( path.isAbsolute( o.filePath ) ); + _.routine.assertOptions( pathResolveLinkTailChain_body, arguments ); + + let system = o.system || self.system; + if( system && system !== self && path.isGlobal( o.filePath ) ) + return system.pathResolveLinkTailChain.body.call( system, o ); + + if( _.longHas( o.found, o.filePath ) ) + { + if( o.throwing && !o.allowingCycled ) + { + throw _.err( 'Links cycle at', _.strQuote( o.filePath ) ); + } + else + { + o.found.push( o.filePath, null ); + o.result.push( null ); + + if( o.allowingCycled ) + o.stat = self.statReadAct + ({ + filePath : o.filePath, + throwing : 0, + resolvingSoftLink : 0, + sync : 1, + }); + + return o.result; + } + } + + o.found.push( o.filePath ); + + /* + condition to avoid recursion in stat and overburden + pathResolveLinkTail does not guarantee reading stat + */ + + if( !o.resolvingSoftLink && ( !o.resolvingTextLink || !self.usingTextLink ) ) + { + return o.result; + } + + /* */ + + if( !o.stat ) + o.stat = self.statReadAct + ({ + filePath : o.filePath, + throwing : 0, + resolvingSoftLink : 0, + sync : 1, + }); + + /* */ + + if( o.recursive === 2 ) + if( o.result.length > 1 ) + { + let returnLastLink = o.stat ? !o.stat.isLink() : true; + if( returnLastLink ) + { + o.result.pop(); + o.found.pop(); + return o.result; + } + } + + /* */ + + if( !o.stat ) + { + o.result.push( null ); + o.found.push( null ); + + // should throw error if any part of chain does not exist + if( o.throwing && !o.allowingMissed ) + { + throw _.err( 'Does not exist file', _.strQuote( o.filePath ) ); + } + + return o.result; + } + + /* */ + + if( !o.recursive ) + return o.result; + + /* */ + + if( o.recursive === 1 ) + if( o.result.length > 1 ) + return o.result; + + /* */ + + if( o.resolvingSoftLink && o.stat.isSoftLink() ) + { + let filePath = self.pathResolveSoftLink({ filePath : o.filePath }); + if( o.preservingRelative && !path.isAbsolute( filePath ) ) + { + o.result.push( filePath ); + o.filePath = path.join( o.filePath, filePath ); + } + else + { + o.filePath = path.join( o.filePath, filePath ) + o.result.push( o.filePath ); + } + o.stat = null; + return self.pathResolveLinkTailChain.body.call( self, o ); + } + + /* */ + + if( self.usingTextLink ) + if( o.resolvingTextLink && o.stat.isTextLink() ) + { + let filePath = self.pathResolveTextLink({ filePath : o.filePath }); + if( o.preservingRelative && !path.isAbsolute( filePath ) ) + { + o.result.push( filePath ); + o.filePath = path.join( o.filePath, filePath ) + } + else + { + o.filePath = path.join( o.filePath, filePath ) + o.result.push( o.filePath ); + } + o.stat = null; + return self.pathResolveLinkTailChain.body.call( self, o ); + } + + return o.result; +} + +_.routineExtend( pathResolveLinkTailChain_body, pathResolveLinkTail.body ); + +var defaults = pathResolveLinkTailChain_body.defaults; +defaults.result = null; +defaults.found = null; + +// + +let pathResolveLinkTailChain = _.routine.uniteCloning_replaceByUnite( pathResolveLinkTailChain_head, pathResolveLinkTailChain_body ); +pathResolveLinkTailChain.having.aspect = 'entry'; + +// + +function pathResolveLinkHeadDirect_head() +{ + let self = this; + let o = self._preFilePathScalarWithProviderDefaults.apply( self, arguments ); + return o; +} + +// + +function pathResolveLinkHeadDirect_body( o ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.boolLike( o.resolvingSoftLink ) || _.numberIs( o.resolvingSoftLink ) ); + _.assert( _.boolLike( o.resolvingTextLink ) || _.numberIs( o.resolvingTextLink ) ); + _.assert( _.boolLike( o.allowingMissed ) ); + _.assert( _.boolLike( o.allowingCycled ) ); + _.assert( _.boolLike( o.throwing ) ); + _.assert( path.isAbsolute( o.filePath ) ); + _.routine.assertOptions( pathResolveLinkHeadDirect_body, arguments ); + + let system = o.system || self.system; + if( system && system !== self && path.isGlobal( o.filePath ) ) + return system.pathResolveLinkHeadDirect.body.call( system, o ); + + if( !o.resolvingSoftLink && ( !o.resolvingTextLink || !self.usingTextLink ) ) + return o.filePath; + + let splits = path.split( o.filePath ); + let filePath = '/'; + let o2 = _.props.extend( null, o ); + + for( let i = 1 ; i < splits.length ; i++ ) + { + + if( i === splits.length-1 ) + { + filePath = path.join( filePath, splits[ i ] ); + break; + } + + filePath = path.join( filePath, splits[ i ] ); + o2.filePath = filePath; + o2.stat = null; + o2.preservingRelative = 0; + if( i === splits.length-1 ) + o2.stat = o.stat; + + if( !o2.stat ) + o2.stat = self.statReadAct + ({ + filePath, + throwing : 0, + sync : 1, + resolvingSoftLink : 0, + }); + + if( !o2.stat ) + { + filePath = path.join.apply( path, _.arrayAppendArrays( [], [ filePath, splits.slice( i+1 ) ] ) ); + o.stat = null; + break; + } + + if + ( + ( o2.resolvingSoftLink && o2.stat.isSoftLink() ) + || ( o2.resolvingTextLink && self.usingTextLink && o2.stat.isTextLink() ) + ) + { + filePath = self.pathResolveLinkTail.body.call( self, o2 ).absolutePath; + } + if( i === splits.length - 1 ) + { + o.stat = o2.stat; + } + } + + return filePath; +} + +_.routineExtend( pathResolveLinkHeadDirect_body, _pathResolveLink ); + +var defaults = pathResolveLinkHeadDirect_body.defaults; + +defaults.system = null; +defaults.stat = null; +defaults.recursive = 3; + +// + +let pathResolveLinkHeadDirect = _.routine.uniteCloning_replaceByUnite( pathResolveLinkHeadDirect_head, pathResolveLinkHeadDirect_body ); +pathResolveLinkHeadDirect.having.aspect = 'entry'; + +// + +function pathResolveLinkHeadReverse_head() +{ + let self = this; + let o = self._preFilePathScalarWithProviderDefaults.apply( self, arguments ); + return o; +} + +// + +function pathResolveLinkHeadReverse_body( o ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.boolLike( o.resolvingSoftLink ) || _.numberIs( o.resolvingSoftLink ) ); + _.assert( _.boolLike( o.resolvingTextLink ) || _.numberIs( o.resolvingTextLink ) ); + _.assert( _.boolLike( o.allowingMissed ) ); + _.assert( _.boolLike( o.allowingCycled ) ); + _.assert( _.boolLike( o.throwing ) ); + _.assert( path.isAbsolute( o.filePath ) ); + _.routine.assertOptions( pathResolveLinkHeadReverse_body, arguments ); + + let system = o.system || self.system; + if( system && system !== self && path.isGlobal( o.filePath ) ) + return system.pathResolveLinkHeadReverse.body.call( system, o ); + + /* Vova: qqq: should not resolve last part of the filePath? */ + + if( path.isRoot( o.filePath ) ) + return o.filePath; + + let prefixPath = path.dir( o.filePath ); + let postfixPath = ''; + + while( !path.isRoot( prefixPath ) ) + { + let o2 = _.props.extend( null, o ); + o2.filePath = prefixPath; + o2.preservingRelative = 0; + prefixPath = self.pathResolveLinkTail( o2 ).absolutePath; + postfixPath = path.join( path.fullName( prefixPath ), postfixPath ); + prefixPath = path.dir( prefixPath ); + _.assert( !_.strBegins( prefixPath, '/..' ) && !_.strHas( prefixPath, '///..' ) ) + } + + if( !postfixPath ) + return o.filePath; + + let result = '/' + postfixPath + '/' + path.fullName( o.filePath ); + + // if( path.parse ) + // result = ( path.parse( prefixPath ).origin || '' ) + result; + + if( path.parse ) + result = path.join( prefixPath, result ) + + return result; +} + +_.routineExtend( pathResolveLinkHeadReverse_body, _pathResolveLink ); + +var defaults = pathResolveLinkHeadReverse_body.defaults; + +defaults.system = null; +defaults.recursive = 3; + +// + +let pathResolveLinkHeadReverse = _.routine.uniteCloning_replaceByUnite( pathResolveLinkHeadReverse_head, pathResolveLinkHeadReverse_body ); +pathResolveLinkHeadReverse.having.aspect = 'entry'; + +// -- +// record +// -- + +function _recordFactoryFormEnd( recordFactory ) +{ + let self = this; + _.assert( recordFactory instanceof _.files.FileRecordFactory ); + _.assert( arguments.length === 1, 'Expects single argument' ); + return recordFactory; +} + +// + +function _recordFormBegin( record ) +{ + let self = this; + return record; +} + +// + +function _recordFormEnd( record ) +{ + let self = this; + return record; +} + +// + +function _recordAbsoluteGlobalMaybeGet( record ) +{ + let self = this; + _.assert( record instanceof _.files.FileRecord ); + _.assert( arguments.length === 1, 'Expects single argument' ); + return record.absolute; +} + +// + +function _recordRealGlobalMaybeGet( record ) +{ + let self = this; + _.assert( record instanceof _.files.FileRecord ); + _.assert( arguments.length === 1, 'Expects single argument' ); + return record.real; +} + +// + +function record( filePath ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + + if( filePath instanceof _.files.FileRecord ) + { + return filePath; + } + + _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); + + return self.recordFactory().record( filePath ); +} + +var having = record.having = Object.create( null ); + +having.writing = 0; +having.reading = 1; +having.driving = 0; +having.kind = 'record'; + +// + +function _recordsSort( o ) +{ + let self = this; + + if( arguments.length === 1 ) + if( _.longIs( o ) ) + { + o = { src : o } + } + + if( arguments.length === 2 ) + { + o = + { + src : arguments[ 0 ], + sorter : arguments[ 1 ] + } + } + + if( _.strIs( o.sorter ) ) + { + let parseOptions = + { + src : o.sorter, + fields : { hardlinks : 1, modified : 1 } + } + o.sorter = _.strSorterParse( parseOptions ); + } + + _.routine.options_( _recordsSort, o ); + + _.assert( _.longIs( o.src ) ); + _.assert( _.longIs( o.sorter ) ); + + for( let i = 0; i < o.src.length; i++ ) + { + if( !( o.src[ i ] instanceof _.files.FileRecord ) ) + throw _.err( '_recordsSort : expects FileRecord instances in src, got:', _.entity.strType( o.src[ i ] ) ); + } + + let result = o.src.slice(); + + let knownSortMethods = [ 'modified', 'hardlinks' ]; + + for( let i = 0; i < o.sorter.length; i++ ) + { + let sortMethod = o.sorter[ i ][ 0 ]; + let sortByMax = o.sorter[ i ][ 1 ]; + + _.assert( knownSortMethods.indexOf( sortMethod ) !== -1, '_recordsSort : unknown sort method: ', sortMethod ); + + let routine = sortByMax ? _.entityMax : _.entityMin; + + if( sortMethod === 'hardlinks' ) + { + let selectedRecord = routine( result, ( record ) => record.stat ? record.stat.nlink : 0 ).element; + result = [ selectedRecord ]; + } + + if( sortMethod === 'modified' ) + { + let selectedRecord = routine( result, ( record ) => record.stat ? record.stat.mtime.getTime() : 0 ).element; + result = _.filter_( null, result, ( record ) => + { + if( record.stat && record.stat.mtime.getTime() === selectedRecord.stat.mtime.getTime() ) + return record; + }); + } + } + + _.assert( result.length === 1 ); + + return result[ 0 ]; +} + +_recordsSort.defaults = +{ + src : null, + sorter : null +} + +// + +function recordFactory( factory ) +{ + let self = this; + + factory = factory || Object.create( null ); + + if( factory instanceof _.files.FileRecordFactory ) + { + + if( !factory.system && self.system ) + factory.system = self.system; + + if( !factory.defaultProvider ) + factory.defaultProvider = self; + + return factory + } + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( !factory.defaultProvider ) + factory.defaultProvider = self; + + return _.files.FileRecordFactory( factory ); +} + +var having = recordFactory.having = Object.create( null ); +having.writing = 0; +having.reading = 0; +having.driving = 0; +having.kind = 'record'; + +// + +function recordFilter( filter ) +{ + let self = this; + + filter = filter || Object.create( null ); + + if( filter instanceof _.files.FileRecordFilter ) + { + + if( !filter.system && self.system ) + filter.system = self.system; + + if( !filter.defaultProvider ) + filter.defaultProvider = self; + + return filter + } + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + let filePath = null; + if( _.strIs( filter ) || _.arrayIs( filter ) ) + { + filePath = filter; + filter = {}; + } + + if( !filter.defaultProvider ) + filter.defaultProvider = self; + + let result = _.files.FileRecordFilter( filter ); + + if( filePath ) + result.copy( filePath ); + + return result; +} + +var having = recordFilter.having = Object.create( null ); +having.writing = 0; +having.reading = 0; +having.driving = 0; +having.kind = 'record'; + +// -- +// stat +// -- + +/* + zzz : statReadAct of Extract and HD handle links in head of path differently + HD always resolve them + add test routine statReadActLinkedHead + Vova : statReadActLinkedHead added, soft links are handled, text links need tests and implementation, low priority +*/ + +let statReadAct = Object.create( null ); +statReadAct.name = 'statReadAct'; + +var defaults = statReadAct.defaults = Object.create( null ); +defaults.filePath = null; +defaults.sync = null; +defaults.throwing = 0; +defaults.resolvingSoftLink = null; + +var having = statReadAct.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 1; + +var operates = statReadAct.operates = Object.create( null ); +operates.filePath = { pathToRead : 1, allowingMissed : 1 } + +// + +function statRead_body( o ) +{ + let self = this; + let result; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.routineIs( self.statReadAct ) ); + + let o2 = + { + filePath : o.filePath, + resolvingTextLink : o.resolvingTextLink, + resolvingSoftLink : o.resolvingSoftLink, + sync : o.sync, + throwing : o.throwing, + allowingMissed : 0, + allowingCycled : 0, + } + + try + { + result = self.pathResolveLinkFull( o2 ); + } + catch( err ) + { + if( !o.throwing ) + { + _.errAttend( err ); + return null; + } + throw _.err( err ); + } + + if( o.sync ) + { + return end( result ); + } + else + { + return result.then( end ); + } + + /* - */ + + function end( result ) + { + result = result.absolutePath; + + if( result === null ) + { + if( o.throwing ) + throw _.err( 'Failed to resolve' ); + else + return result; + } + + let stat = o2.stat; + if( stat ) + { + _.assert( _.routineIs( stat.isTerminal ), 'Stat should have routine isTerminal' ); + _.assert( _.routineIs( stat.isDir ), 'Stat should have routine isDir' ); + _.assert( _.routineIs( stat.isTextLink ), 'Stat should have routine isTextLink' ); + _.assert( _.routineIs( stat.isSoftLink ), 'Stat should have routine isSoftLink' ); + _.assert( _.routineIs( stat.isHardLink ), 'Stat should have routine isHardLink' ); + _.assert( _.strIs( stat.filePath ), 'Stat should have file path' ); + } + return stat; + } + +} + +_.routineExtend( statRead_body, statReadAct ); + +statRead_body.defaults.resolvingTextLink = 0; +statRead_body.having.driving = 0; +statRead_body.having.aspect = 'body'; + +// + +/** + * Returns object with information about a file. + * @param {String|Object} o Path to a file or object with options. + * @param {String|FileRecord} [ o.filePath=null ] - Path to a file or instance of FileRecord @see{@link wFileRecord} + * @param {Boolean} [ o.sync=true ] - Determines in which way file stats will be readed : true - synchronously, otherwise - asynchronously. + * In asynchronous mode returns wConsequence. + * @param {Boolean} [ o.throwing=false ] - Controls error throwing. Returns null if error occurred and ( throwing ) is disabled. + * @param {Boolean} [ o.resolvingTextLink=false ] - Enables resolving of text links @see{@link wFileProviderPartial~resolvingTextLink}. + * @param {Boolean} [ o.resolvingSoftLink=true ] - Enables resolving of soft links @see{@link wFileProviderPartial~resolvingSoftLink}. + * @returns {Object|wConsequence|null} + * If ( o.filePath ) path exists - returns file stats as Object, otherwise returns null. + * If ( o.sync ) mode is disabled - returns Consequence instance @see{@link wConsequence }. + * @example + * wTools.fileProvider.statResolvedRead( './existingDir/test.txt' ); + * // returns + * Stats + * { + dev : 2523469189, + mode : 16822, + nlink : 1, + uid : 0, + gid : 0, + rdev : 0, + blksize : undefined, + ino : 13229323905402304, + size : 0, + blocks : undefined, + atimeMs : 1525429693979.7004, + mtimeMs : 1525429693979.7004, + ctimeMs : 1525429693979.7004, + birthtimeMs : 1513244276986.976, + atime : '2018-05-04T10:28:13.980Z', + mtime : '2018-05-04T10:28:13.980Z', + ctime : '2018-05-04T10:28:13.980Z', + birthtime : '2017-12-14T09:37:56.987Z', + } + * + * @example + * wTools.fileProvider.statResolvedRead( './notExistingFile.txt' ); + * // returns null + * + * @example + * let consequence = wTools.fileProvider.statResolvedRead + * ({ + * filePath : './existingDir/test.txt', + * sync : 0 + * }); + * consequence.give( ( err, stats ) => + * { + * if( err ) + * throw err; + * + * console.log( stats ); + * }) + * + * @method statResolvedRead + * @throws { Exception } If no arguments provided. + * @throws { Exception } If ( o.filePath ) is not a String or instance of wFileRecord. + * @throws { Exception } If ( o.filePath ) path to a file doesn't exist. + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +let statRead = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, statRead_body ); + +statRead.having.aspect = 'entry'; +statRead.having.hubRedirecting = 0; + +statRead.defaults.resolvingSoftLink = 0; +statRead.defaults.resolvingTextLink = 0; + +_.assert( statRead.defaults !== statRead_body.defaults ); +_.assert( statRead.defaults.resolvingSoftLink === 0 ); +_.assert( statRead.body !== statRead_body ); +_.assert( statRead.body.defaults === statRead.defaults ); +_.assert( statRead.body.having === statRead.having ); + +// + +let statResolvedRead = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, statRead_body ); + +statResolvedRead.having.aspect = 'entry'; +statResolvedRead.having.hubRedirecting = 0; + +statResolvedRead.defaults.resolvingSoftLink = null; +statResolvedRead.defaults.resolvingTextLink = null; + +_.assert( statRead.defaults !== statResolvedRead.defaults ); +_.assert( statRead.defaults.resolvingSoftLink === 0 ); +_.assert( statRead.body.defaults === statRead.defaults ); +_.assert( statResolvedRead.defaults.resolvingSoftLink === null ); +_.assert( statResolvedRead.body.defaults === statResolvedRead.defaults ); +_.assert( statResolvedRead.body.having === statResolvedRead.having ); + +// + +/** + * Returns sum of sizes of files in `paths`. + * @example + * let path1 = 'tmp/sample/file1', + path2 = 'tmp/sample/file2', + textData1 = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + textData2 = 'Aenean non feugiat mauris'; + + wTools.fileWrite( { filePath : path1, data : textData1 } ); + wTools.fileWrite( { filePath : path2, data : textData2 } ); + let size = wTools.filesSize( [ path1, path2 ] ); + console.log(size); // 81 + * @param {string|string[]} paths path to file or array of paths + * @param {Object} [o] additional o + * @param {Function} [o.onBegin] callback that invokes before calculation size. + * @param {Function} [o.onEnd] callback. + * @returns {number} size in bytes + * @method filesSize + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +/* +qqq : split head / body +Dmytro : split routine. Create simple ( smoke ) test routines filesSize(). +*/ + +function filesSize_head( routine, args ) +{ + let o = args[ 0 ] || Object.create( null ); + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1, 'Expects single argument' ); + _.assert( _.strIs( o ) || _.arrayIs( o ) || _.mapIs( o ) ); + + if( _.strIs( o ) || _.arrayIs( o ) ) + o = { filePath : o }; + + _.routine.options_( routine, o ); + + return o; +} + +function filesSize_body( o ) +{ + let self = this; + // o = o || Object.create( null ); + // + // if( _.strIs( o ) || _.arrayIs( o ) ) + // o = { filePath : o }; + // + // _.assert( arguments.length === 1, 'Expects single argument' ); + + o.filePath = _.array.as( o.filePath ); + + let optionsForSize = _.props.extend( null, o ); + optionsForSize.filePath = o.filePath[ 0 ]; + + let result = self.fileSize( optionsForSize ); + + for( let p = 1 ; p < o.filePath.length ; p++ ) + { + optionsForSize.filePath = o.filePath[ p ]; + result += self.fileSize( optionsForSize ); + } + + return result; +} + +_.routineExtend( filesSize_body, statResolvedRead.body ); +// filesSize_body.defaults = +// { +// filePath : null, +// }; + +var having = filesSize_body.having = Object.create( null ); + +having.writing = 0; +having.reading = 1; +having.driving = 0; + +var operates = filesSize_body.operates = Object.create( null ); + +let filesSize = _.routine.uniteCloning_replaceByUnite( filesSize_head, filesSize_body ); + +// + +/** + * Return file size in bytes. For symbolic links return false. If onEnd callback + * is defined, method returns instance of wConsequence. + * + * @param {string|Object} o - object or path string + * @param {string} o.filePath - path to file + * @param {Function} [o.onBegin] - callback that invokes before calculation size. + * @param {Function} o.onEnd - this callback invoked in end of pathCurrent js event + * loop and accepts file size as argument. + * + * @example + * let path = 'tmp/fileSize/data4', + * bufferData1 = BufferNode.from( [ 0x01, 0x02, 0x03, 0x04 ] ), // size 4 + * bufferData2 = BufferNode.from( [ 0x07, 0x06, 0x05 ] ); // size 3 + * + * wTools.fileWrite( { filePath : path, data : bufferData1 } ); + * + * let size1 = wTools.fileSize( path ); + * console.log(size1); // 4 + * + * let con = wTools.fileSize + * ({ + * filePath : path, + * onEnd : function( size ) + * { + * console.log( size ); // 7 + * } + * }); + * + * wTools.fileWrite( { filePath : path, data : bufferData2, append : 1 } ); + * + * @method fileSize + * @returns {number|boolean|wConsequence} + * @throws {Error} If passed less or more than one argument. + * @throws {Error} If passed unexpected parameter in o. + * @throws {Error} If filePath is not string. + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + * + */ + +/* +qqq : extend test, check cases when does not exist, check throwing option +Dmytro : extended test routine. Throwing option is checked. Async mode is used. + Description of routine has callback onEnd, but now it is not used because + _.routine.uniteCloning_replaceByUnite check srcMap and screenMap in assert. +*/ + +function fileSize_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let stat = self.statResolvedRead( o ); + + if( !o.throwing && stat === null ) + return null; + + _.sure( _.object.isBasic( stat ) ); + + if( stat.isDir() ) + return self.UsingBigIntForStat ? 0n : 0; + + return stat.size; +} + +_.routineExtend( fileSize_body, statResolvedRead.body ); + +var having = fileSize_body.having; +having.driving = 0; +having.aspect = 'body'; +having.hubRedirecting = 0; + +let fileSize = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, fileSize_body ); + +fileSize.having.aspect = 'entry'; + +_.assert( fileSize.having.hubRedirecting === 0 ); + +// + +function isInoAct( o ) +{ + let self = this; + _.routine.assertOptions( isInoAct, arguments ); + if( _.numberIs( o.ino ) || _.bigIntIs( o.ino ) ) + return true; + return false; +} + +isInoAct.defaults = +{ + ino : null, +} + +// + +function isIno( o ) +{ + let self = this; + if( !_.mapIs( arguments[ 0 ] ) ) + o = { ino : arguments[ 0 ] } + _.assert( arguments.length === 1 ); + o = _.routine.options_( isIno, o ); + return self.isInoAct( o ); +} + +isIno.defaults = +{ + ... isInoAct.defaults, +} + +// + +let _fileExistsAct = Object.create( null ); +statReadAct.name = 'fileExistsAct'; + +var defaults = _fileExistsAct.defaults = Object.create( null ); +defaults.filePath = null; +defaults.sync = null; + +var having = _fileExistsAct.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 1; + +var operates = _fileExistsAct.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 } + +// + +function fileExistsAct( o ) +{ + let self = this; + let o2 = _.props.extend( null, o ); + _.assert( fileExistsAct, arguments ); + o2.throwing = 0; + o2.resolvingSoftLink = 0; + let result = self.statReadAct( o2 ); + _.assert( result === null || _.object.isBasic( result ) ); + _.assert( arguments.length === 1 ); + return !!result; +} + +_.routineExtend( fileExistsAct, _fileExistsAct ); + +// + +/** + * Returns object with information about a file. + * @param {String|Object} o Path to a file or object with options. + * @param {String|FileRecord} [ o.filePath=null ] - Path to a file or instance of FileRecord @see{@link wFileRecord} + * @param {Boolean} [ o.sync=true ] - Determines in which way file stats will be readed : true - synchronously, otherwise - asynchronously. + * In asynchronous mode returns wConsequence. + * @param {Boolean} [ o.throwing=false ] - Controls error throwing. Returns null if error occurred and ( throwing ) is disabled. + * @param {Boolean} [ o.resolvingTextLink=false ] - Enables resolving of text links @see{@link wFileProviderPartial~resolvingTextLink}. + * @param {Boolean} [ o.resolvingSoftLink=true ] - Enables resolving of soft links @see{@link wFileProviderPartial~resolvingSoftLink}. + * @returns {Object|wConsequence|null} + * If ( o.filePath ) path exists - returns file stats as Object, otherwise returns null. + * If ( o.sync ) mode is disabled - returns Consequence instance @see{@link wConsequence }. + * @example + * wTools.fileProvider.fileExists( './existingDir/test.txt' ); + * // returns + * Stats + * { + dev : 2523469189, + mode : 16822, + nlink : 1, + uid : 0, + gid : 0, + rdev : 0, + blksize : undefined, + ino : 13229323905402304, + size : 0, + blocks : undefined, + atimeMs : 1525429693979.7004, + mtimeMs : 1525429693979.7004, + ctimeMs : 1525429693979.7004, + birthtimeMs : 1513244276986.976, + atime : '2018-05-04T10:28:13.980Z', + mtime : '2018-05-04T10:28:13.980Z', + ctime : '2018-05-04T10:28:13.980Z', + birthtime : '2017-12-14T09:37:56.987Z', + } + * + * @example + * wTools.fileProvider.fileExists( './notExistingFile.txt' ); + * // returns null + * + * @example + * let consequence = wTools.fileProvider.fileExists + * ({ + * filePath : './existingDir/test.txt', + * sync : 0 + * }); + * consequence.give( ( err, stats ) => + * { + * if( err ) + * throw err; + * + * console.log( stats ); + * }) + * + * @method fileExists + * @throws { Exception } If no arguments provided. + * @throws { Exception } If ( o.filePath ) is not a String or instance of wFileRecord. + * @throws { Exception } If ( o.filePath ) path to a file doesn't exist. + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function fileExists_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.routineIs( self.fileExistsAct ) ); + + // let o2 = _.mapOnly_( null, o, self.fileExistsAct.defaults ); + + return self.fileExistsAct( o ); +} + +_.routineExtend( fileExists_body, fileExistsAct ); + +var having = fileExists_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let fileExists = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, fileExists_body ); + +var having = fileExists.having; +fileExists.having.aspect = 'entry'; + +// + +function isTerminal_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( isTerminal_body, arguments ); + _.assert( _.boolLike( o.resolvingSoftLink ) || _.numberIs( o.resolvingSoftLink ) ); + _.assert( _.boolLike( o.resolvingTextLink ) || _.numberIs( o.resolvingTextLink ) ); + + let o2 = + { + filePath : o.filePath, + resolvingSoftLink : o.resolvingSoftLink, + resolvingTextLink : o.resolvingTextLink, + throwing : 0 + } + + o.filePath = self.pathResolveLinkFull( o2 ).absolutePath; + + _.assert( o2.stat !== undefined ); + + if( o2.stat === null ) + return false; + + return o2.stat.isTerminal(); +} + +var defaults = isTerminal_body.defaults = Object.create( null ); +defaults.filePath = null; +defaults.resolvingSoftLink = 0; +defaults.resolvingTextLink = 0; + +var having = isTerminal_body.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 0; +having.hubResolving = 1; + +var operates = isTerminal_body.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 } + +// + +/** + * Returns true if file at ( filePath ) is an existing regular terminal file. + * @example + * wTools.isTerminal( './existingDir/test.txt' ); // true + * @param {string} filePath Path string + * @returns {boolean} + * @method isTerminal + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +let isTerminal = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, isTerminal_body ); + +isTerminal.having.aspect = 'entry'; + +// + +/** + * Returns true if resolved file at ( filePath ) is an existing regular terminal file. + * @example + * wTools.isTerminal( './existingDir/test.txt' ); // true + * @param {string} filePath Path string + * @returns {boolean} + * @method resolvedIsTerminal + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +let resolvedIsTerminal = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, isTerminal_body ); + +resolvedIsTerminal.defaults.resolvingSoftLink = null; +resolvedIsTerminal.defaults.resolvingTextLink = null; + +resolvedIsTerminal.having.aspect = 'entry'; + +// + +function isDir_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( isDir_body, arguments ); + _.assert( _.boolLike( o.resolvingSoftLink ) || _.numberIs( o.resolvingSoftLink ) ); + _.assert( _.boolLike( o.resolvingTextLink ) || _.numberIs( o.resolvingTextLink ) ); + + let o2 = + { + filePath : o.filePath, + resolvingSoftLink : o.resolvingSoftLink, + resolvingTextLink : o.resolvingTextLink, + throwing : 0 + } + + o.filePath = self.pathResolveLinkFull( o2 ).absolutePath; + + _.assert( o2.stat !== undefined ); + + if( !o2.stat ) + return false; + + return o2.stat.isDir(); +} + +var defaults = isDir_body.defaults = Object.create( null ); +defaults.filePath = null; +defaults.resolvingSoftLink = 0; +defaults.resolvingTextLink = 0; + +var having = isDir_body.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 0; + +var operates = isDir_body.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 } + +// + +/** + * Return True if file at ( filePath ) is an existing directory. + * If file is symbolic link to file or directory return false. + * @example + * wTools.isDir( './existingDir/' ); // true + * @param {string} filePath Tested path string + * @returns {boolean} + * @method isDir + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +let isDir = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, isDir_body ); + +isDir.having.aspect = 'entry'; + +// + +/** + * Return True if file at resolved ( filePath ) is an existing directory. + * If file is symbolic link to file or directory return false. + * @example + * wTools.isDir( './existingDir/' ); // true + * @param {string} filePath Tested path string + * @returns {boolean} + * @method resolvedIsDir + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +let resolvedIsDir = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, isDir_body ); + +resolvedIsDir.defaults.resolvingSoftLink = null; +resolvedIsDir.defaults.resolvingTextLink = null; + +resolvedIsDir.having.aspect = 'entry'; + +// + +/** + * Return True if file at `filePath` is a hard link. + * @param filePath + * @returns {boolean} + * @method isHardLink + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function isHardLink_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( isHardLink_body, arguments ); + _.assert( _.boolLike( o.resolvingSoftLink ) || _.numberIs( o.resolvingSoftLink ) ); + _.assert( _.boolLike( o.resolvingTextLink ) || _.numberIs( o.resolvingTextLink ) ); + + let o2 = + { + filePath : o.filePath, + resolvingSoftLink : o.resolvingSoftLink, + resolvingTextLink : o.resolvingTextLink, + throwing : 0 + } + + o.filePath = self.pathResolveLinkFull( o2 ).absolutePath; + + _.assert( o2.stat !== undefined ); + + if( o2.stat === null ) + return false; + + return o2.stat.isHardLink(); +} + +var defaults = isHardLink_body.defaults = Object.create( null ); +defaults.filePath = null; +defaults.resolvingSoftLink = 0; +defaults.resolvingTextLink = 0; + +var having = isHardLink_body.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 0; +having.hubResolving = 1; + +var operates = isHardLink_body.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 } + +// + +let isHardLink = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, isHardLink_body ); + +isHardLink.defaults.resolvingSoftLink = 0; +isHardLink.defaults.resolvingTextLink = 0; + +isHardLink.having.aspect = 'entry'; + +// + +let resolvedIsHardLink = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, isHardLink_body ); + +resolvedIsHardLink.defaults.resolvingSoftLink = null; +resolvedIsHardLink.defaults.resolvingTextLink = null; + +resolvedIsHardLink.having.aspect = 'entry'; + +// + +/** + * Return True if `filePath` is a symbolic link. + * @param filePath + * @returns {boolean} + * @method isSoftLink + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function isSoftLink_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( isSoftLink_body, arguments ); + _.assert( _.boolLike( o.resolvingTextLink ) || _.numberIs( o.resolvingTextLink ) ); + + + let o2 = + { + filePath : o.filePath, + resolvingSoftLink : 0, + resolvingTextLink : o.resolvingTextLink, + throwing : 0, + } + + o.filePath = self.pathResolveLinkFull( o2 ).absolutePath; + + _.assert( o2.stat !== undefined ); + + if( o2.stat === null ) + return false; + + return o2.stat.isSoftLink() +} + +var defaults = isSoftLink_body.defaults = Object.create( null ); +defaults.filePath = null; +defaults.resolvingTextLink = 0; + +var having = isSoftLink_body.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 0; +having.hubResolving = 1; + +var operates = isSoftLink_body.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 } + +// + +let isSoftLink = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, isSoftLink_body ); +isSoftLink.defaults.resolvingTextLink = 0; +isSoftLink.having.aspect = 'entry'; + +// + +let resolvedIsSoftLink = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, isSoftLink_body ); +resolvedIsSoftLink.defaults.resolvingTextLink = null; +resolvedIsSoftLink.having.aspect = 'entry'; + +// + +function isTextLink_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( isTextLink_body, arguments ); + _.assert( _.boolLike( o.resolvingSoftLink ) || _.numberIs( o.resolvingSoftLink ) ); + + let o2 = + { + filePath : o.filePath, + resolvingSoftLink : o.resolvingSoftLink, + resolvingTextLink : 0, + throwing : 0 + } + + o.filePath = self.pathResolveLinkFull( o2 ).absolutePath; + + _.assert( o2.stat !== undefined ); + + if( o2.stat === null ) + return false; + + return o2.stat.isTextLink(); +} + +var defaults = isTextLink_body.defaults = Object.create( null ); +defaults.filePath = null; +defaults.resolvingSoftLink = 0; + +var having = isTextLink_body.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 0; +having.hubResolving = 1; + +var operates = isTextLink_body.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 } + +// + +let isTextLink = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, isTextLink_body ); +isTextLink.defaults.resolvingSoftLink = 0; +isTextLink.having.aspect = 'entry'; + +// + +let resolvedIsTextLink = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, isTextLink_body ); +resolvedIsTextLink.defaults.resolvingSoftLink = null; +resolvedIsTextLink.having.aspect = 'entry'; + +// + +function isLink_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let result = false; + + if( o.resolvingSoftLink && o.resolvingTextLink ) + return result; + + let o2 = + { + filePath : o.filePath, + resolvingSoftLink : o.resolvingSoftLink, + resolvingTextLink : o.resolvingTextLink, + throwing : 0 + } + + o.filePath = self.pathResolveLinkFull( o2 ).absolutePath; + + _.assert( o2.stat !== undefined ); + + if( o2.stat === null ) + return result; + + result = o2.stat.isLink(); + + return result; +} + +var defaults = isLink_body.defaults = Object.create( null ); +defaults.filePath = null; +defaults.resolvingSoftLink = 0; +defaults.resolvingTextLink = 0; +defaults.usingTextLink = 0; + +var having = isLink_body.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.aspect = 'body'; +having.driving = 0; + +var operates = isLink_body.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 }; + +// + +let isLink = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, isLink_body ); + +isLink.having.aspect = 'entry'; + +// + +let resolvedIsLink = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, isLink_body ); + +resolvedIsLink.defaults.resolvingSoftLink = null; +resolvedIsLink.defaults.resolvingTextLink = null; + +resolvedIsLink.having.aspect = 'entry'; + +// + +/** + * Returns True if file at ( filePath ) is an existing empty directory, otherwise returns false. + * If file is symbolic link to file or directory return false. + * @example + * wTools.fileProvider.dirIsEmpty( './existingEmptyDir/' ); // true + * @param {string} filePath - Path to the directory. + * @returns {boolean} + * @method dirIsEmpty + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function dirIsEmpty( filePath ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( self.isDir( filePath ) ) + return !self.dirRead( filePath ).length; + + return false; +} + +var having = dirIsEmpty.having = Object.create( null ); + +having.writing = 0; +having.reading = 1; +having.driving = 0; + +// + +function resolvedDirIsEmpty( filePath ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let o = { filePath }; + + if( self.resolvedIsDir( o ) ) + return !self.dirRead( o.filePath ).length; + + return false; +} + +var having = resolvedDirIsEmpty.having = Object.create( null ); + +having.writing = 0; +having.reading = 1; +having.driving = 0; + +// -- +// read +// -- + +let streamReadAct = Object.create( null ); +statReadAct.name = 'streamReadAct'; + +var defaults = streamReadAct.defaults = Object.create( null ); +defaults.filePath = null; +defaults.encoding = null; +defaults.onStreamBegin = null; + +var having = streamReadAct.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 1; + +var operates = streamReadAct.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 } + +// + +function streamRead_body( o ) +{ + let self = this; + let result; + let encoder = _.files.ReadEncoders[ o.encoding ]; + + let optionsRead = _.props.extend( null, o ); + delete optionsRead.throwing; + + handleBegin(); + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( !o.throwing ) + { + try + { + result = self.streamReadAct( optionsRead ); + } + catch( err ) + { + return null; + } + } + else + { + result = self.streamReadAct( optionsRead ); + } + + result.on( 'error', ( err ) => handleError( err ) ); + result.on( 'end', () => handleEnd() ); + + return result; + + + /* begin */ + + function handleBegin() + { + if( encoder && encoder.onBegin ) + { + let r = encoder.onBegin.call( self, { operation : o, encoder, provider : self }) + _.sure( r === undefined ); + } + } + + /* end */ + + function handleEnd() + { + + if( encoder && encoder.onEnd ) + try + { + let o2 = { stream : result, operation : o, encoder, provider : self }; + let r = encoder.onEnd.call( self, o2 ); + _.sure( r === undefined ); + result = o2.result; + } + catch( err ) + { + handleError( err ); + return null; + } + + } + + /* error */ + + function handleError( err ) + { + + err = _._err + ({ + args : [ err, '\nfileRead( ', o.filePath, ' )\n' ], + usingSourceCode : 0, + level : 0, + }); + + if( encoder && encoder.onError ) + try + { + /* zzz : remove encoder.onError? */ + err = encoder.onError.call( self, { error : err, stream : result, operation : o, encoder, provider : self }) + } + catch( err2 ) + { + /* the simplest output is required to avoid recursion */ + console.error( err2 ); + console.error( err.toString() + '\n' + err.stack ); + } + + return null; + } + +} + +_.routineExtend( streamRead_body, streamReadAct ); + +var defaults = streamRead_body.defaults; +defaults.throwing = null; + +var having = streamRead_body.having; +having.driving = 0; +having.aspect = 'body'; + +let streamRead = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, streamRead_body ); +streamRead.having.aspect = 'entry'; + +// + +let fileReadAct = Object.create( null ); +fileReadAct.name = 'fileReadAct'; + +var defaults = fileReadAct.defaults = Object.create( null ); +defaults.sync = null; +defaults.filePath = null; +defaults.encoding = null; +defaults.advanced = null; +defaults.resolvingSoftLink = null; + +var having = fileReadAct.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 1; + +var operates = fileReadAct.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 }; + +// + +function fileRead_head( routine, args ) +{ + let self = this; + + _.assert( args.length === 1 || args.length === 2 ); + + if( args.length === 2 ) + args = [ { filePath : args[ 0 ], encoding : args[ 1 ] } ]; /* aaa : add test to cover this */ /* Dmytro : covered in routine `fileReadWithEncoding` */ + + if( args[ 0 ].verbosity !== undefined ) + { + _global_.logger.styleSet( 'negative' ); + _global_.logger.warn( 'Option verbosity will be deprecated. Please use option logger.' ) + _global_.logger.styleSet( 'default' ); + args[ 0 ].logger = args[ 0 ].verbosity; + delete args[ 0 ].verbosity; + } + + let o = self._preFilePathScalarWithoutProviderDefaults( routine, args ); + + _.assert( _.longHas( [ 'data', 'o' ], o.outputFormat ) ); + + self._providerDefaultsApply( o ); + + return o; +} + +// + +function fileRead_body( o ) +{ + let self = this; + let result = null; + + // if( o.encoding === _.unknown ) /* qqq : cover */ + // o.encoding = _.files.encoder.deduce({ filePath : o.filePath, returning : 'name', feature : { reader : true } }); + let encoderOp = _.files.encoder.for + ({ + encoding : o.encoding, + filePath : o.filePath, + fileProvider : self, + feature : { reader : true }, + }); + let encoder = encoderOp.encoder; + o.encoding = encoderOp.encoding; + // let encoder = _.files.ReadEncoders[ o.encoding ]; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( o.encoding ) ); + _.assert( _.longHas( [ 'data', 'o' ], o.outputFormat ) ); + + if( o.resolvingTextLink && self.usingTextLink ) + o.filePath = self.pathResolveTextLink( o.filePath ); + + /* exec */ + + handleBegin(); + + let optionsRead = _.mapOnly_( null, o, self.fileReadAct.defaults ); + + try + { + result = self.fileReadAct( optionsRead ); + } + catch( err ) + { + if( o.sync ) + result = err; + else + result = new _.Consequence().error( err ); + } + + /* throwing */ + + if( o.sync ) + { + if( _.errIs( result ) ) + return handleError( result ); + return handleEnd( result ); + } + else + { + + result + .then( handleEnd ) + .catch( handleError ); + + return result; + } + + /* begin */ + + function handleBegin() + { + if( encoder && encoder.onBegin ) + { + let r = encoder.onBegin.call( self, { operation : o, encoder, provider : self }) + _.sure( r === undefined ); + } + if( o.onBegin ) + _.Consequence.Take( o.onBegin, o ); + } + + /* end */ + + function handleEnd( data ) + { + + if( encoder && encoder.onEnd ) + try + { + let o2 = { data, operation : o, encoder, provider : self }; + let r = encoder.onEnd.call( self, o2 ); + _.sure( r === undefined ); + data = o2.data; + } + catch( err ) + { + handleError( err ); + return null; + } + + // if( o.verbosity >= 1 ) + // self.logger.log( ' . Read .', _.color.strFormat( o.filePath, 'path' ) ); + if( o.logger && o.logger.verbosity >= 1 ) + o.logger.log( ' . Read .', _.color.strFormat( o.filePath, 'path' ) ); + + o.result = data; + + let r; + if( o.outputFormat === 'data' ) + r = data; + else + r = o; + + if( o.onEnd ) + _.Consequence.Take( o.onEnd, o ); + + return r; + } + + /* error */ + + function handleError( err ) + { + + err = _._err + ({ + args : [ err, '\nfileRead( ', o.filePath, ' )\n' ], + usingSourceCode : 0, + level : 0, + }); + + if( encoder && encoder.onError ) + try + { + /* zzz : remove encoder.onError? */ + err = encoder.onError.call( self, { error : err, operation : o, encoder, provider : self }) + } + catch( err2 ) + { + /* the simplest output is reqired to avoid recursion */ + console.error( err2 ); + console.error( err.toString() + '\n' + err.stack ); + } + + if( o.onError ) + _.Consequence.Error( o.onError, err ); + + if( o.throwing ) + throw err; + + _.errAttend( err ); + + return null; + } + + /* */ + +} + +_.routineExtend( fileRead_body, fileReadAct ); + +var defaults = fileRead_body.defaults; +defaults.outputFormat = 'data'; +defaults.throwing = null; +defaults.onBegin = null; /* xxx : remove */ +defaults.onEnd = null; /* xxx : remove */ +defaults.onError = null; /* xxx : remove */ +defaults.resolvingSoftLink = 1; +defaults.resolvingTextLink = null; +defaults.logger = 0; + +var having = fileRead_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +/** + * Reads the entire content of a file. + * Accepts single paramenter - path to a file ( o.filePath ) or options map( o ). + * Returns wConsequence instance. If `o` sync parameter is set to true (by default) and returnRead is set to true, + method returns encoded content of a file. + * There are several way to get read content : as argument for function passed to wConsequence.give(), as second argument + for `o.onEnd` callback, and as direct method returns, if `o.returnRead` is set to true. + * + * @example + * // content of tmp/json1.json : {"a" :1, "b" :"s", "c" : [ 1, 3, 4 ] } + let fileReadOptions = + { + sync : 0, + filePath : 'tmp/json1.json', + encoding : 'json', + + onEnd : function( err, result ) + { + console.log(result); // { a : 1, b : 's', c : [ 1, 3, 4 ] } + } + }; + + let con = wTools.fileProvider.fileRead( fileReadOptions ); + + // or + fileReadOptions.onEnd = null; + let con2 = wTools.fileProvider.fileRead( fileReadOptions ); + + con2.give(function( err, result ) + { + console.log(result); // { a : 1, b : 's', c : [ 1, 3, 4 ] } + }); + + * @example + fileRead({ filePath : file.absolute, encoding : 'buffer.node' }) + + * @param {Object} o Read options + * @param {String} [o.filePath=null] Path to read file + * @param {Boolean} [o.sync=true] Determines in which way will be read file. If this set to false, file will be read + asynchronously, else synchronously + * Note : if even o.sync sets to true, but o.returnRead if false, method will path resolve read content through wConsequence + anyway. + * @param {Boolean} [o.outputFormat='data'] If this parameter sets to true, o.onBegin callback will get `o` options, wrapped + into object with key 'options' and options as value. + * @param {Boolean} [o.throwing=false] Controls error throwing. Returns null if error occurred and ( throwing ) is disabled. + * @param {String} [o.name=null] + * @param {String} [o.encoding='utf8'] Determines encoding processor. The possible values are : + * 'utf8' : default value, file content will be read as string. + * 'json' : file content will be parsed as JSON. + * 'arrayBuffer' : the file content will be return as raw BufferRaw. + * @param {fileRead~onBegin} [o.onBegin=null] @see [@link fileRead~onBegin] + * @param {Function} [o.onEnd=null] @see [@link fileRead~onEnd] + * @param {Function} [o.onError=null] @see [@link fileRead~onError] + * @param {*} [o.advanced=null] + * @returns {wConsequence|BufferRaw|string|Array|Object} + * @throws {Error} If missed arguments. + * @throws {Error} If ( o ) has extra parameters. + * @method fileRead + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +/** + * This callback is run before fileRead starts read the file. Accepts error as first parameter. + * If in fileRead passed 'o.outputFormat' that is set to true, callback accepts as second parameter object with key 'options' + and value that is reference to options map passed into fileRead method, and user has ability to configure that + before start reading file. + * @callback fileRead~onBegin + * @param {Error} err + * @param {Object|*} options options argument passed into fileRead. + */ + +/** + * This callback invoked after file has been read, and accepts encoded file content data (by depend from + options.encoding value), string by default ('utf8' encoding). + * @callback fileRead~onEnd + * @param {Error} err Error occurred during file read. If read success it's sets to null. + * @param {BufferRaw|Object|Array|String} result Encoded content of read file. + */ + +/** + * Callback invoke if error occurred during file read. + * @callback fileRead~onError + * @param {Error} error + */ + +const fileRead = _.routine.uniteCloning_replaceByUnite( fileRead_head, fileRead_body ); + +fileRead.having.aspect = 'entry'; +fileRead.having.hubResolving = 1; + +_.assert( fileRead.encoders === undefined ); +// _.assert( _.mapHasAll( fileRead.encoders, fileRead_body.encoders ) ); + +// + +let fileReadUnknown = _.routine.uniteCloning( fileRead_head, fileRead_body ); +fileReadUnknown.having.aspect = 'entry'; +fileReadUnknown.defaults.encoding = _.unknown; + +// + +/** + * Reads the entire content of a file synchronously. + * Method returns encoded content of a file. + * Can accepts `filePath` as first parameters and options as second + * + * @example + * // content of tmp/json1.json : { "a" : 1, "b" : "s", "c" : [ 1, 3, 4 ]} + let fileReadOptions = + { + filePath : 'tmp/json1.json', + encoding : 'json', + + onEnd : function( err, result ) + { + console.log(result); // { a : 1, b : 's', c : [ 1, 3, 4 ] } + } + }; + + let res = wTools.fileReadSync( fileReadOptions ); + // { a : 1, b : 's', c : [ 1, 3, 4 ] } + + * @param {Object} o read options + * @param {string} o.filePath path to read file + * @param {boolean} [o.outputFormat='data'] If this parameter sets to true, o.onBegin callback will get `o` options, wrapped + into object with key 'options' and options as value. + * @param {boolean} [o.silent=false] If set to true, method will caught errors occurred during read file process, and + pass into o.onEnd as first parameter. Note : if sync is set to false, error will caught anyway. + * @param {string} [o.name=null] + * @param {string} [o.encoding='utf8'] Determines encoding processor. The possible values are : + * 'utf8' : default value, file content will be read as string. + * 'json' : file content will be parsed as JSON. + * 'arrayBuffer' : the file content will be return as raw BufferRaw. + * @param {fileRead~onBegin} [o.onBegin=null] @see [@link fileRead~onBegin] + * @param {Function} [o.onEnd=null] @see [@link fileRead~onEnd] + * @param {Function} [o.onError=null] @see [@link fileRead~onError] + * @param {*} [o.advanced=null] + * @returns {wConsequence|BufferRaw|string|Array|Object} + * @throws {Error} if missed arguments + * @throws {Error} if `o` has extra parameters + * @method fileReadSync + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +let fileReadSync = _.routine.uniteCloning( fileRead.head, fileRead.body ); + +fileReadSync.defaults.sync = 1; +fileReadSync.having.aspect = 'entry'; + +// + +function fileReadJson_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + return self.fileRead( o ); +} + +_.routineExtend( fileReadJson_body, fileRead.body ); + +var defaults = fileReadJson_body.defaults; +defaults.sync = 1; +defaults.encoding = 'json'; + +var having = fileReadJson_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +/** + * Reads a JSON file and then parses it into an object. + * + * @example + * // content of tmp/json1.json : {"a" :1, "b" :"s", "c" :[1, 3, 4]} + * + * let res = wTools.fileReadJson( 'tmp/json1.json' ); + * // { a : 1, b : 's', c : [ 1, 3, 4 ] } + * @param {string} filePath file path + * @returns {*} + * @throws {Error} If missed arguments, or passed more then one argument. + * @method fileReadJson + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +let fileReadJson = _.routine.uniteCloning_replaceByUnite( fileRead.head, fileReadJson_body ); + +fileReadJson.having.aspect = 'entry'; + +// + +function fileReadJs_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + return self.fileRead( o ); +} + +_.routineExtend( fileReadJs_body, fileRead.body ); + +var defaults = fileReadJs_body.defaults; +defaults.sync = 1; +defaults.encoding = 'js.structure'; + +var having = fileReadJs_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let fileReadJs = _.routine.uniteCloning_replaceByUnite( fileRead.head, fileReadJs_body ); +var having = fileReadJs.having; +fileReadJs.having.aspect = 'entry'; + +// + +function _fileInterpret_head( routine, args ) +{ + let self = this; + + _.assert( args.length === 1 ); + + let o = args[ 0 ]; + + if( self.path.like( o ) ) + o = { filePath : self.path.from( o ) }; + + _.routine.options_( routine, o ); + let encoding = o.encoding; + self._providerDefaultsApply( o ); + o.encoding = encoding; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( o.filePath ) ); + + o.filePath = self.path.normalize( o.filePath ); + + return o; +} + +// + +/* xxx : deprecated */ +function _fileInterpret_body( o ) +{ + let self = this; + let result = null; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( !o.encoding ) + { + let ext = self.path.ext( o.filePath ); + for( let e in fileInterpret.encoders ) + { + // let encoder = fileInterpret.encoders[ e ]; + let encoder = _.files.ReadEncoders[ o.encoding ]; + if( !encoder.exts ) + continue; + // if( encoder.forConfig !== undefined && !encoder.forConfig ) + // continue; + + if( encoder.feature.config !== undefined && !encoder.feature.config ) + continue; + + if( _.longHas( encoder.exts, ext ) ) + { + o.encoding = e; + break; + } + } + } + + if( !o.encoding ) + o.encoding = fileRead.defaults.encoding; + + return self.fileRead( o ); +} + +_.routineExtend( _fileInterpret_body, fileRead.body ); + +_fileInterpret_body.defaults.encoding = null; + +let fileInterpret = _.routine.uniteCloning_replaceByUnite( _fileInterpret_head, _fileInterpret_body ); + +fileInterpret.having.aspect = 'entry'; + +// + +// let hashReadAct = ( function hashReadAct() +// { +// let Crypto; +// +// return function hashReadAct( o ) +// { +// let self = this; +// +// _.assert( arguments.length === 1, 'Expects single argument' ); +// +// if( Crypto === undefined ) +// Crypto = require( 'crypto' ); +// let md5sum = Crypto.createHash( 'md5' ); +// +// /* */ +// +// if( o.sync && _.boolLike( o.sync ) ) +// { +// let result; +// try +// { +// let stat = self.statResolvedRead({ filePath : o.filePath, sync : 1, throwing : 0 }); +// _.sure( !!stat, 'Cant get stats of file ' + _.strQuote( o.filePath ) ); +// if( stat.size > self.hashFileSizeLimit ) +// throw _.err( 'File is too big ' + _.strQuote( o.filePath ) + ' ' + stat.size + ' > ' + self.hashFileSizeLimit ); +// let read = self.fileReadSync( o.filePath ); +// md5sum.update( read ); +// result = md5sum.digest( 'hex' ); +// } +// catch( err ) +// { +// throw err; +// } +// +// return result; +// +// } +// else if( !o.sync ) +// { +// let con = new _.Consequence(); +// let stream = self.streamRead( o.filePath ); +// +// stream.on( 'data', function( d ) +// { +// md5sum.update( d ); +// }); +// +// stream.on( 'end', function() +// { +// let hash = md5sum.digest( 'hex' ); +// con.take( hash ); +// }); +// +// stream.on( 'error', function( err ) +// { +// con.error( _.err( err ) ); +// }); +// +// return con; +// } +// else _.assert( 0 ); +// } +// +// })(); + +function hashReadAct( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + /* */ + + if( o.sync && _.boolLike( o.sync ) ) + { + let read = self.fileReadSync({ filePath : o.filePath, encoding : 'buffer.raw', logger : o.logger }); + return _.files.hashFrom( read ); + } + else if( !o.sync ) + { + let stream = self.streamRead( o.filePath ); + return _.files.hashFrom( stream ); + } + else _.assert( 0 ); + + /* */ + +} + +var defaults = hashReadAct.defaults = Object.create( null ); +defaults.filePath = null; +defaults.sync = null; + +var having = hashReadAct.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 1; + +var operates = hashReadAct.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 } + +// + +/** + * Returns md5 hash string based on the content of the terminal file. + * @param {String|Object} o Path to a file or object with options. + * @param {String|FileRecord} [ o.filePath=null ] - Path to a file or instance of FileRecord @see{@link wFileRecord} + * @param {Boolean} [ o.sync=true ] - Determines in which way file will be read : true - synchronously, otherwise - asynchronously. + * In asynchronous mode returns wConsequence. + * @param {Boolean} [ o.throwing=false ] - Controls error throwing. Returns NaN if error occurred and ( throwing ) is disabled. + * @param {Boolean} [ o.verbosity=0 ] - Sets the level of console output. + * @returns {Object|wConsequence|NaN} + * If ( o.filePath ) path exists - returns hash as String, otherwise returns null. + * If ( o.sync ) mode is disabled - returns Consequence instance @see{@link wConsequence }. + * @example + * wTools.fileProvider.hashRead( './existingDir/test.txt' ); + * // returns 'fd8b30903ac80418777799a8200c4ff5' + * + * @example + * wTools.fileProvider.hashRead( './notExistingFile.txt' ); + * // returns NaN + * + * @example + * let consequence = wTools.fileProvider.hashRead + * ({ + * filePath : './existingDir/test.txt', + * sync : 0 + * }); + * consequence.give( ( err, hash ) => + * { + * if( err ) + * throw err; + * + * console.log( hash ); + * }) + * + * @method hashRead + * @throws { Exception } If no arguments provided. + * @throws { Exception } If ( o.filePath ) is not a String or instance of wFileRecord. + * @throws { Exception } If ( o.filePath ) path to a file doesn't exist or file is a directory. + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function hashRead_body( o ) +{ + let self = this; + let result; + + if( o.verbosity >= 1 ) + self.logger.log( ' . hashRead :', o.filePath ); + if( o.hashFileSizeLimit === null ) + o.hashFileSizeLimit = self.hashFileSizeLimit; + + try + { + if( o.hashFileSizeLimit ) + { + let stat = self.statResolvedRead({ filePath : o.filePath, sync : 1, throwing : 1 }); + if( stat.size > o.hashFileSizeLimit ) + { + throw _.err( `File ${ o.filePath } is too big ${ stat.size } > ${ o.hashFileSizeLimit }` ); + } + } + result = self.hashReadAct( o ); + } + catch( err ) /* qqq : make sure catch blocks of other methods return consequence if o.sync ~ false */ + { + let error = _.err( err, '\nCant read hash of', o.filePath ) + if( o.sync ) + { + if( o.throwing ) + throw error; + else + return NaN; + } + else + { + let result = new _.Consequence(); + if( o.throwing ) + return result.error( error ); + else + return result.take( NaN ); + } + } + + if( _.consequenceIs( result ) ) + result.finally( ( err, arg ) => + { + if( err ) + if( o.throwing ) + { + throw _.err( err, '\nCant read hash of', o.filePath ); + } + else + { + _.errAttend( err ); + return NaN; + } + return arg; + }); + + return result; +} + +_.routineExtend( hashRead_body, hashReadAct ); + +var defaults = hashRead_body.defaults; +defaults.throwing = null; +// defaults.verbosity = null; +defaults.logger = false; +defaults.hashFileSizeLimit = null; + +var having = hashRead_body.having; +having.driving = 0; +having.aspect = 'body'; + +let hashRead = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, hashRead_body ); +hashRead.having.aspect = 'entry'; + +// + +function hashSzRead_body( o ) +{ + let self = this; + let result; + + /* */ + + if( o.hashFileSizeLimit === null ) + o.hashFileSizeLimit = self.hashFileSizeLimit; + + if( o.sync ) + { + let stat = self.statResolvedRead({ filePath : o.filePath, sync : 1, throwing : 1 }); + if( o.hashFileSizeLimit && stat.size > o.hashFileSizeLimit ) + { + throw _.err( `File ${ o.filePath } is too big ${ stat.size } > ${ o.hashFileSizeLimit }` ); + } + let read = self.fileReadSync( o.filePath, 'buffer.raw' ); + return _.files.hashSzFrom( read ); + } + else if( !o.sync ) + { + let stream = self.streamRead( o.filePath ); + return _.files.hashSzFrom( stream ); + } + else _.assert( 0 ); + + /* */ + + /* zzz : remove Consequence.From after And will be adjusted */ + let ready = _.Consequence.AndKeep( _.Consequence.From( stat ), _.Consequence.From( hash ) ).then( ( arg ) => + { + if( !arg[ 0 ] || !arg[ 1 ] ) + return null; + return arg[ 0 ].size + '-' + arg[ 1 ]; + }); + + // let stat = self.statRead({ filePath : o.filePath, sync : o.sync, throwing : o.throwing }); + // let hash = self.hashRead( o ); + // + // /* zzz : remove Consequence.From after And will be adjusted */ + // let ready = _.Consequence.AndKeep( _.Consequence.From( stat ), _.Consequence.From( hash ) ).then( ( arg ) => + // { + // if( !arg[ 0 ] || !arg[ 1 ] ) + // return null; + // return arg[ 0 ].size + '-' + arg[ 1 ]; + // }); + + if( o.sync ) + return ready.sync(); + return ready; +} + +_.routineExtend( hashSzRead_body, hashRead.body ); + +var defaults = hashSzRead_body.defaults; +let hashSzRead = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, hashSzRead_body ); +hashSzRead.having.aspect = 'entry'; + +// + +function hashSzIsUpToDate_head( routine, args ) +{ + let self = this; + + if( args.length === 2 ) + args = [ { filePath : args[ 0 ], hash : args[ 1 ] } ]; + + return self._preFilePathScalarWithProviderDefaults( routine, args ); +} + +function hashSzIsUpToDate_body( o ) +{ + let self = this; + let result; + + _.assert( _.strDefined( o.hash ) ); + + let ready; + + if( o.data === null ) + ready = _.Consequence.From( self.statRead + ({ + filePath : o.filePath, + sync : o.sync, + throwing : o.throwing, + resolvingSoftLink : 1, + resolvingTextLink : 1, + })); + else + ready = _.Consequence.From( null ); + + let parsed = o.hash.split( '-' ); + parsed[ 0 ] = _.bigIntFrom( parsed[ 0 ] ); + + if( o.data === null ) + ready.then( ( stat ) => + { + if( stat === null ) + return null; + if( stat.size !== parsed[ 0 ] ) + return false; + return self.hashRead( _.mapOnly_( null, o, self.hashRead.defaults ) ); + }) + else + ready.then( ( stat ) => + { + let data = _.bufferBytesFrom( o.data ); + if( _.bigIntFrom( data.byteLength ) !== parsed[ 0 ] ) + return false; + return _.files.hashFrom( data ); + }) + + ready.then( ( hash ) => + { + if( !hash ) + return hash; + if( hash !== parsed[ 1 ] ) + return false; + return true; + }); + + if( o.sync ) + return ready.sync(); + return ready; +} + +_.routineExtend( hashSzIsUpToDate_body, hashRead.body ); + +var defaults = hashSzIsUpToDate_body.defaults; +defaults.hash = null; +defaults.data = null; +let hashSzIsUpToDate = _.routine.uniteCloning_replaceByUnite( hashSzIsUpToDate_head, hashSzIsUpToDate_body ); +hashSzIsUpToDate.having.aspect = 'entry'; + +// + +let dirReadAct = Object.create( null ); +dirReadAct.name = 'dirReadAct'; + +var defaults = dirReadAct.defaults = Object.create( null ); +defaults.filePath = null; +defaults.sync = null; + +var having = dirReadAct.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 1; + +var operates = dirReadAct.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 } + +// + +function dirRead_head( routine, args ) +{ + let self = this; + let o = self._preFilePathScalarWithProviderDefaults.apply( self, arguments ); + return o; +} + +// + +function dirRead_body( o ) +{ + let self = this; + let result; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.longHas( [ 'record', 'absolute', 'relative' ], o.outputFormat ) ) + _.routine.assertOptions( dirRead_body, arguments ); + + let filePath = o.filePath; + let o2 = _.props.extend( null, o ); + delete o2.outputFormat; + delete o2.basePath; + delete o2.throwing; + o2.filePath = self.path.normalize( o2.filePath ); + + /* */ + + try + { + result = self.dirReadAct( o2 ); + } + catch( err ) + { + if( o.throwing ) + throw _.err( err ); + else + return null; + } + + /* */ + + if( o2.sync ) + { + if( result ) + result = adjust( result ); + } + else + { + result.finally( function( err, list ) + { + if( err ) + if( o.throwing ) + { + throw _.err( err ); + } + else + { + _.errAttend( err ); + return null; + } + if( list ) + return adjust( list ); + return list; + }); + } + + return result; + + /* - */ + + function adjust( result ) + { + if( _.strIs( result ) ) + { + filePath = self.path.dir( filePath ); + result = [ result ]; + } + + _.assert( _.arrayIs( result ) ); + + result.sort( function( a, b ) + { + a = a.toLowerCase(); + b = b.toLowerCase(); + if( a < b ) + return -1; + if( a > b ) + return +1; + + return 0; + }); + + result = result.map( ( p ) => self.path.escape( p ) ); /* yyy */ + + if( o.outputFormat === 'absolute' ) + result = result.map( function( relative ) + { + return self.path.join( filePath, relative ); + }); + else if( o.outputFormat === 'record' ) + result = result.map( function( relative ) + { + return self.recordFactory({ dirPath : filePath, basePath : o.basePath }).record( relative ); + }); + else if( o.basePath ) + result = result.map( function( relative ) + { + return self.path.relative( o.basePath, self.path.join( filePath, relative ) ); + }); + + return result; + } + +} + +_.routineExtend( dirRead_body, dirReadAct ); + +var defaults = dirRead_body.defaults; +defaults.outputFormat = 'relative'; +defaults.basePath = null; +defaults.throwing = 0; + +var having = dirRead_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +/** + * Returns list of files located in a directory. List is represented as array of paths to that files. + * @param {String|Object} o Path to a directory or object with options. + * @param {String|FileRecord} [ o.filePath=null ] - Path to a directory or instance of FileRecord @see{@link wFileRecord} + * @param {Boolean} [ o.sync=true ] - Determines in which way list of files will be read : true - synchronously, otherwise - asynchronously. + * In asynchronous mode returns wConsequence. + * @param {Boolean} [ o.throwing=false ] - Controls error throwing. Returns null if error occurred and ( throwing ) is disabled. + * @param {String} [ o.outputFormat='relative' ] - Sets style of a file path in a result array. Possible values : 'relative', 'absolute', 'record'. + * @param {String} [ o.basePath=o.filePath ] - Relative path to a files from directory located by path ( o.filePath ). By default is equal to ( o.filePath ); + * @returns {Array|wConsequence|null} + * If ( o.filePath ) path exists - returns list of files as Array, otherwise returns null. + * If ( o.sync ) mode is disabled - returns Consequence instance @see{@link wConsequence }. + * + * @example + * wTools.fileProvider.dirRead( './existingDir' ); + * // returns [ 'a.txt', 'b.js', 'c.md' ] + * + * @example + * wTools.fileProvider.dirRead( './notExistingDir' ); + * // returns null + * + * * @example + * wTools.fileProvider.dirRead( './existingEmptyDir' ); + * // returns [] + * + * @example + * let consequence = wTools.fileProvider.dirRead + * ({ + * filePath : './existingDir', + * sync : 0 + * }); + * consequence.give( ( err, files ) => + * { + * if( err ) + * throw err; + * + * console.log( files ); + * }) + * + * @method dirRead + * @throws { Exception } If no arguments provided. + * @throws { Exception } If ( o.filePath ) path is not a String or instance of FileRecord @see{@link wFileRecord} + * @throws { Exception } If ( o.filePath ) path doesn't exist. + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +let dirRead = _.routine.uniteCloning_replaceByUnite( dirRead_head, dirRead_body ); + +dirRead.having.aspect = 'entry'; + +// + +function dirReadDirs_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let result = self.dirRead( o ); + + result = result.filter( function( path ) + { + let stat = self.statResolvedRead( path ); + if( stat.isDir() ) + return true; + }); + + return result; +} + +_.routineExtend( dirReadDirs_body, dirRead.body ); + +var having = dirReadDirs_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let dirReadDirs = _.routine.uniteCloning_replaceByUnite( dirRead.head, dirReadDirs_body ); +dirReadDirs.having.aspect = 'entry'; + +// + +function dirReadTerminals_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let result = self.dirRead( o ); + + result = result.filter( function( path ) + { + let stat = self.statResolvedRead( path ); + if( !stat.isDir() ) + return true; + }); + + return result; + +} + +_.routineExtend( dirReadTerminals_body, dirRead.body ); + +var having = dirReadTerminals_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let dirReadTerminals = _.routine.uniteCloning_replaceByUnite( dirRead.head, dirReadTerminals_body ); +dirReadTerminals.having.aspect = 'entry'; + +// + +// let rightsReadAct = Object.create( null ); +// rightsReadAct.name = 'rightsReadAct'; + +function rightsReadAct( o ) +{ + let self = this; + let stat = self.statRead( o ); + return stat.mode; +} + +var defaults = rightsReadAct.defaults = Object.create( null ); +defaults.filePath = null; +defaults.sync = null; + +var having = rightsReadAct.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 1; + +var operates = rightsReadAct.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 } + +// + +function rightsRead_head( routine, args ) +{ + let self = this; + + let o = args[ 0 ]; + if( _.strIs( args[ 0 ] ) ) + o = { filePath : args[ 0 ] } + _.assert( args.length === 1 ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.routine.options_( routine, o ); + + if( o.sync === null ) + o.sync = self.sync; + + return o; +} + +// + +function rightsRead_body( o ) +{ + let self = this; + _.assert( arguments.length === 1, 'Expects single argument' ); + return self.rightsReadAct( o ); +} + +_.routineExtend( rightsRead_body, rightsReadAct ); + +var having = rightsRead_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let rightsRead = _.routine.uniteCloning_replaceByUnite( rightsRead_head, rightsRead_body ); +var having = rightsRead.having; +having.aspect = 'entry'; + +// + +function filesFingerprints( files ) +{ + let self = this; + + if( _.strIs( files ) || files instanceof _.files.FileRecord ) + files = [ files ]; + + _.assert( _.arrayIs( files ) || _.mapIs( files ) ); + + let result = Object.create( null ); + + for( let f = 0 ; f < files.length ; f++ ) + { + let record = self.record( files[ f ] ); + let fingerprint = Object.create( null ); + + if( !record.isActual ) + continue; + + fingerprint.size = record.stat.size; + fingerprint.hash = record.hashRead(); + + result[ record.relative ] = fingerprint; + } + + return result; +} + +var having = filesFingerprints.having = Object.create( null ); + +having.writing = 0; +having.reading = 1; +having.driving = 0; + +// + +/** + * Check if two paths, file stats or FileRecords are associated with the same file or files with same content. + * @example + * let path1 = 'tmp/sample/file1', + path2 = 'tmp/sample/file2', + usingExtraStat = true, + buffer = BufferNode.from( [ 0x01, 0x02, 0x03, 0x04 ] ); + + wTools.fileWrite( { filePath : path1, data : buffer } ); + setTimeout( function() + { + wTools.fileWrite( { filePath : path2, data : buffer } ); + + let sameWithoutTime = wTools.filesCanBeSame( path1, path2 ); // true + + let sameWithTime = wTools.filesCanBeSame( path1, path2, usingExtraStat ); // false + }, 100); + * @param {string|wFileRecord} ins1 first file to compare + * @param {string|wFileRecord} ins2 second file to compare + * @param {boolean} usingExtraStat if this argument sets to true method will additionally check modified time of files, and + if they are different, method returns false. + * @returns {boolean} + * @method filesCanBeSame + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function filesAreSame_head( routine, args ) +{ + let self = this; + let o; + + if( args.length === 3 ) + { + o = + { + ins1 : args[ 0 ], + ins2 : args[ 1 ], + default : args[ 2 ], + } + } + else if( args.length === 2 ) + { + o = + { + ins1 : args[ 0 ], + ins2 : args[ 1 ], + } + } + else + { + o = args[ 0 ]; + _.assert( args.length === 1 ); + } + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.routine.options_( routine, o ); + + return o; +} + +// + +function filesAreSameCommon_body( o ) +{ + let self = this; + + let f = self.recordFactory({ resolvingSoftLink : 0, resolvingTextLink : 0 }); + + o.ins1 = f.record( o.ins1 ); + o.ins2 = f.record( o.ins2 ); + + /* no stat */ + + if( !o.ins1.stat ) + return false; + if( !o.ins2.stat ) + return false; + + let sameEffectiveProvider = o.ins1.factory.effectiveProvider === o.ins2.factory.effectiveProvider; + let inoIsNumberBiggerZero = _.numberIs( o.ins1.stat.ino ) && o.ins1.stat.ino > 0; + // if( o.ins1.factory.effectiveProvider === o.ins2.factory.effectiveProvider && _.numberIs( o.ins1.stat.ino ) && o.ins1.stat.ino > 0 ) + if( sameEffectiveProvider && inoIsNumberBiggerZero ) + { + let could = _.files.stat.areHardLinked( o.ins1.stat, o.ins2.stat ); + if( could === true ) + // if( could === true || could === _.maybe ) /* yyy */ + return true; + } + + /* dir */ + + if( o.ins1.stat.isDir() ) + { + if( !o.ins2.stat.isDir() ) + return false; + + // if( o.ins1.factory.effectiveProvider === o.ins2.factory.effectiveProvider && _.numberIs( o.ins1.stat.ino ) && o.ins1.stat.ino > 0 ) + if( sameEffectiveProvider && inoIsNumberBiggerZero ) + if( self.UsingBigIntForStat ) + return o.ins1.ino === o.ins2.ino; + else + return o.ins1.ino === o.ins2.ino ? null : false; + + // if( o.ins1.ino > 0 ) + // if( o.ins1.ino === o.ins2.ino ) + // return true; + // if( o.ins1.size !== o.ins2.size ) + // return false; + // return o.ins1.real === o.ins2.real; + + return false; + } + + /* soft link */ + + if( o.ins1.isSoftLink || o.ins2.isSoftLink ) + { + if( !o.ins1.isSoftLink || !o.ins2.isSoftLink ) + return false; + return self.pathResolveSoftLink( o.ins1 ) === self.pathResolveSoftLink( o.ins2 ); + } + + /* text link */ + + if( self.usingTextLink ) + if( o.ins1.isTextLink || o.ins2.isTextLink ) + { + if( !o.ins1.isTextLink || !o.ins2.isTextLink ) + return false; + return self.pathResolveTextLink( o.ins1 ) === self.pathResolveTextLink( o.ins2 ); + } + + /* hard linked */ + + // if( o.ins1.factory.effectiveProvider === o.ins2.factory.effectiveProvider && _.numberIs( o.ins1.stat.ino ) && o.ins1.stat.ino > 0 ) + if( sameEffectiveProvider && inoIsNumberBiggerZero ) + if( self.UsingBigIntForStat ) + if( o.ins1.stat.ino === o.ins2.stat.ino ) + return true; + + /* false for empty files */ + + if( !o.ins1.stat.size && !o.ins2.stat.size ) + return true; + + if( !o.ins1.stat.size || !o.ins2.stat.size ) + return false; + + /* size */ + + if( o.ins1.stat.size !== o.ins2.stat.size ) + return false; + + return true; +} + +var defaults = filesAreSameCommon_body.defaults = Object.create( null ); +defaults.ins1 = null; +defaults.ins2 = null; +defaults.default = NaN; + +var having = filesAreSameCommon_body.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 1; +having.aspect = 'body'; + +var operates = filesAreSameCommon_body.operates = Object.create( null ); +operates.ins1 = { pathToRead : 1 }; +operates.ins2 = { pathToRead : 1 }; + +// + +function filesCanBeSame_body( o ) +{ + let self = this; + let result = filesAreSameCommon_body.call( self, o ); + + if( result ) + { + /* hash */ + + try + { + let h1 = o.ins1.hashRead(); + let h2 = o.ins2.hashRead(); + + _.assert( _.strIs( h1 ) && _.strIs( h2 ) ); + + result = h1 === h2; + } + catch( err ) + { + result = o.default; + } + } + + return result; +} + +_.routineExtend( filesCanBeSame_body, filesAreSameCommon_body ); + +let filesCanBeSame = _.routine.uniteCloning_replaceByUnite( filesAreSame_head, filesCanBeSame_body ); +filesCanBeSame.having.aspect = 'entry'; + +// + +function filesAreSameForSure_body( o ) +{ + let self = this; + let result = filesAreSameCommon_body.call( self, o ); + + if( !result ) + return false; + + if( !o.ins1.stat.size && !o.ins2.stat.size ) + return false; + + let file1 = o.ins1.factory.effectiveProvider.fileRead({ filePath : o.ins1.absolute, encoding : 'buffer.bytes' }); + let file2 = o.ins2.factory.effectiveProvider.fileRead({ filePath : o.ins2.absolute, encoding : 'buffer.bytes' }); + debugger; /* xxx */ + return _.entity.identicalShallow( file1, file2 ); + // return _.entityIdentical( file1, file2 ); +} + +_.routineExtend( filesAreSameForSure_body, filesAreSameCommon_body ); + +// + +let filesAreSameForSure = _.routine.uniteCloning_replaceByUnite( filesAreSame_head, filesAreSameForSure_body ); +filesAreSameForSure.having.aspect = 'entry'; + +// -- +// write +// -- + +let streamWriteAct = Object.create( null ); +streamWriteAct.name = 'streamWriteAct'; + +var defaults = streamWriteAct.defaults = Object.create( null ); +defaults.filePath = null; + +var having = streamWriteAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = streamWriteAct.operates = Object.create( null ); +operates.filePath = { pathToWrite : 1 } + +// + +function streamWrite_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let o2 = _.props.extend( null, o ); + + return self.streamWriteAct( o2 ); +} + +_.routineExtend( streamWrite_body, streamWriteAct ); + +var having = streamWrite_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let streamWrite = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, streamWrite_body ); +streamWrite.having.aspect = 'entry'; + +// + +let fileWriteAct = Object.create( null ); +fileWriteAct.name = 'fileWriteAct'; + +var defaults = fileWriteAct.defaults = Object.create( null ); +defaults.filePath = null; +defaults.sync = null; +defaults.data = ''; +defaults.advanced = null; +defaults.encoding = 'meta.original'; +defaults.writeMode = 'rewrite'; + +var having = fileWriteAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = fileWriteAct.operates = Object.create( null ); +operates.filePath = { pathToWrite : 1 } + +// + +function fileWrite_head( routine, args ) +{ + let self = this; + let o; + + if( args[ 1 ] !== undefined ) + { + o = { filePath : args[ 0 ], data : args[ 1 ] }; + _.assert( args.length === 2 ); + } + else + { + o = args[ 0 ]; + _.assert( args.length === 1 ); + _.assert( _.object.isBasic( o ), 'Expects 2 arguments {-o.filePath-} and {-o.data-} to write, or single options map' ); + } + + if( o.verbosity !== undefined ) + { + _global_.logger.styleSet( 'negative' ); + _global_.logger.warn( 'Option verbosity will be deprecated. Please use option logger.' ) + _global_.logger.styleSet( 'default' ); + o.logger = o.verbosity; + delete o.verbosity; + } + + _.assert( o.data !== undefined, 'Expects defined {-o.data-}' ); + _.routine.options_( routine, o ); + self._providerDefaultsApply( o ); + _.assert( _.strIs( o.filePath ), 'Expects string {-o.filePath-}' ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + o.filePath = self.path.normalize( o.filePath ); + + return o; +} + +// + +function fileWrite_body( o ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + + o.encoding = o.encoding || self.encoding; + if( o.encoding === _.unknown ) /* qqq : cover */ + o.encoding = _.files.encoder.deduce({ filePath : o.filePath, returning : 'name', feature : { writer : true } }); + let encoder = _.files.WriteEncoders[ o.encoding ]; + + // _.assert( o.encoding === null || o.encoding === undefined || !!encoder, `WriteEncoder::${o.encoding} is not registered` ); + + let o2 = _.mapOnly_( null, o, self.fileWriteAct.defaults ); + + if( encoder && encoder.onBegin ) + { + let r = encoder.onBegin.call( self, { operation : o2, encoder, data : o2.data } ); + _.sure( r === undefined ); + } + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( !path.isSafe( o.filePath, self.safe ) ) + { + throw path.ErrorNotSafe( 'Writing', o.filePath, o.safe ); + } + + log(); + + /* makingDirectory */ + + if( o.makingDirectory ) + { + self.dirMakeForFile( o.filePath ); + } + + let terminatingLink = !self.resolvingSoftLink && self.isSoftLink( o.filePath ); + + /* xxx : qqq : optimize */ + if( terminatingLink && o.writeMode !== 'rewrite' ) + { + // self.fieldPush( 'resolvingSoftLink', 1 ); + // let readData = self.fileRead({ filePath : o.filePath, encoding : 'meta.original' }); + // let readData = self.fileRead({ filePath : o.filePath, encoding : 'meta.original', resolvingSoftLink : 1 }); + // self.fieldPop( 'resolvingSoftLink', 1 ); + + let writeData = o.data; + let readData; + + if( _.strIs( writeData ) ) + readData = self.fileRead({ filePath : o.filePath, encoding : 'utf8', resolvingSoftLink : 1 }); + else if( _.bufferBytesIs( o.data ) ) + readData = self.fileRead({ filePath : o.filePath, encoding : 'buffer.bytes', resolvingSoftLink : 1 }); + else if( _.bufferNodeIs( o.data ) ) + readData = self.fileRead({ filePath : o.filePath, encoding : 'buffer.node', resolvingSoftLink : 1 }); + else + readData = self.fileRead({ filePath : o.filePath, encoding : 'buffer.raw', resolvingSoftLink : 1 }); + + // if( _.bufferBytesIs( readData ) ) + // writeData = _.bufferBytesFrom( writeData ); + // else if( _.bufferRawIs( readData ) ) + // writeData = _.bufferRawFrom( writeData ); + // else + // _.assert( _.strIs( readData ), 'not implemented for:', _.entity.strType( readData ) ); + + if( o.writeMode === 'append' ) + { + /* xxx : add and use routine from module::wTools */ + if( _.strIs( writeData ) ) + o2.data = _.strJoin([ readData, writeData ]); + else + o2.data = _.bufferJoin( readData, writeData ) + } + else if( o.writeMode === 'prepend' ) + { + if( _.strIs( writeData ) ) + o2.data = _.strJoin([ writeData, readData ]); + else + o2.data = _.bufferJoin( writeData, readData ); + } + else + throw _.err( 'not implemented writeMode :', o.writeMode ) + + o2.writeMode = 'rewrite'; + } + + /* purging */ + + if( o.purging || terminatingLink ) + { + self.filesDelete({ filePath : o2.filePath, throwing : 0 }); + } + + _.assert( self.path.isNormalized( o2.filePath ) ); + + let result = self.fileWriteAct( o2 ); + + if( encoder && encoder.onEnd ) + _.sure( encoder.onEnd.call( self, { operation : o, encoder, data : o.data, result } ) === undefined ); + + return result; + + /* log */ + + function log() + { + // if( o.verbosity >= 3 ) + if( o.logger && o.logger.verbosity >= 3 ) + o.logger.log( ' + writing', _.entity.exportStringDiagnosticShallow( o.data ), 'to', o.filePath ); + } + +} + +_.routineExtend( fileWrite_body, fileWriteAct ); + +var defaults = fileWrite_body.defaults; +// defaults.verbosity = null; +defaults.logger = false; +defaults.makingDirectory = 1; +defaults.purging = 0; + +var having = fileWrite_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +/** + * Writes data to a file. `data` can be a string or a buffer. Creating the file if it does not exist yet. + * Returns wConsequence instance. + * By default method writes data synchronously, with replacing file if exists, and if parent dir hierarchy doesn't + exist, it's created. Method can accept two parameters : string `filePath` and string\buffer `data`, or single + argument : options map, with required 'filePath' and 'data' parameters. + * @example + * + let data = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + options = + { + filePath : 'tmp/sample.txt', + data, + sync : false, + }; + let con = wTools.fileWrite( options ); + con.give( function() + { + console.log('write finished'); + }); + * @param {Object} options write options + * @param {string} options.filePath path to file is written. + * @param {string|BufferNode} [options.data=''] data to write + * @param {boolean} [options.append=false] if this options sets to true, method appends passed data to existing data + in a file + * @param {boolean} [options.sync=true] if this parameter sets to false, method writes file asynchronously. + * @param {boolean} [options.force=true] if it's set to false, method throws exception if parents dir in `filePath` + path is not exists + * @param {boolean} [options.silentError=false] if it's set to true, method will catch error, that occurs during + file writes. + * @param {boolean} [options.verbosity=false] if sets to true, method logs write process. + * @param {boolean} [options.clean=false] if sets to true, method removes file if exists before writing + * @returns {wConsequence} + * @throws {Error} If arguments are missed + * @throws {Error} If passed more then 2 arguments. + * @throws {Error} If `filePath` argument or options.PathFile is not string. + * @throws {Error} If `data` argument or options.data is not string or BufferNode, + * @throws {Error} If options has unexpected property. + * @method fileWrite + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +let fileWrite = _.routine.uniteCloning_replaceByUnite( fileWrite_head, fileWrite_body ); + +fileWrite.having.aspect = 'entry'; + +// _.assert( _.aux.is( fileWrite.encoders ) ); + +// + +/* xxx : qqq : remove body */ +function fileAppend_body( o ) +{ + let self = this; + _.assert( arguments.length === 1, 'Expects single argument' ); + return self.fileWrite( o ); +} + +_.routineExtend( fileAppend_body, fileWriteAct ); + +var defaults = fileAppend_body.defaults; +defaults.writeMode = 'append'; + +var having = fileAppend_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let fileAppend = _.routine.uniteCloning( fileWrite_head, fileAppend_body ); +fileAppend.having.aspect = 'entry'; + +// + +let fileWriteUnknown = _.routine.uniteCloning( fileWrite_head, fileWrite_body ); +fileWriteUnknown.having.aspect = 'entry'; +fileWriteUnknown.defaults.encoding = _.unknown; + +// + +function fileWriteJson_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + /* stringify */ + + let originalData = o.data; + if( o.jsLike ) + { + o.data = _.entity.exportJs( o.data ); + } + else + { + if( o.cloning ) + o.data = _.cloneData({ src : o.data }); + if( o.pretty ) + o.data = _.entity.exportJson( o.data, { cloning : 0 } ); + else + o.data = JSON.stringify( o.data ); + } + + if( o.prefix ) + o.data = o.prefix + o.data; + + /* validate */ + + if( Config.debug && o.pretty ) + { + try /* Dmytro : are this code need extension? */ + { + + // let parsedData = o.jsLike ? _.exec( o.data ) : JSON.parse( o.data ); + // _.assert( _.entityEquivalent( parsedData, originalData ), 'not identical' ); + + } + catch( err ) + { + + self.logger.log( '-' ); + self.logger.error( 'JSON:' ); + self.logger.error( _.entity.exportString( o.data, { levels : 999 } ) ); + self.logger.log( '-' ); + throw _.err( 'Cant convert JSON\n', err ); + } + } + + /* write */ + + // delete o.prefix; + // delete o.pretty; + // delete o.jsLike; + // delete o.cloning; + + let o2 = _.mapOnly_( null, o, self.fileWrite.defaults ); + + return self.fileWrite( o2 ); +} + +_.routineExtend( fileWriteJson_body, fileWrite.body ); + +var defaults = fileWriteJson_body.defaults; +defaults.prefix = ''; +defaults.jsLike = 0; +defaults.pretty = 1; +defaults.sync = null; +defaults.cloning = _.entity.exportJson.defaults.cloning; +_.assert( defaults.cloning !== undefined ); + +var having = fileWriteJson_body.having; +having.driving = 0; +having.aspect = 'body'; + +_.assert( _.boolLike( _.entity.exportJson.defaults.cloning ) ); + +// + +/** + * Writes data as json string to a file. `data` can be a any primitive type, object, array, array like. Method can + accept options similar to fileWrite method, and have similar behavior. + * Returns wConsequence instance. + * By default method writes data synchronously, with replacing file if exists, and if parent dir hierarchy doesn't + exist, it's created. Method can accept two parameters : string `filePath` and string\buffer `data`, or single + argument : options map, with required 'filePath' and 'data' parameters. + * @example + * const fileProvider = _.FileProvider.Default(); + * let fs = require('fs'); + let data = { a : 'hello', b : 'world' }, + let con = fileProvider.fileWriteJson( 'tmp/sample.json', data ); + // file content : { "a" : "hello", "b" : "world" } + + * @param {Object} o write options + * @param {string} o.filePath path to file is written. + * @param {string|BufferNode} [o.data=''] data to write + * @param {boolean} [o.append=false] if this options sets to true, method appends passed data to existing data + in a file + * @param {boolean} [o.sync=true] if this parameter sets to false, method writes file asynchronously. + * @param {boolean} [o.force=true] if it's set to false, method throws exception if parents dir in `filePath` + path is not exists + * @param {boolean} [o.silentError=false] if it's set to true, method will catch error, that occurs during + file writes. + * @param {boolean} [o.verbosity=false] if sets to true, method logs write process. + * @param {boolean} [o.clean=false] if sets to true, method removes file if exists before writing + * @param {string} [o.pretty=''] determines data stringify method. + * @returns {wConsequence} + * @throws {Error} If arguments are missed + * @throws {Error} If passed more then 2 arguments. + * @throws {Error} If `filePath` argument or options.PathFile is not string. + * @throws {Error} If options has unexpected property. + * @method fileWriteJson + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +let fileWriteJson = _.routine.uniteCloning_replaceByUnite( fileWrite_head, fileWriteJson_body ); +fileWriteJson.having.aspect = 'entry'; + +// + +let fileWriteJs = _.routine.uniteCloning_replaceByUnite( fileWrite_head, fileWriteJson_body ); + +var defaults = fileWriteJs.defaults; +defaults.jsLike = 1; + +var having = fileWriteJs.having; +having.driving = 0; +having.aspect = 'body'; + +// + +function fileTouch_head( routine, args ) +{ + let self = this; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 || args.length === 2 ); + + let o = args[ 0 ]; + + if( args.length === 2 ) + { + o = + { + filePath : self.path.from( args[ 0 ] ), + data : args[ 1 ] + } + } + else + { + if( self.path.like( o ) ) + o = { filePath : self.path.from( o ) }; + } + + _.routine.options_( routine, o ); + self._providerDefaultsApply( o ); + _.assert( _.strIs( o.filePath ), 'Expects string {-o.filePath-}, but got', _.entity.strType( o.filePath ) ); + + return o; +} + +// + +function fileTouch_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( self.fileExists( o.filePath ) ) + { + // let stat = self.statRead( o.filePath ); + if( !self.resolvedIsTerminal( o.filePath ) ) + { + throw _.err( o.filePath, 'is not terminal' ); + return null; + } + o.data = self.fileRead({ filePath : o.filePath, encoding : 'meta.original' }); + } + else + { + o.data = ''; + } + + // o.data = stat ? self.fileRead({ filePath : o.filePath, encoding : 'meta.original' }) : ''; + self.fileWrite( o ); + + return self; +} + +_.routineExtend( fileTouch_body, fileWrite.body ); + +var defaults = fileTouch_body.defaults; +defaults.data = null; + +var having = fileTouch_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let fileTouch = _.routine.uniteCloning_replaceByUnite( fileTouch_head, fileTouch_body ); +fileTouch.having.aspect = 'entry'; + +// + +let timeWriteAct = Object.create( null ); +timeWriteAct.name = 'timeWriteAct'; + +var defaults = timeWriteAct.defaults = Object.create( null ); +defaults.filePath = null; +defaults.atime = null; +defaults.mtime = null; +/* qqq : add and cover option sync */ + +var having = timeWriteAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = timeWriteAct.operates = Object.create( null ); +operates.filePath = { pathToWrite : 1 } + +// + +function timeWrite_head( routine, args ) +{ + let self = this; + let o; + + if( args.length === 3 ) + o = + { + filePath : args[ 0 ], + atime : args[ 1 ], + mtime : args[ 2 ], + } + else if( args.length === 2 ) + { + let stat = args[ 1 ]; + if( _.strIs( stat ) ) + stat = self.statResolvedRead({ filePath : stat, sync : 1, throwing : 1 }) + o = + { + filePath : args[ 0 ], + atime : stat.atime, + mtime : stat.mtime, + } + } + else + { + _.assert( args.length === 1 ); + o = args[ 0 ]; + } + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.routine.options_( routine, o ); + + return o; +} + +// + +function timeWrite_body( o ) +{ + let self = this; + _.assert( arguments.length === 1, 'Expects single argument' ); + return self.timeWriteAct( o ); +} + +_.routineExtend( timeWrite_body, timeWriteAct ); + +var having = timeWrite_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let timeWrite = _.routine.uniteCloning_replaceByUnite( timeWrite_head, timeWrite_body ); +timeWrite.having.aspect = 'entry'; + +// + +let rightsWriteAct = Object.create( null ); +rightsWriteAct.name = 'rightsWriteAct'; + +var defaults = rightsWriteAct.defaults = Object.create( null ); +defaults.filePath = null; +defaults.addRights = null; +defaults.delRights = null; +defaults.setRights = null; +defaults.sync = null; + +var having = rightsWriteAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = rightsWriteAct.operates = Object.create( null ); +operates.filePath = { pathToWrite : 1 } + +// + +function rightsWrite_pre_functor( defaultKey ) +{ + + return function rightsWrite_head( routine, args ) + { + let self = this; + let o; + + if( args.length === 2 ) + { + let rights = args[ 1 ]; + if( _.strIs( rights ) ) + rights = self.rightsRead({ filePath : stat, sync : 1, throwing : 1 }) + o = + { + filePath : args[ 0 ], + [ defaultKey ] : rights, + } + } + else + { + _.assert( args.length === 1 ); + o = args[ 0 ]; + } + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.routine.options_( routine, o ); + + if( o.sync === null ) + o.sync = self.sync; + + return o; + } + +} + +// + +function rightsWrite_body( o ) +{ + let self = this; + _.assert( arguments.length === 1, 'Expects single argument' ); + return self.rightsWriteAct( o ); +} + +_.routineExtend( rightsWrite_body, rightsWriteAct ); + +var having = rightsWrite_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let rightsWrite = _.routine.uniteCloning_replaceByUnite( rightsWrite_pre_functor( 'setRights' ), rightsWrite_body ); +var having = rightsWrite.having; +having.aspect = 'entry'; + +let rightsAdd = _.routine.uniteCloning_replaceByUnite( rightsWrite_pre_functor( 'addRights' ), rightsWrite_body ); +var having = rightsAdd.having; +having.aspect = 'entry'; + +let rightsDel = _.routine.uniteCloning_replaceByUnite( rightsWrite_pre_functor( 'delRights' ), rightsWrite_body ); +var having = rightsDel.having; +having.aspect = 'entry'; + +// + +let fileDeleteAct = Object.create( null ); +fileDeleteAct.name = 'fileDeleteAct'; + +var defaults = fileDeleteAct.defaults = Object.create( null ); +defaults.filePath = null; +defaults.sync = null; + +var having = fileDeleteAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = fileDeleteAct.operates = Object.create( null ); +operates.filePath = { pathToWrite : 1 } + +// + +function fileDelete_body( o ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + let result = null; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.numberIs( o.safe ) ); + + if( _.arrayIs( o.filePath ) ) + { + if( o.sync ) + { + for( let f = 0 ; f < o.filePath.length ; f++ ) + { + let o2 = _.props.extend( null, o ); + o2.filePath = o.filePath[ f ]; + fileDelete_body.call( self, o2 ); + } + return; + } + else + { + let con = new _.Consequence().take( null ); + let cons = []; + for( let f = 0 ; f < o.filePath.length ; f++ ) + { + let o2 = _.props.extend( null, o ); + o2.filePath = o.filePath[ f ]; + cons[ f ] = fileDelete_body.call( self, o2 ); + } + con.andKeep( cons ); + return con; + } + } + + /* is safe */ + + o.filePath = self.pathResolveLinkTailChain + ({ + filePath : o.filePath, + resolvingSoftLink : o.resolvingSoftLink, + resolvingTextLink : o.resolvingTextLink, + }); + + _.assert( path.s.allAreAbsolute( o.filePath ) ); + if( !path.s.allAreSafe( o.filePath, o.safe ) ) + { + throw path.ErrorNotSafe( 'Deleting', o.filePath, o.safe ); + } + + /* act */ + + act( o.filePath[ 0 ] ); + + return result; + + /* */ + + function act( filePath ) + { + + let o2 = _.props.extend( null, o ); + + o2.filePath = filePath; + + delete o2.throwing; + delete o2.verbosity; + delete o2.resolvingSoftLink; + delete o2.resolvingTextLink; + delete o2.safe; + + /* */ + + try + { + result = self.fileDeleteAct( o2 ); + } + catch( err ) + { + log( 0 ); + _.assert( !!o.sync ); + if( o.throwing ) + throw _.err( err ); + return null; + } + + /* */ + + if( o.sync ) + { + log( 1 ); + } + else + result.finally( function( err, arg ) + { + log( !err ); + if( err ) + { + if( o.throwing ) + throw err; + _.errAttend( err ); + return null; + } + return arg; + }); + + } + + /* */ + + function log( ok ) + { + if( !( o.verbosity >= 2 ) ) + return; + if( ok ) + self.logger.log( ' - fileDelete ' + o.filePath ); + else + self.logger.log( ' ! failed fileDelete ' + o.filePath ); + } + +} + +_.routineExtend( fileDelete_body, fileDeleteAct ); + +var defaults = fileDelete_body.defaults; +defaults.throwing = null; +defaults.verbosity = null; +defaults.safe = null; +defaults.resolvingSoftLink = 0; +defaults.resolvingTextLink = 0; + +var having = fileDelete_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +/** + * Deletes a terminal file or empty directory. + * @param {String|Object} o Path to a file or object with options. + * @param {String|FileRecord} [ o.filePath=null ] Path to a file or instance of FileRecord @see{@link wFileRecord} + * @param {Boolean} [ o.sync=true ] Determines in which way file stats will be readed : true - synchronously, otherwise - asynchronously. + * In asynchronous mode returns wConsequence. + * @param {Boolean} [ o.throwing=false ] Controls error throwing. Returns null if error occurred and ( throwing ) is disabled. + * @returns {undefined|wConsequence|null} + * If ( o.filePath ) doesn't exist and ( o.throwing ) is disabled - returns null. + * If ( o.sync ) mode is disabled - returns Consequence instance @see{@link wConsequence }. + * + * @example + * wTools.fileProvider.fileDelete( './existingDir/test.txt' ); + * + * @example + * let consequence = wTools.fileProvider.fileDelete + * ({ + * filePath : './existingDir/test.txt', + * sync : 0 + * }); + * consequence.give( ( err, result ) => + * { + * if( err ) + * throw err; + * + * console.log( result ); + * }) + * + * @method fileDelete + * @throws { Exception } If no arguments provided. + * @throws { Exception } If ( o.filePath ) is not a String or instance of wFileRecord. + * @throws { Exception } If ( o.filePath ) path to a file doesn't exist or file is an directory with files. + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +let fileDelete = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, fileDelete_body ); +fileDelete.having.aspect = 'entry'; + +// + +let fileResolvedDelete = _.routine.uniteCloning_replaceByUnite({ head : _preFilePathScalarWithProviderDefaults, body : fileDelete_body, name : 'fileResolvedDelete' }); +fileResolvedDelete.defaults.resolvingSoftLink = null; +fileResolvedDelete.defaults.resolvingTextLink = null; +fileResolvedDelete.having.aspect = 'entry'; + +// + +let dirMakeAct = Object.create( null ); +dirMakeAct.name = 'dirMakeAct'; + +var defaults = dirMakeAct.defaults = Object.create( null ); +defaults.filePath = null; +defaults.sync = null; + +var having = dirMakeAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = dirMakeAct.operates = Object.create( null ); +operates.filePath = { pathToWrite : 1 } + +// + +function dirMake_body( o ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( path.isNormalized( o.filePath ) ); + + let o2 = { filePath : o.filePath } + let filePath = self.pathResolveLinkFull( o2 ).absolutePath; + + if( self.fileExists( filePath ) ) + { + + let stat = o2.stat; + _.assert( !!stat, () => 'No access to file ' + filePath ); + if( stat.isTerminal() ) + if( o.rewritingTerminal ) + self.fileDelete( filePath ); + else + return handleError( _.err( 'Cant rewrite terminal file', _.strQuote( filePath ), 'by directory file.' ) ); + + if( stat.isDir() ) + { + if( !o.recursive ) + return handleError( _.err( 'File already exists:', _.strQuote( filePath ) ) ); + else + return o.sync ? undefined : new _.Consequence().take( null ); + } + + } + + let exists = self.fileExists( path.dir( filePath ) ); + + if( !o.recursive && !exists ) + return handleError( _.err( 'Directory', _.strQuote( filePath ), ' doesn\'t exist!. Use {-o.recursive-} option to create it.' ) ); + + let splits = [ filePath ]; + let dir = filePath; + + if( !exists ) + while( !exists ) + { + dir = path.dir( dir ); + + if( dir === '/' ) + break; + + // exists = !!self.statResolvedRead( dir ); + exists = self.fileExists( dir ); + + if( !exists ) + { + _.arrayPrependOnce( splits, dir ); + } + else + { + break; + } + } + + /* */ + + if( o.sync ) + { + for( let i = 0; i < splits.length; i++ ) + onPart.call( self, splits[ i ] ); + } + else + { + let con = new _.Consequence().take( null ); + for( let i = 0; i < splits.length; i++ ) + con.then( _.routineSeal( self, onPart, [ splits[ i ] ] ) ); + + return con; + } + + /* */ + + function onPart( filePath ) + { + let self = this; + let o2 = _.mapOnly_( null, o, self.dirMakeAct.defaults ); + o2.filePath = filePath; + return self.dirMakeAct( o2 ); + } + + /* */ + + function handleError( err ) + { + if( o.sync ) + throw err; + else + return new _.Consequence().error( err ); + } + +} + +_.routineExtend( dirMake_body, dirMakeAct ); + +var defaults = dirMake_body.defaults; +defaults.recursive = 1; +defaults.rewritingTerminal = 1; + +var having = dirMake_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let dirMake = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, dirMake_body ); +dirMake.having.aspect = 'entry'; + +// + +function dirMakeForFile_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + o.filePath = self.path.dir( o.filePath ); + + return self.dirMake( o ); +} + +_.routineExtend( dirMakeForFile_body, dirMakeAct ); + +var defaults = dirMakeForFile_body.defaults; +defaults.recursive = 1; + +var having = dirMakeForFile_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let dirMakeForFile = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, dirMakeForFile_body ); +dirMakeForFile.having.aspect = 'entry'; + +// -- +// locking +// -- + +let fileLockDefaults = Object.create( null ); +fileLockDefaults.filePath = null +fileLockDefaults.sync = 1 +fileLockDefaults.throwing = 1 +fileLockDefaults.timeOut = 5000 +fileLockDefaults.id = null + +// + +let fileLockAct = Object.create( null ); +fileLockAct.name = 'fileLockAct'; + +var defaults = fileLockAct.defaults = Object.create( fileLockDefaults ); +defaults.locking = 0; +defaults.sharing = 'process' // 0, 'process', 'group' +defaults.waiting = 0; + +var having = fileLockAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = fileLockAct.operates = Object.create( null ); +operates.filePath = { pathToWrite : 1 } + +// + +function fileLock_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.numberIs( o.timeOut ) ); + + let con = _.Consequence.Try( () => self.fileLockAct( o ) ); + + con.finally( ( err, got ) => + { + if( !err ) + return got; + + if( o.throwing ) + throw err; + _.errAttend( err ); + return null; + }) + + if( o.sync ) + return con.sync(); + + return con; +} + +_.routineExtend( fileLock_body, fileLockAct ); + +var having = fileLock_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let fileLock = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, fileLock_body ); +dirMakeForFile.having.aspect = 'entry'; + +// + +let fileUnlockAct = Object.create( null ); +fileUnlockAct.name = 'fileUnlockAct'; + +var defaults = fileUnlockAct.defaults = Object.create( fileLockDefaults ); + +var having = fileUnlockAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = fileUnlockAct.operates = Object.create( null ); +operates.filePath = { pathToWrite : 1 } + +// + +function fileUnlock_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.numberIs( o.timeOut ) ); + + let con = _.Consequence.Try( () => self.fileUnlockAct( o ) ); + + con.finally( ( err, got ) => + { + if( !err ) + return got; + + if( o.throwing ) + throw err; + _.errAttend( err ); + return null; + }) + + if( o.sync ) + return con.sync(); + + return con; +} + +_.routineExtend( fileUnlock_body, fileUnlockAct ); + +var having = fileUnlock_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let fileUnlock = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, fileUnlock_body ); +dirMakeForFile.having.aspect = 'entry'; + +// + +let fileIsLockedAct = Object.create( null ); +fileUnlockAct.name = 'fileUnlockAct'; + +var defaults = fileIsLockedAct.defaults = Object.create( fileLockDefaults ); + +var having = fileIsLockedAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = fileIsLockedAct.operates = Object.create( null ); +operates.filePath = { pathToWrite : 1 } + +// + +function fileIsLocked_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let con = _.Consequence.Try( () => self.fileIsLockedAct( o ) ); + + con.finally( ( err, got ) => + { + if( !err ) + return got; + + if( o.throwing ) + throw err; + _.errAttend( err ); + return null; + }) + + if( o.sync ) + return con.sync(); + + return con; +} + +_.routineExtend( fileIsLocked_body, fileIsLockedAct ); + +var having = fileIsLocked_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let fileIsLocked = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, fileIsLocked_body ); +dirMakeForFile.having.aspect = 'entry'; + +// -- +// linkingAction +// -- + +let fileRenameAct = Object.create( null ); +fileRenameAct.name = 'fileRenameAct'; + +var defaults = fileRenameAct.defaults = Object.create( null ); +defaults.dstPath = null; +defaults.srcPath = null; +defaults.relativeDstPath = null; +defaults.relativeSrcPath = null; +defaults.sync = null; +defaults.context = null; + +var having = fileRenameAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = fileRenameAct.operates = Object.create( null ); +operates.dstPath = { pathToWrite : 1 } +operates.srcPath = { pathToRead : 1 } +operates.relativeDstPath = { pathToWrite : 1 } +operates.relativeSrcPath = { pathToRead : 1 } + +// + +/** + * Changes name of the file. + * Takes single argument - object with options or two arguments : destination( o.dstPath ) and source( o.srcPath ) paths. + * Routine changes name of the source file if ( o.srcPath ) and ( dstPath ) have different file names. Also moves source file to the new location( dstPath ) + * if parent dirs of ( o.srcPath ) and ( o.dstPath ) are not same. If ( o.dstPath ) path exists and ( o.rewriting ) is enabled, the destination file can be overwritten. + * + * @param {Object} o Object with options. + * @param {String|FileRecord} [ o.dstPath=null ] - Destination path or instance of FileRecord @see{@link wFileRecord}. Path must be absolute. + * @param {String|FileRecord} [ o.srcPath=null ] - Source path or instance of FileRecord @see{@link wFileRecord}. Path can be relative to destination path or absolute. + * In case of FileRecord instance, absolute path will be used. + * @param {Boolean} [ o.sync=true ] - Determines in which way file will be renamed : true - synchronously, otherwise - asynchronously. + * In asynchronous mode returns wConsequence. + * @param {Boolean} [ o.throwing=true ] - Controls error throwing. Returns false if error occurred and ( o.throwing ) is disabled. + * @param {Boolean} [ o.rewriting=false ] - Controls rewriting of the destination file( o.dstPath ). + * @returns {Boolean|wConsequence} Returns true after successful rename, otherwise false is returned. Also returns false if an error occurs and ( o.throwing ) is disabled. + * In async mode returns Consequence instance @see{@link wConsequence } with same result. + * + * @example + * wTools.fileProvider.fileRename( '/existingDir/notExistingDst', '/existingDir/existingSrc' ); + * //returns true + * + * @example + * wTools.fileProvider.fileRename( '/existingDir/existingSrc', '/existingDir/existingSrc' ); + * //returns false + * + * @example + * wTools.fileProvider.fileRename + * ({ + * dstPath : '/existingDir/notExistingDst', + * srcPath : '/existingDir/notExistingSrc', + * throwing : 1 + * }); + * //throws an Error + * + * @example + * wTools.fileProvider.fileRename + * ({ + * dstPath : '/existingDir/notExistingDst', + * srcPath : '/existingDir/notExistingSrc', + * throwing : 0 + * }); + * //returns false + * + * @example + * wTools.fileProvider.fileRename + * ({ + * dstPath : '/existingDir/notExistingDst', + * srcPath : '/existingDir/notExistingSrc', + * throwing : 0 + * }); + * //returns false + * + * @example + * wTools.fileProvider.fileRename + * ({ + * dstPath : '/existingDir/existingDst', + * srcPath : '/existingDir/existingSrc', + * throwing : 0, + * rewriting : 0 + * }); + * //returns false + * + * @example + * wTools.fileProvider.fileRename + * ({ + * dstPath : '/existingDir/existingDst', + * srcPath : '/existingDir/existingSrc', + * throwing : 0, + * rewriting : 1 + * }); + * //returns true + * + * @example + * let consequence = wTools.fileProvider.fileRename + * ({ + * dstPath : '/existingDir/notExistingDst', + * srcPath : '/existingDir/existingSrc', + * sync : 0 + * }); + * consequence.give( ( err, got ) => + * { + * if( err ) + * throw err; + * + * console.log( got ); // true + * }) + * + * @method fileRename + * @throws { Exception } If no arguments provided. + * @throws { Exception } If ( o.srcPath ) is not a String or instance of wFileRecord. + * @throws { Exception } If ( o.dstPath ) is not a String or instance of wFileRecord. + * @throws { Exception } If ( o.srcPath ) path to a file doesn't exist. + * @throws { Exception } If destination( o.dstPath ) and source( o.srcPath ) files exist and ( o.rewriting ) is disabled. + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function _fileRenameDo( c ) +{ + let self = this; + let o = c.options; + + _.assert( _.fileStatIs( c.srcStat ) || c.srcStat === null ); + + let srcStat = c.srcStat; + + if( o.resolvingSrcSoftLink || o.resolvingSrcTextLink ) + if( self.fileExists( c.originalSrcResolvedPath ) ) + c.srcStat = self.statRead({ filePath : c.originalSrcResolvedPath, sync : 1, resolvingSoftLink : 0, resolvingTextLink : 0 }); + + if( c.srcStat === null ) + return null; + + if( o.onlyMoving ) + return self.fileRenameAct( c.options2 ); + + if( c.srcStat.isSoftLink() ) + { + let chain; + + if( c.srcResolvedStat === null && o.resolvingSrcSoftLink === 2 ) + return null; + + if( !o.resolvingSrcSoftLink ) + { + chain = { result : [ c.originalSrcResolvedPath ], found : [ c.originalSrcResolvedPath ] } + let resolved = self.pathResolveSoftLink( c.originalSrcResolvedPath ); + chain.result.push( resolved ); + if( self.path.isRelative( resolved ) ) + resolved = self.path.resolve( c.originalSrcResolvedPath ) + chain.found.push( resolved ); + } + else + { + chain = + { + filePath : c.originalSrcResolvedPath, + resolvingSoftLink : o.resolvingSrcSoftLink, + resolvingTextLink : o.resolvingSrcTextLink, + allowingCycled : o.allowingCycled, + allowingMissed : o.allowingMissed, + preservingRelative : 1, + throwing : 1 + } + self.pathResolveLinkTailChain( chain ); + + if( c.srcResolvedStat === null ) + { + _.assert( chain.found[ chain.found.length -1 ] === null ); + _.assert( chain.result[ chain.result.length -1 ] === null ); + chain.found.pop(); + chain.result.pop(); + } + } + + o.srcPath = chain.found.pop(); + o.relativeSrcPath = chain.result.pop() + + let con = _.Consequence.Try( () => + { + let result; + if( o.resolvingSrcSoftLink === 2 ) + { + c.options2.srcPath = o.srcPath; + c.options2.relativeSrcPath = o.relativeSrcPath; + result = self.fileRenameAct( c.options2 ); + } + else + { + result = self.softLinkAct + ({ + dstPath : o.dstPath, + srcPath : o.srcPath, + relativeDstPath : o.relativeDstPath, + relativeSrcPath : o.relativeSrcPath, + sync : o.sync, + type : null, + context : c, + }); + } + return o.sync ? true : result; + }) + .then( () => + { + _.each( chain.found, ( path ) => self.fileDelete( path ) ) + return true; + }) + + if( o.sync ) + return con.sync(); + + return con; + } + else if( c.srcStat.isTextLink() ) + { + let chain; + + if( c.srcResolvedStat === null && o.resolvingSrcTextLink === 2 ) + return null; + + if( !o.resolvingSrcTextLink ) + { + chain = { result : [ c.originalSrcResolvedPath ], found : [ c.originalSrcResolvedPath ] } + let resolved = self.pathResolveTextLink( c.originalSrcResolvedPath ); + chain.result.push( resolved ); + if( self.path.isRelative( resolved ) ) + resolved = self.path.resolve( c.originalSrcResolvedPath ) + chain.found.push( resolved ); + } + else + { + chain = + { + filePath : c.originalSrcResolvedPath, + resolvingSoftLink : o.resolvingSrcSoftLink, + resolvingTextLink : o.resolvingSrcTextLink, + allowingCycled : o.allowingCycled, + allowingMissed : o.allowingMissed, + preservingRelative : 1, + throwing : 1 + } + self.pathResolveLinkTailChain( chain ); + + if( c.srcResolvedStat === null ) + { + _.assert( chain.found[ chain.found.length -1 ] === null ); + _.assert( chain.result[ chain.result.length -1 ] === null ); + chain.found.pop(); + chain.result.pop(); + } + } + + o.srcPath = chain.found.pop(); + o.relativeSrcPath = chain.result.pop() + + let con = _.Consequence.Try( () => + { + let result; + if( o.resolvingSrcTextLink === 2 ) + { + c.options2.srcPath = o.srcPath; + c.options2.relativeSrcPath = o.relativeSrcPath; + result = self.fileRenameAct( c.options2 ); + } + else + { + result = self.textLinkAct + ({ + dstPath : o.dstPath, + srcPath : o.srcPath, + relativeDstPath : o.relativeDstPath, + relativeSrcPath : o.relativeSrcPath, + sync : o.sync, + context : c, + }); + } + return o.sync ? true : result; + }) + .then( () => + { + _.each( chain.found, ( path ) => self.fileDelete( path ) ) + return true; + }) + + if( o.sync ) + return con.sync(); + + return con; + } + else + { + let dstIsHardLink = c.dstStat && c.dstStat.isHardLink(); + + if( !dstIsHardLink ) + return self.fileRenameAct( c.options2 ); + + let con = _.Consequence.Try( () => + { + if( !c.srcStat.isHardLink() ) + return true; + let result = self.hardLinkBreak({ filePath : c.options2.srcPath, sync : o.sync }); + return o.sync ? true : result; + }) + .then( () => + { + let o2 = _.props.extend( null, c.options2 ); + let result = self.fileCopyAct( o2 ); + return o.sync ? true : result; + }) + .then( () => + { + self.fileDelete( c.options2.srcPath ); + return true; + }) + + if( o.sync ) + return con.sync(); + + return con; + } +} + +_.routineExtend( _fileRenameDo, fileRenameAct ); + +let fileRename = _.files.linker.functor +({ + actMethodName : 'fileRenameAct', + onDo : _fileRenameDo, + skippingSamePath : true, + skippingMissed : false, +}); + +var defaults = fileRename.body.defaults; + +defaults.rewriting = 0; +defaults.rewritingDirs = 0; +defaults.makingDirectory = 0; /* qqq2 : change default to makingDirectory : 1 */ +defaults.allowingMissed = 0; +defaults.allowingCycled = 0; +defaults.throwing = null; +defaults.verbosity = null; +defaults.onlyMoving = 0; + +defaults.resolvingSrcSoftLink = 1; +defaults.resolvingSrcTextLink = 0; +defaults.resolvingDstSoftLink = 0; +defaults.resolvingDstTextLink = 0; + +defaults.breakingDstHardLink = 1; + +_.props.extend( fileRename.defaults, fileRename.body.defaults ); + +// + +let fileCopyAct = Object.create( null ); +fileCopyAct.name = 'fileCopyAct'; + +var defaults = fileCopyAct.defaults = Object.create( null ); +defaults.dstPath = null; +defaults.srcPath = null; +defaults.relativeDstPath = null; +defaults.relativeSrcPath = null; +defaults.sync = null; +defaults.context = null; /* xxx : investigate */ + +var having = fileCopyAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = fileCopyAct.operates = Object.create( null ); +operates.dstPath = { pathToWrite : 1 } +operates.srcPath = { pathToRead : 1 } +operates.relativeDstPath = { pathToWrite : 1 } +operates.relativeSrcPath = { pathToRead : 1 } + +// + +/** + * Creates copy of a file. Accepts two arguments: ( srcPath ), ( dstPath ) or options map. + * Returns true if operation is finished successfully or if source and destination paths are equal. + * Otherwise throws error with corresponding message or returns false, it depends on ( o.throwing ) property. + * In asynchronously mode returns wConsequence instance. + * @example + const fileProvider = _.FileProvider.Default(); + let result = fileProvider.fileCopy( 'src.txt', 'dst.txt' ); + console.log( result );// true + let stats = fileProvider.statResolvedRead( 'dst.txt' ); + console.log( stats ); // returns Stats object + * @example + const fileProvider = _.FileProvider.Default(); + let consequence = fileProvider.fileCopy + ({ + srcPath : 'src.txt', + dstPath : 'dst.txt', + sync : 0 + }); + consequence.give( function( err, got ) + { + if( err ) + throw err; + console.log( got ); // true + let stats = fileProvider.statResolvedRead( 'dst.txt' ); + console.log( stats ); // returns Stats object + }); + + * @param {Object} o - options map. + * @param {string} o.srcPath path to source file. + * @param {string} o.dstPath path where to copy source file. + * @param {boolean} [o.sync=true] If set to false, method will copy file asynchronously. + * @param {boolean} [o.rewriting=true] Enables rewriting of destination path if it exists. + * @param {boolean} [o.throwing=true] Enables error throwing. Returns false if error occurred and ( o.throwing ) is disabled. + * @param {boolean} [o.verbosity=true] Enables logging of copy process. + * @returns {wConsequence} + * @throws {Error} If missed argument, or pass more than 2. + * @throws {Error} If dstPath or dstPath is not string. + * @throws {Error} If options map has unexpected property. + * @throws {Error} If ( o.rewriting ) is false and destination path exists. + * @throws {Error} If path to source file( srcPath ) not exists and ( o.throwing ) is enabled, otherwise returns false. + * @method fileCopy + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function _fileCopySizeCheck( c ) +{ + let self = this; + let o = c.options; + + if( c.srcStat.isLink() ) + if( c.srcResolvedStat === null ) + { + let isSoftLink = c.srcStat.isSoftLink(); + let isTextLink = c.srcStat.isTextLink(); + + if( ( o.resolvingSrcSoftLink === 2 && isSoftLink ) || ( o.resolvingSrcTextLink === 2 && isTextLink ) ) + { + if( self.fileExists( o.dstPath ) ) + throw _.err( `Destination file ${o.dstPath} shouldn't exist` ); + } + else + { + let dstPath = isSoftLink ? self.pathResolveSoftLink( o.dstPath ) : self.pathResolveTextLink( o.dstPath ); + let srcPath = o.relativeSrcPath; + if( self.path.isGlobal( o.relativeSrcPath ) ) + srcPath = self.path.localFromGlobal( o.relativeSrcPath ); + + if( dstPath !== srcPath ) + throw _.err( `Destination file ${o.dstPath} should be a link to ${o.relativeSrcPath}` ); + } + } +} + +// + +function _fileCopyVerify2( c ) +{ + let self = this; + let o = c.options; + + _.assert( _.strIs( o.srcPath ) ); + _.assert( _.fileStatIs( c.srcStat ) || c.srcStat === null ); + + if( c.srcStat === undefined ) + c.srcStat = self.statRead({ filePath : o.srcPath, sync : 1 }); + + if( !o.breakingDstHardLink ) + { + let linked = self.areHardLinked([ o.dstPath, o.srcPath ]); + if( linked || linked === _.maybe ) + c.end( false ); + } +} + +// + +function _fileCopyDo( c ) +{ + let self = this; + let o = c.options; + + _.assert( _.fileStatIs( c.srcStat ) || c.srcStat === null ); + + let srcStat = c.srcStat; + + if( o.resolvingSrcSoftLink || o.resolvingSrcTextLink ) + if( self.fileExists( c.originalSrcResolvedPath ) ) + c.srcStat = self.statRead({ filePath : c.originalSrcResolvedPath, sync : 1, resolvingSoftLink : 0, resolvingTextLink : 0 }); + + if( c.srcStat === null ) + return null; + + if( c.srcStat.isSoftLink() ) + { + + if( o.resolvingSrcSoftLink === 2 ) + { + if( c.srcResolvedStat === null ) + return null; + return act(); + } + + return self.softLinkAct + ({ + dstPath : o.dstPath, + srcPath : o.srcPath, + relativeDstPath : o.relativeDstPath, + relativeSrcPath : o.relativeSrcPath, + sync : o.sync, + type : null, + context : c, + }); + } + else if( c.srcStat.isTextLink() ) + { + + if( o.resolvingSrcTextLink === 2 ) + { + if( c.srcResolvedStat === null ) + return null; + return act(); + } + + /* qqq : cover, please */ + return self.textLinkAct + ({ + dstPath : o.dstPath, + srcPath : o.srcPath, + relativeDstPath : o.relativeDstPath, + relativeSrcPath : o.relativeSrcPath, + sync : o.sync, + context : c, + }); + + } + else + { + return act(); + } + + /* */ + + function act() + { + + if( o.resolvingSrcSoftLink === 2 || o.resolvingSrcTextLink === 2 ) + { + if( c.srcResolvedStat.isDir() ) + return self.dirMakeAct + ({ + filePath : o.dstPath, + sync : o.sync + }) + } + else + { + if( srcStat.isDir() ) + { + throw _.err( 'Cant copy directory ' + _.strQuote( o.srcPath ) + ', consider method filesReflect' ); + } + } + + let con = _.Consequence.Try( () => + { + if( o.breakingDstHardLink && self.isHardLink( o.dstPath ) ) + return self.hardLinkBreak({ filePath : o.dstPath, sync : o.sync }); + return true; + }); + + con.then( () => + { + let result = self.fileCopyAct + ({ + dstPath : o.dstPath, + srcPath : o.srcPath, + relativeDstPath : o.relativeDstPath, + relativeSrcPath : o.relativeSrcPath, + sync : o.sync, + context : c, + }); + return o.sync ? true : result; + }) + + if( o.sync ) + return con.sync(); + + return con; + } + +} + +_.routineExtend( _fileCopyDo, fileCopyAct ); + +let fileCopy = _.files.linker.functor +({ + actMethodName : 'fileCopyAct', + onDo : _fileCopyDo, + onVerify2 : _fileCopyVerify2, + onSizeCheck : _fileCopySizeCheck, + skippingSamePath : true, + skippingMissed : false, + linkMaybe : true, +}); + +var defaults = fileCopy.body.defaults; + +defaults.rewriting = 1; +defaults.rewritingDirs = 0; +defaults.makingDirectory = 0; /* qqq2 : change default to makingDirectory : 1 */ +defaults.allowingMissed = 0; +defaults.allowingCycled = 0; +defaults.throwing = null; +defaults.verbosity = null; + +defaults.resolvingSrcSoftLink = 1; +defaults.resolvingSrcTextLink = 0; + +defaults.breakingDstHardLink = 0; +defaults.resolvingDstSoftLink = 0; +defaults.resolvingDstTextLink = 0; + +_.props.extend( fileCopy.defaults, fileCopy.body.defaults ); + +// + +/** + * Creates hard link( new name ) to existing source( o.srcPath ) named as ( o.dstPath ). + * + * Accepts only ready options. + * Expects normalized absolute paths for source( o.srcPath ) and destination( o.dstPath ), routine makes nativization by itself. + * Source ( o.srcPath ) must be an existing terminal file. + * Destination ( o.dstPath ) must not exist in filesystem. + * Folders structure before destination( o.dstPath ) must exist in filesystem. + * If source( o.srcPath ) and destination( o.dstPath ) paths are equal, operiation is considered as successful. + * + * @method hardLinkAct + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +let hardLinkAct = Object.create( null ); +hardLinkAct.name = 'hardLinkAct'; + +var defaults = hardLinkAct.defaults = Object.create( null ); +defaults.dstPath = null; +defaults.srcPath = null; +defaults.relativeDstPath = null; +defaults.relativeSrcPath = null; +defaults.breakingSrcHardLink = 0; +defaults.breakingDstHardLink = 1; +defaults.sync = null; +defaults.context = null; + +var having = hardLinkAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; +// having.hardLinking = 1; + +var operates = hardLinkAct.operates = Object.create( null ); +operates.dstPath = { pathToWrite : 1 } +operates.srcPath = { pathToRead : 1 } +operates.relativeDstPath = { pathToWrite : 1 } +operates.relativeSrcPath = { pathToRead : 1 } + +// + +/** + * Creates hard link( new name ) to existing source( o.srcPath ) named as ( o.dstPath ). + * Rewrites target( o.dstPath ) by default if it exists. Logging of working process is controled by option( o.verbosity ). + * Returns true if link is successfully created. If some error occurs during execution method uses option( o.throwing ) to + * determine what to do - throw error or return false. + * + * + * @param { wTools~linkOptions } o - options { @link wTools~linkOptions } + * @property { boolean } [ o.breakingSrcHardLink=false ] - Breaks all hardlinks to source( o.srcPath ) file before creating a new hardlink. + * @property { boolean } [ o.breakingDstHardLink=true ] - Breaks all hardlinks to destination( o.dstPath ) file before creating a new hardlink. + * + * + * This is how routine links two existing hardlinks( = ) depending on combination of breakingSrcHardLink and breakingDstHardLink: + * f1 = src - dst = f2 + * breakingSrcHardLink:1 breakingDstHardLink:1 - breaks hardlinks: f1 = src and dst = f2 + * breakingSrcHardLink:1 breakingDstHardLink:0 - breaks hardlink f1 = src + * breakingSrcHardLink:0 breakingDstHardLink:1 - breaks hardlink dst = f2 + * breakingSrcHardLink:0 breakingDstHardLink:0 - preserves both hardlinks, is forbidden because its impossible to implement on FileProvider.HardDrive + * + * @method hardLink + * @throws { exception } If( o.srcPath ) doesn`t exist. + * @throws { exception } If cant link ( o.srcPath ) with ( o.dstPath ). + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function _hardLinkVerify1( c ) +{ + let self = this; + let o = c.options; + _.assert( _.boolLike( o.breakingSrcHardLink ) ); + _.assert( _.boolLike( o.breakingDstHardLink ) ); + _.assert + ( + !!c.options.breakingSrcHardLink || !!c.options.breakingDstHardLink, + 'Both source and destination hardlinks could not be preserved, please set breakingSrcHardLink or breakingDstHardLink to true' + ); + // _.assert( o.allowingMissed === 0 || _.longIs( o.dstPath ), 'o.allowingMissed could be disabled when linkingAction two files' ); + +} + +// + +function _hardLinkVerify2( c ) +{ + let self = this; + let o = c.options; + + if( c.srcStat === undefined ) + c.srcStat = self.statRead({ filePath : o.srcPath, sync : 1 }); + + let srcStat = c.srcStat; + + if( o.resolvingSrcSoftLink || o.resolvingSrcTextLink ) + if( self.fileExists( c.originalSrcResolvedPath ) ) + c.srcStat = self.statRead({ filePath : c.originalSrcResolvedPath, sync : 1, resolvingSoftLink : 0, resolvingTextLink : 0 }); + + if( c.srcStat && c.srcStat.isLink() ) + return; + + _.assert( o.allowingMissed === 0 || _.longIs( o.dstPath ), 'o.allowingMissed could be disabled when linkingAction two files' ); + + if( srcStat === null ) + { + c.error( _.err( 'Source file should exist.' ) ); + } + else if( !srcStat.isTerminal() ) + { + c.error( _.err( `Source file should be a terminal:\n ${o.srcPath}` ) ); + } + else + { + let linked = self.areHardLinked([ o.dstPath, o.srcPath ]); + if( linked || linked === _.maybe ) + c.end( false ); + } +} + +// + +function _hardLinkDo( c ) +{ + let self = this; + let o = c.options; + + _.assert( _.fileStatIs( c.srcStat ) || c.srcStat === null ); + + if( c.srcStat === null ) + return null; + + if( c.srcStat.isSoftLink() ) + { + if( o.resolvingSrcSoftLink === 2 ) + { + if( c.srcResolvedStat ) + return act(); + return tempRenameThen( () => null ); + } + + return tempRenameThen( () => + { + return self.softLinkAct + ({ + dstPath : o.dstPath, + srcPath : o.srcPath, + relativeDstPath : o.relativeDstPath, + relativeSrcPath : o.relativeSrcPath, + sync : o.sync, + type : null, + context : c, + }); + }) + } + else if( c.srcStat.isTextLink() ) + { + + if( o.resolvingSrcTextLink === 2 ) + { + if( c.srcResolvedStat ) + return act(); + return tempRenameThen( () => null ); + } + + return tempRenameThen( () => + { + /* qqq : cover, please */ + return self.textLinkAct + ({ + dstPath : o.dstPath, + srcPath : o.srcPath, + relativeDstPath : o.relativeDstPath, + relativeSrcPath : o.relativeSrcPath, + sync : o.sync, + context : c, + }); + }) + } + else + { + return act(); + } + + /* */ + + function act() + { + if( o.resolvingSrcSoftLink === 2 || o.resolvingSrcTextLink === 2 ) + { + if( c.srcResolvedStat.isDir() ) + { + return tempRenameThen( () => + { + return self.dirMakeAct + ({ + filePath : o.dstPath, + sync : o.sync + }) + }) + } + } + + // c.options2.context = c; /* aaa : move to linker. make it working for all 5 methods */ /* Dmytro : moved */ + + return self.hardLinkAct( c.options2 ); + } + + /* */ + + function tempRenameThen( callback ) + { + let con = _.Consequence.Try( () => c.tempRenameMaybe() ); + + con.then( () => + { + if( o.sync ) + { + callback(); + return true; + } + return callback(); + }); + + if( o.sync ) + return con.sync(); + + return con; + } + +} + +// function _hardLinkDo( c ) +// { +// let self = this; + +// if( c.options.breakingSrcHardLink ) +// if( !self.fileExists( c.options2.dstPath ) ) +// { +// if( c.srcStat.isHardLink() ) +// self.hardLinkBreak( c.options2.srcPath ); +// } +// else +// { +// if( !c.options.breakingDstHardLink ) +// if( c.dstStat.isHardLink() ) +// { +// let srcData = self.fileRead( c.options2.srcPath ); +// self.fileWrite( c.options2.dstPath, srcData ); +// self.fileDelete( c.options2.srcPath ); +// let dstPath = c.options2.dstPath; +// c.options2.dstPath = c.options2.srcPath; +// c.options2.srcPath = dstPath; +// } +// } + +// return self.hardLinkAct( c.options2 ); +// } + +_.routineExtend( _hardLinkDo, hardLinkAct ); + +/* qqq2 : cover returned value of hardLink if dstPath is array of files. should be number */ + +let hardLink = _.files.linker.functor +({ + actMethodName : 'hardLinkAct', + onDo : _hardLinkDo, + onVerify1 : _hardLinkVerify1, + onVerify2 : _hardLinkVerify2, + skippingSamePath : true, + skippingMissed : false, + hardLinking : true, + renaming : false, +}); + +var defaults = hardLink.body.defaults; + +defaults.rewriting = 1; +defaults.rewritingDirs = 0; +defaults.makingDirectory = 0; /* qqq2 : change default to makingDirectory : 1 */ +defaults.throwing = null; +defaults.verbosity = null; +defaults.allowingDiscrepancy = 1; +defaults.allowingMissed = 0; +defaults.allowingCycled = 0; +defaults.sourceMode = 'modified>hardlinks>'; + +defaults.breakingSrcHardLink = 0; +defaults.resolvingSrcSoftLink = 1; +defaults.resolvingSrcTextLink = 0; +defaults.breakingDstHardLink = 1; +defaults.resolvingDstSoftLink = 0; +defaults.resolvingDstTextLink = 0; + +_.props.extend( hardLink.defaults, hardLink.body.defaults ); + +/* xxx qqq2 : add test routine to check linkingAction methods fails if context is passed */ + +// + +let softLinkAct = Object.create( null ); +softLinkAct.name = 'softLinkAct'; + +var defaults = softLinkAct.defaults = Object.create( null ); +defaults.dstPath = null; +defaults.srcPath = null; +defaults.relativeDstPath = null; +defaults.relativeSrcPath = null; +defaults.sync = null; +defaults.type = null; +defaults.context = null; + +var having = softLinkAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = softLinkAct.operates = Object.create( null ); +operates.dstPath = { pathToWrite : 1 } +operates.srcPath = { pathToRead : 1 } +operates.relativeDstPath = { pathToWrite : 1 } +operates.relativeSrcPath = { pathToRead : 1 } + +// + +/** + * link methods options + * @typedef { object } wTools~linkOptions + * @property { boolean } [ dstPath= ] - Target file. + * @property { boolean } [ srcPath= ] - Source file. + * @property { boolean } [ o.sync=true ] - Runs method in synchronous mode. Otherwise asynchronously and returns wConsequence object. + * @property { boolean } [ rewriting=true ] - Rewrites target( o.dstPath ). + * @property { boolean } [ verbosity=true ] - Logs working process. + * @property { boolean } [ throwing=true ] - Enables error throwing. Otherwise returns true/false. + * @property { boolean } [ o.breakingSrcHardLink= ] - Breaks all hardlinks to source( o.srcPath ) file before link operation. + * @property { boolean } [ o.breakingDstHardLink= ] - Breaks all hardlinks to destination( o.dstPath ) file before link operation. + */ + +/** + * Creates soft link( symbolic ) to existing source( o.srcPath ) named as ( o.dstPath ). + * Rewrites target( o.dstPath ) by default if it exist. Logging of working process is controled by option( o.verbosity ). + * Returns true if link is successfully created. If some error occurs during execution method uses option( o.throwing ) to + * determine what to do - throw error or return false. + * + * @param { wTools~linkOptions } o - options { @link wTools~linkOptions } + * + * @method softLink + * @throws { exception } If( o.srcPath ) doesn`t exist. + * @throws { exception } If cant link ( o.srcPath ) with ( o.dstPath ). + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function _softLinkDo( c ) +{ + let self = this; + return self.softLinkAct( c.options2 ); +} + +_.routineExtend( _softLinkDo, softLinkAct ); + +function _softLinkVerify2( c ) +{ + let self = this; + let o = c.options; + + if( !o.allowingMissed ) + // if( self.areSoftLinked([ o.dstPath, o.srcPath ]) ) + if( o.dstPath === o.srcPath ) + c.error( _.err( 'Soft link cycle', path.moveTextualReport( o.dstPath, o.srcPath ) ) ); + + // if( o.dstPath !== o.srcPath && self.areSoftLinked([ o.dstPath, o.srcPath ]) ) + // if( o.dstPath === o.srcPath ) + // return true; + + // if( o.dstPath !== o.srcPath && self.areSoftLinked([ o.dstPath, o.srcPath ]) ) + // return true; + +} + +let softLink = _.files.linker.functor +({ + actMethodName : 'softLinkAct', + onDo : _softLinkDo, + onVerify2 : _softLinkVerify2, + skippingSamePath : false, + skippingMissed : false, + linkMaybe : true, +}); + +var defaults = softLink.body.defaults; + +defaults.rewriting = 1; +defaults.rewritingDirs = 0; +defaults.makingDirectory = 0; /* qqq2 : change default to makingDirectory : 1 */ +defaults.throwing = null; +defaults.verbosity = null; +defaults.allowingMissed = 0; +defaults.allowingCycled = 0; + +defaults.resolvingSrcSoftLink = 0; +defaults.resolvingSrcTextLink = 0; +defaults.resolvingDstSoftLink = 0; +defaults.resolvingDstTextLink = 0; + +_.props.extend( softLink.defaults, softLink.body.defaults ); + +// + +function textLinkAct( o ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + + _.routine.assertOptions( textLinkAct, arguments ); + _.assert( path.is( o.srcPath ) ); + _.assert( path.isAbsolute( o.dstPath ) ); + + let srcPath = o.relativeSrcPath; + + let result = self.fileWrite + ({ + filePath : o.dstPath, + data : 'link ' + srcPath, + sync : o.sync, + makingDirectory : 0 + }); + + if( o.sync ) + return true; + else + return result; +} + +var defaults = textLinkAct.defaults = Object.create( null ); +defaults.dstPath = null; +defaults.srcPath = null; +defaults.sync = null; +defaults.relativeDstPath = null; +defaults.relativeSrcPath = null; +defaults.context = null; + +var having = textLinkAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = textLinkAct.operates = Object.create( null ); +operates.dstPath = { pathToWrite : 1 } +operates.srcPath = { pathToRead : 1 } +operates.relativeDstPath = { pathToWrite : 1 } +operates.relativeSrcPath = { pathToRead : 1 } + +// + +/** + * Creates text link to existing source( o.srcPath ) named as ( o.dstPath ). + * Rewrites target( o.dstPath ) by default if it exist. Logging of working process is controled by option( o.verbosity ). + * Returns true if link is successfully created. If some error occurs during execution method uses option( o.throwing ) to + * determine what to do - throw error or return false. + * + * @param { wTools~linkOptions } o - options { @link wTools~linkOptions } + * + * @method textLink + * @throws { exception } If( o.srcPath ) doesn`t exist. + * @throws { exception } If cant link ( o.srcPath ) with ( o.dstPath ). + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function _textLinkDo( c ) +{ + let self = this; + return self.textLinkAct( c.options2 ); +} + +_.routineExtend( _textLinkDo, textLinkAct ); + +function _textLinkVerify2( c ) +{ + let self = this; + let o = c.options; + if( o.dstPath !== o.srcPath && self.areTextLinked([ o.dstPath, o.srcPath ]) ) + c.end( false ); +} + +function _textIsLink( stat ) +{ + let self = this; + let r = false; + self.fieldPush( 'usingTextLink', 1 ); + r = stat.isTextLink(); + self.fieldPop( 'usingTextLink', 1 ); + return r; +} + +function _textOnStat( filePath, resolving ) +{ + let self = this; + self.fieldPush( 'usingTextLink', 1 ); + let result = self.statRead + ({ + filePath, + throwing : 0, + resolvingSoftLink : resolving, + resolvingTextLink : resolving, + sync : 1, + }); + self.fieldPop( 'usingTextLink', 1 ); + return result; +} + +let textLink = _.files.linker.functor +({ + actMethodName : 'textLinkAct', + onDo : _textLinkDo, + onVerify2 : _textLinkVerify2, + onIsLink : _textIsLink, + onStat : _textOnStat, + skippingSamePath : false, + skippingMissed : false, + linkMaybe : true, +}); + +var defaults = textLink.body.defaults; + +defaults.rewriting = 1; +defaults.rewritingDirs = 0; +defaults.makingDirectory = 0; /* qqq2 : change default to makingDirectory : 1 */ +defaults.throwing = null; +defaults.verbosity = null; +defaults.allowingMissed = 0; +defaults.allowingCycled = 0; + +defaults.resolvingSrcSoftLink = 0; +defaults.resolvingSrcTextLink = 0; +defaults.resolvingDstSoftLink = 0; +defaults.resolvingDstTextLink = 0; + +_.props.extend( textLink.defaults, textLink.body.defaults ); + +// + +function fileExchange_head( routine, args ) +{ + let self = this; + let o; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( args.length === 2 ) + { + o = + { + dstPath : args[ 0 ], + srcPath : args[ 1 ], + } + _.assert( args.length === 2 ); + } + else + { + o = args[ 0 ]; + _.assert( args.length === 1 ); + } + + _.routine.options_( routine, o ); + self._providerDefaultsApply( o ); + _.assert( _.strIs( o.srcPath ) && _.strIs( o.dstPath ) ); + + return o; +} + +// + +function fileExchange_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + // throw _.err( 'not tested after introducing of allowingCycled' ); + // let src = self.statResolvedRead({ filePath : o.srcPath, throwing : 0 }); + // let dst = self.statResolvedRead({ filePath : o.dstPath, throwing : 0 });] + + let src, dst; + + try + { + src = _statResolvedRead( o.srcPath ); + dst = _statResolvedRead( o.dstPath ); + } + catch( err ) + { + return handleError( err ); + } + + let optionsForRename = + { + resolvingSrcTextLink : 0, + resolvingDstTextLink : 0, + resolvingSrcSoftLink : 0, + resolvingDstSoftLink : 0, + allowingMissed : 0 + } + + if( !src.stat || !dst.stat ) + { + if( o.allowingMissed ) + { + if( !src.stat && dst.stat ) + { + o.srcPath = dst.filePath; + o.dstPath = src.filePath; + } + if( !src.stat && !dst.stat ) + return returnNull(); + + return self.fileRename( _.props.extend( null, o, optionsForRename ) ); + } + else if( o.throwing ) + { + let err; + + if( !src.stat && !dst.stat ) + { + err = _.err( 'srcPath and dstPath not exist! srcPath: ', o.srcPath, ' dstPath: ', o.dstPath ) + } + else if( !src.stat ) + { + err = _.err( 'srcPath not exist! srcPath: ', o.srcPath ); + } + else if( !dst.stat ) + { + err = _.err( 'dstPath not exist! dstPath: ', o.dstPath ); + } + + return handleError( err ); + } + else + return returnNull(); + } + + let tempPath = src.filePath + '-' + _.idWithGuid() + '.tmp'; + + var o2 = _.props.extend( null, o, optionsForRename ); + + o2.srcPath = src.filePath; + o2.dstPath = tempPath; + // o2.originalSrcPath = null; + // o2.originalDstPath = null; + + if( o.sync ) + { + self.fileRename( _.props.extend( null, o2 ) ); + o2.dstPath = src.filePath; + o2.srcPath = dst.filePath; + self.fileRename( _.props.extend( null, o2 ) ); + o2.dstPath = dst.filePath; + o2.srcPath = tempPath; + return self.fileRename( _.props.extend( null, o2 ) ); + } + else + { + let con = self.fileRename( _.props.extend( null, o2 ) ); + + con.then( () => + { + o2.dstPath = src.filePath; + o2.srcPath = dst.filePath; + return self.fileRename( _.props.extend( null, o2 ) ); + }); + + con.then( () => + { + o2.dstPath = dst.filePath; + o2.srcPath = tempPath; + return self.fileRename( _.props.extend( null, o2 ) ); + }); + + con.catch( ( err ) => + { + if( !o.throwing ) + return null; + throw err; + }); + + return con; + } + + /* - */ + + function _statResolvedRead( filePath ) + { + let o2 = + { + filePath, + resolvingTextLink : self.resolvingTextLink, + resolvingSoftLink : self.resolvingSoftLink, + sync : 1, + throwing : o.throwing, + allowingMissed : o.allowingMissed, + allowingCycled : o.allowingCycled, + } + filePath = self.pathResolveLinkFull( o2 ).absolutePath; + return { filePath, stat : o2.stat }; + } + + /* - */ + + function returnNull() + { + if( o.sync ) + return null; + else + return new _.Consequence().take( null ); + } + + /* - */ + + function handleError( err ) + { + if( !o.throwing ) + return returnNull(); + + if( o.sync ) + throw _.err( err ); + return new _.Consequence().error( err ); + } + +} + +var defaults = fileExchange_body.defaults = Object.create( null ); +defaults.srcPath = null; +defaults.dstPath = null; +defaults.sync = null; +defaults.allowingMissed = 1; +defaults.allowingCycled = 1; +defaults.throwing = null; +defaults.verbosity = null; + +var having = fileExchange_body.having = Object.create( null ); +having.writing = 1; +having.reading = 1; +having.driving = 0; +having.aspect = 'body'; + +// + +/** + * Swaps content of the two files. + * Takes single argument - object with options or two arguments : destination( o.dstPath ) and source( o.srcPath ) paths. + * @param {Object} o Object with options. + * @param {String|FileRecord} [ o.dstPath=null ] - Destination path or instance of FileRecord @see{@link wFileRecord}. Path must be absolute. + * @param {String|FileRecord} [ o.srcPath=null ] - Source path or instance of FileRecord @see{@link wFileRecord}. Path can be relative to destination path or absolute. + * In case of FileRecord instance, absolute path will be used. + * @param {Boolean} [ o.sync=true ] - Determines execution mode: true - synchronously, false - asynchronously. + * In asynchronous mode returns wConsequence @see{@link wConsequence }. + * @param {Boolean} [ o.throwing=true ] - Controls error throwing. Returns false if error occurred and ( o.throwing ) is disabled. + * @param {Boolean} [ o.allowingMissed=true ] - Allows missing of the file( s ). If source ( o.srcPath ) is missing - ( o.srcPath ) becomes destination and ( o.dstPath ) becomes the source. Routine returns null if both paths are missing. + * @returns {Boolean|wConsequence} Returns true after successful exchange, otherwise false is returned. Also returns false if an error occurs and ( o.throwing ) is disabled. + * In async mode returns Consequence instance @see{@link wConsequence } with same result. + * + * @example + * wTools.fileProvider.fileExchange( '/existingDir/existingDst', '/existingDir/existingSrc' ); + * //returns true + * + * @example + * let consequence = wTools.fileProvider.fileExchange + * ({ + * dstPath : '/existingDir/existingDst', + * srcPath : '/existingDir/existingSrc', + * sync : 0 + * }); + * consequence.give( ( err, got ) => + * { + * if( err ) + * throw err; + * + * console.log( got ); // true + * }) + * + * @method fileExchange + * @throws { Exception } If no arguments provided. + * @throws { Exception } If ( o.srcPath ) is not a String or instance of wFileRecord. + * @throws { Exception } If ( o.dstPath ) is not a String or instance of wFileRecord. + * @throws { Exception } If ( o.srcPath ) path to a file doesn't exist. + * @throws { Exception } If destination( o.dstPath ) and source( o.srcPath ) files exist and ( o.rewriting ) is disabled. + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +let fileExchange = _.routine.uniteCloning_replaceByUnite( fileExchange_head, fileExchange_body ); +fileExchange.having.aspect = 'entry'; + +// -- +// link +// -- + +let hardLinkBreakAct = Object.create( null ); +hardLinkBreakAct.name = 'hardLinkBreakAct'; + +var defaults = hardLinkBreakAct.defaults = Object.create( null ); +defaults.filePath = null; +defaults.sync = null; + +var having = hardLinkBreakAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = hardLinkBreakAct.operates = Object.create( null ); +operates.filePath = { pathToRead : 1, pathToWrite : 1 } + +// + +function hardLinkBreak_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.routineIs( self.hardLinkBreakAct ) ) + return self.hardLinkBreakAct( o ); + else + { + let options = + { + filePath : o.filePath, + purging : 1 + }; + + if( o.sync ) + return self.fileTouch( options ); + else + return _.time.out( 0, () => self.fileTouch( options ) ); + } +} + +_.routineExtend( hardLinkBreak_body, hardLinkBreakAct ); + +var having = hardLinkBreak_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let hardLinkBreak = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, hardLinkBreak_body ); +hardLinkBreak.having.aspect = 'entry'; + +// + +let softLinkBreakAct = Object.create( null ); +softLinkBreakAct.name = 'softLinkBreakAct'; + +var defaults = softLinkBreakAct.defaults = Object.create( null ); +defaults.filePath = null; +defaults.sync = null; + +var having = softLinkBreakAct.having = Object.create( null ); +having.writing = 1; +having.reading = 0; +having.driving = 1; + +var operates = softLinkBreakAct.operates = Object.create( null ); +operates.filePath = { pathToRead : 1, pathToWrite : 1 } + +// + +function softLinkBreak_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.routineIs( self.softLinkBreakAct ) ) + return self.softLinkBreakAct( o ); + else + { + let options = + { + filePath : o.filePath, + purging : 1 + }; + + if( o.sync ) + return self.fileTouch( options ); + else + return _.time.out( 0, () => self.fileTouch( options ) ); + } +} + +_.routineExtend( softLinkBreak_body, softLinkBreakAct ); + +var having = softLinkBreak_body.having; +having.driving = 0; +having.aspect = 'body'; + +// + +let softLinkBreak = _.routine.uniteCloning_replaceByUnite( _preFilePathScalarWithProviderDefaults, softLinkBreak_body ); +softLinkBreak.having.aspect = 'entry'; + +// + +let areHardLinkedAct = Object.create( null ); +areHardLinkedAct.name = 'areHardLinkedAct'; + +var defaults = areHardLinkedAct.defaults = Object.create( null ); +defaults.filePath = null; + +var having = areHardLinkedAct.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 1; + +var operates = areHardLinkedAct.operates = Object.create( null ); +operates.filePath = { pathToRead : 1, vector : [ 2, 2 ] } + +// + +/** + * Check if one of paths is hard link to other. + * @example + let fs = require( 'fs' ); + + let path1 = '/home/tmp/sample/file1', + path2 = '/home/tmp/sample/file2', + buffer = BufferNode.from( [ 0x01, 0x02, 0x03, 0x04 ] ); + + wTools.fileWrite( { filePath : path1, data : buffer } ); + fs.symlinkSync( path1, path2 ); + + let linked = wTools.areHardLinked( path1, path2 ); // true + + * @param {string|wFileRecord} ins1 path string/file record instance + * @param {string|wFileRecord} ins2 path string/file record instance + + * @returns {boolean} + * @throws {Error} if missed one of arguments or pass more then 2 arguments. + * @method areHardLinked + * @class wFileProviderPartial + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function filesAreLinked_head( routine, args ) +{ + let self = this; + let o; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( args.length === 2 ) + { + o = { filePath : [ args[ 0 ], args[ 1 ] ] } + } + else if( _.argumentsArray.like( args[ 0 ] ) ) + { + _.assert( args.length === 1 ); + o = { filePath : args[ 0 ] } + } + else + { + _.assert( args.length === 1 ); + o = args[ 0 ]; + } + + _.assert( _.mapIs( o ) ); + + // o = self._preFilePathVectorWithProviderDefaults.call( self, routine, [ o ] ); + + o = self._preFilePathVectorWithoutProviderDefaults.call( self, routine, [ o ] ); + self._providerDefaultsApply( o ); + + return o; +} + +// + +function areHardLinked_body( o ) /* qqq : refactor. probably move some code to areHardLinkedAct */ +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( areHardLinked_body, arguments ); + + if( !o.filePath.length ) + return true; + + let result; + + for( let i = 1 ; i < o.filePath.length ; i++ ) + { + result = self.areHardLinkedAct({ filePath : [ o.filePath[ 0 ], o.filePath[ i ] ] }); + _.assert( _.boolIs( result ) || result === _.maybe ); + if( !result ) + break; + } + + return result; +} + +_.routineExtend( areHardLinked_body, areHardLinkedAct ); + +var having = areHardLinked_body.having; +having.aspect = 'body'; + +// + +let areHardLinked = _.routine.uniteCloning_replaceByUnite( filesAreLinked_head, areHardLinked_body ); + +var having = areHardLinked.having; +having.driving = 0; +having.aspect = 'entry'; + +// + +function areSoftLinked_body( o ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( areSoftLinked_body, arguments ); + _.assert( o.filePath.length >= 2 ); + + o.filePath = path.s.normalize( o.filePath ); + + _.assert( path.s.allAreAbsolute( o.filePath ) ); + + if( o.filePath[ 0 ] === o.filePath[ 1 ] ) + return false; + + let resolved = []; + + // xxx + // if( o.filePath[ 1 ] === 'extract+dst:///dst/a1' ) + // debugger; + + for( let i = 0 ; i < o.filePath.length ; i++ ) + { + resolved[ i ] = self.pathResolveLinkFull + ({ + filePath : o.filePath[ i ], + resolvingTextLink : o.resolvingTextLink, + resolvingSoftLink : true, + }).absolutePath; + _.assert( path.is( resolved[ 0 ] ) ); + } + + for( let i = 1 ; i < resolved.length ; i++ ) + { + if( resolved[ 0 ] !== resolved[ i ] ) + return false; + } + + return true; +} + +var defaults = areSoftLinked_body.defaults = Object.create( null ); +defaults.filePath = null; +defaults.resolvingTextLink = 0; + +var operates = areSoftLinked_body.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 } + +var having = areSoftLinked_body.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 0; +having.aspect = 'body'; + +// + +let areSoftLinked = _.routine.uniteCloning_replaceByUnite( filesAreLinked_head, areSoftLinked_body ); + +areSoftLinked.having.driving = 0; +areSoftLinked.having.aspect = 'entry'; + +// + +function areTextLinked_body( o ) +{ + let self = this; + let path = self.system ? self.system.path : self.path;; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( areTextLinked_body, arguments ); + _.assert( o.filePath.length >= 2 ); + + o.filePath = path.s.normalize( o.filePath ); + + _.assert( path.s.allAreAbsolute( o.filePath ) ); + + if( o.filePath[ 0 ] === o.filePath[ 1 ] ) + return false; + + let resolved = []; + + for( let i = 0 ; i < o.filePath.length ; i++ ) + { + resolved[ i ] = self.pathResolveLinkFull + ({ + filePath : o.filePath[ i ], + resolvingSoftLink : o.resolvingSoftLink, + resolvingTextLink : true, + }).absolutePath; + _.assert( path.is( resolved[ i ] ) ); + } + + for( let i = 1 ; i < resolved.length ; i++ ) + { + if( resolved[ 0 ] !== resolved[ i ] ) + return false; + } + + return true; +} + +var defaults = areTextLinked_body.defaults = Object.create( null ); +defaults.filePath = null; +defaults.resolvingSoftLink = 0; + +var operates = areTextLinked_body.operates = Object.create( null ); +operates.filePath = { pathToRead : 1 } + +var having = areTextLinked_body.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 0; +having.aspect = 'body'; + +// + +let areTextLinked = _.routine.uniteCloning_replaceByUnite( filesAreLinked_head, areTextLinked_body ); + +areTextLinked.having.driving = 0; +areTextLinked.having.aspect = 'entry'; + +// -- +// accessor +// -- + +function _preferredProviderGet( src ) +{ + let self = this; + _.assert( arguments.length === 0 ); + return self; +} + +// + +function _protocolsSet( protocols ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( protocols === null ) + { + self[ protocolsSymbol ] = []; + self[ protocolSymbol ] = null; + return protocols; + } + + if( _.strIs( protocols ) ) + return self._protocolsSet([ protocols ]); + + _.assert( _.arrayIs( protocols ) ) + _.assert( protocols.every( ( p ) => !_.strHas( p, ':' ) && !_.strHas( p, '/' ) ) ); + + protocols = protocols.map( ( p ) => p.toLowerCase() ); + + let protocol = protocols[ 0 ] || null; + + _.assert( _.strIs( protocol ) || protocol === null ); + + self[ protocolsSymbol ] = protocols; + self[ protocolSymbol ] = protocol; + + if( protocol ) + self[ originPathSymbol ] = self.originsForProtocols( protocol ); + else + self[ originPathSymbol ] = null; + +} + +var having = _protocolsSet.having = Object.create( null ); +having.writing = 0; +having.reading = 0; +having.driving = 0; +having.kind = 'inter'; + +// + +function _protocolSet( protocol ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( protocol === null || _.strIs( protocol ) ); + + self._protocolsSet( protocol ); +} + +var having = _protocolSet.having = Object.create( null ); +having.writing = 0; +having.reading = 0; +having.driving = 0; +having.kind = 'inter'; + +// + +function _originPathSet( origins ) +{ + let self = this; + self.protocols = self.protocolsForOrigins( origins ); +} + +var having = _originPathSet.having = Object.create( null ); +having.writing = 0; +having.reading = 0; +having.driving = 0; +having.kind = 'inter'; + +// -- +// vars +// -- + +let verbositySymbol = Symbol.for( 'verbosity' ); +let protocolsSymbol = Symbol.for( 'protocols' ); +let protocolSymbol = Symbol.for( 'protocol' ); +let originPathSymbol = Symbol.for( 'originPath' ); + +let WriteMode = [ 'rewrite', 'prepend', 'append' ]; /* xxx : map or set */ + +let ProviderDefaults = +{ + 'encoding' : null, + 'resolvingSoftLink' : null, + 'resolvingTextLink' : null, + 'usingSoftLink' : null, + 'usingTextLink' : null, + 'verbosity' : null, + 'sync' : null, + 'throwing' : null, + 'safe' : null, + 'system' : null, +} + +/** + * @typedef {Object} Fields + * @property {String[]} protocols=[] + * @property {String} encoding='utf8' + * @property {Number} hashFileSizeLimit=8MB + * @property {Boolean} resolvingSoftLink=1 + * @property {Boolean} resolvingTextLink=0 + * @property {Boolean} usingSoftLink=1 + * @property {Boolean} usingTextLink=0 + * @property {Number} verbosity=0 + * @property {Boolean} sync=1 + * @property {Boolean} throwing=1 + * @property {Boolean} safe=1 + * @property {Boolean} stating=1 + * @property {Boolean} usingGlobalPath=0 + * @property {Object} path + * @property {Object} logger + * @property {Object} system + * @property {String} protocol + * @property {String} originPath + * @class wFileProviderPartial + * @namespace wTools + * @module Tools/mid/Files + */ + +// -- +// relations +// -- + +let Composes = +{ + + protocols : _.define.own([]), + + encoding : 'utf8', + hashFileSizeLimit : 1 << 23, + + resolvingSoftLink : 1, + resolvingTextLink : 0, + usingSoftLink : 1, + usingTextLink : 0, + + verbosity : 0, + sync : 1, + throwing : 1, + safe : 1, + stating : 1, + usingGlobalPath : 0, + globing : 1, + +} + +let Aggregates = +{ +} + +let Associates = +{ + path : null, + logger : null, + system : null, +} + +let Restricts = +{ + id : 0, +} + +let Medials = +{ + protocol : null, + originPath : null, +} + +let Statics = +{ + + MakeDefault, + Path : _.path.CloneExtending({ fileProvider : Self }), + WriteMode, + ProviderDefaults, + Counter : 0, + + SupportsIno : 0, + SupportsRights : 0, + SupportsLinks : 1, + +} + +let Forbids = +{ + + done : 'done', + currentAct : 'currentAct', + current : 'current', + resolvingHardLink : 'resolvingHardLink', + + pathNativize : 'pathNativize', + pathsNativize : 'pathsNativize', + pathCurrent : 'pathCurrent', + pathResolve : 'pathResolve', + pathsResolve : 'pathsResolve', + + softLinkRead : 'softLinkRead', + softLinkReadAct : 'softLinkReadAct', + linkSoftAct : 'linkSoftAct', + linkSoft : 'linkSoft', + linkHardAct : 'linkHardAct', + linkHard : 'linkHard', + pathResolveHardLinkAct : 'pathResolveHardLinkAct', + pathResolveHardLink : 'pathResolveHardLink', + + isTerminalAct : 'isTerminalAct', + isDirAct : 'isDirAct', + isTextLinkAct : 'isTextLinkAct', + isSoftLinkAct : 'isSoftLinkAct', + isHardLinkAct : 'isHardLinkAct', + _recordPathForm : '_recordPathForm', + hub : 'hub', + +} + +let Accessors = +{ + protocols : 'protocols', + protocol : 'protocol', + originPath : 'originPath', + preferredProvider : { get : _preferredProviderGet, set : false }, +} + +// -- +// declare +// -- + +let Extension = +{ + + init, + finit, + MakeDefault, + + // helper + + _fileOptionsGet, + _providerDefaultsApply, + assertProviderDefaults, + + _preFilePathScalarWithoutProviderDefaults, + _preFilePathScalarWithProviderDefaults, + _preFilePathVectorWithoutProviderDefaults, + _preFilePathVectorWithProviderDefaults, + + _preFileFilterWithoutProviderDefaults, + _preFileFilterWithProviderDefaults, + _preSrcDstPathWithoutProviderDefaults, + _preSrcDstPathWithProviderDefaults, + + // system + + protocolsForOrigins, + originsForProtocols, + providerForPath, + providerRegisterTo, + providerUnregister, + hasProvider, + + // path + + preferredFromGlobalAct, + globalFromPreferredAct, + + pathNativizeAct, + pathCurrentAct : null, + pathDirTempAct, /* xxx qqq : remove default implementation */ + pathAllowedAct, + + // resolve + + pathResolveSoftLinkAct, + pathResolveSoftLink, + + pathResolveTextLinkAct, + pathResolveTextLink, + + pathResolveLinkStep, + pathResolveLinkFull, + pathResolveLinkTail, + pathResolveLinkTailChain, + pathResolveLinkHeadDirect, + pathResolveLinkHeadReverse, + + // record + + _recordFactoryFormEnd, + _recordFormBegin, + _recordFormEnd, + + _recordAbsoluteGlobalMaybeGet, + _recordRealGlobalMaybeGet, + + record, + _recordsSort, + recordFactory, + recordFilter, + + // stat + + statReadAct, + statRead, + statsRead : vectorize( statRead ), + statResolvedRead, + statsResolvedRead : vectorize( statResolvedRead ), + + filesSize, /* xxx : move */ + fileSize, + + isInoAct, + isIno, + + fileExistsAct, + fileExists, + filesExists : vectorize( fileExists ), + filesExistsAll : vectorizeAll( fileExists ), + filesExistsAny : vectorizeAny( fileExists ), + filesExistsNone : vectorizeNone( fileExists ), + + isTerminal, + areTerminals : vectorize( isTerminal ), + allAreTerminals : vectorizeAll( isTerminal ), + anyAreTerminals : vectorizeAny( isTerminal ), + noneAreTerminals : vectorizeNone( isTerminal ), + resolvedIsTerminal, + resolvedAreTerminals : vectorize( resolvedIsTerminal ), + resolvedAllAreTerminals : vectorizeAll( resolvedIsTerminal ), + resolvedAnyAreTerminals : vectorizeAny( resolvedIsTerminal ), + resolvedNoneAreTerminals : vectorizeNone( resolvedIsTerminal ), + + isDir, + areDirs : vectorize( isDir ), + allAreDirs : vectorizeAll( isDir ), + anyAreDirs : vectorizeAny( isDir ), + noneAreDirs : vectorizeNone( isDir ), + resolvedIsDir, + resolvedAreDirs : vectorize( resolvedIsDir ), + resolvedAllAreDirs : vectorizeAll( resolvedIsDir ), + resolvedAnyAreDirs : vectorizeAny( resolvedIsDir ), + resolvedNoneAreDirs : vectorizeNone( resolvedIsDir ), + + isHardLink, + areHardLinks : vectorize( isHardLink ), + allAreHardLinks : vectorizeAll( isHardLink ), + anyAreHardLinks : vectorizeAny( isHardLink ), + noneAreHardLinks : vectorizeNone( isHardLink ), + resolvedIsHardLink, + resolvedAreHardLinks : vectorize( resolvedIsHardLink ), + resolvedAllAreHardLinks : vectorizeAll( resolvedIsHardLink ), + resolvedAnyAreHardLinks : vectorizeAny( resolvedIsHardLink ), + resolvedNoneAreHardLinks : vectorizeNone( resolvedIsHardLink ), + + isSoftLink, + areSoftLinks : vectorize( isSoftLink ), + allAreSoftLinks : vectorizeAll( isSoftLink ), + anyAreSoftLinks : vectorizeAny( isSoftLink ), + noneAreSoftLinks : vectorizeNone( isSoftLink ), + resolvedIsSoftLink, + resolvedAreSoftLinks : vectorize( resolvedIsSoftLink ), + resolvedAllAreSoftLinks : vectorizeAll( resolvedIsSoftLink ), + resolvedAnyAreSoftLinks : vectorizeAny( resolvedIsSoftLink ), + resolvedNoneAreSoftLinks : vectorizeNone( resolvedIsSoftLink ), + + isTextLink, + areTextLinks : vectorize( isTextLink ), + allAreTextLinks : vectorizeAll( isTextLink ), + anyAreTextLinks : vectorizeAny( isTextLink ), + noneAreTextLinks : vectorizeNone( isTextLink ), + resolvedIsTextLink, + resolvedAreTextLinks : vectorize( resolvedIsTextLink ), + resolvedAllAreTextLinks : vectorizeAll( resolvedIsTextLink ), + resolvedAnyAreTextLinks : vectorizeAny( resolvedIsTextLink ), + resolvedNoneAreTextLinks : vectorizeNone( resolvedIsTextLink ), + + isLink, + areLinks : vectorize( isLink ), + allAreLinks : vectorizeAll( isLink ), + anyAreLinks : vectorizeAny( isLink ), + noneAreLinks : vectorizeNone( isLink ), + resolvedIsLink, + filesResolvedAreLinks : vectorize( resolvedIsLink ), + filesResolvedAllAreLinks : vectorizeAll( resolvedIsLink ), + filesResolvedAnyAreLinks : vectorizeAny( resolvedIsLink ), + filesResolvedNoneAreLinks : vectorizeNone( resolvedIsLink ), + + dirIsEmpty, + dirsAreEmpty : vectorize( dirIsEmpty ), + dirsAllAreEmpty : vectorizeAll( dirIsEmpty ), + dirsAnyAreEmpty : vectorizeAny( dirIsEmpty ), + dirsNoneAreEmpty : vectorizeNone( dirIsEmpty ), + resolvedDirIsEmpty, + resolvedDirsAreEmpty : vectorize( resolvedDirIsEmpty ), + resolvedDirsAllAreEmpty : vectorizeAll( resolvedDirIsEmpty ), + resolvedDirsAnyAreEmpty : vectorizeAny( resolvedDirIsEmpty ), + resolvedDirsNoneAreEmpty : vectorizeNone( resolvedDirIsEmpty ), + + // read + + streamReadAct, + streamRead, + + fileReadAct, + fileRead, + fileReadUnknown, + fileReadSync, + fileReadJson, /* xxx : qqq : redo with head and body of fileRead */ + fileReadJs, /* xxx : qqq : redo with head and body of fileRead */ + fileInterpret, /* xxx : remove */ + + hashReadAct, + hashRead, + hashSzRead, /* qqq : cover */ + hashSzIsUpToDate, /* qqq : cover */ + + dirReadAct, + dirRead, + dirReadDirs, + dirReadTerminals, + + /* qqq : implement and cover timeRead and timeReadAct */ + + rightsReadAct, + rightsRead, + + filesFingerprints, + filesCanBeSame, + filesAreSameForSure, + + // write + + streamWriteAct, + streamWrite, + + fileWriteAct, + fileWrite, + fileAppend, + fileWriteUnknown, + fileWriteJson, /* xxx : qqq : redo with head and body of fileWrite */ + fileWriteJs, /* xxx : qqq : redo with head and body of fileWrite */ + fileTouch, + + timeWriteAct, + timeWrite, + + rightsWriteAct, + rightsWrite, + rightsAdd, + rightsDel, + + fileDeleteAct, + fileDelete, + fileResolvedDelete, + + dirMakeAct, + dirMake, + dirMakeForFile, + + // locking + + fileLockAct, + fileLock, + + fileUnlockAct, + fileUnlock, + + fileIsLockedAct, + fileIsLocked, + + // linkingAction + + fileRenameAct, + fileRename, + + fileCopyAct, + fileCopy, + + hardLinkAct, + hardLink, + + softLinkAct, + softLink, + + textLinkAct, + textLink, + + fileExchange, + + // link + + hardLinkBreakAct, + hardLinkBreak, + softLinkBreakAct, + softLinkBreak, + + areHardLinkedAct, + areHardLinked, + areSoftLinked, + areTextLinked, + + // accessor + + _preferredProviderGet, + _protocolsSet, + _protocolSet, + _originPathSet, + + // relations + + Composes, + Aggregates, + Associates, + Restricts, + Medials, + Statics, + Forbids, + Accessors, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Extension, +}); + +_.Copyable.mixin( Self ); +_.FieldsStack.mixin( Self ); +_.Verbal.mixin( Self ); + +_.assert( _.routineIs( Self.prototype.statsResolvedRead ) ); +_.assert( _.object.isBasic( Self.prototype.statsResolvedRead.defaults ) ); +_.assert( Self.prototype.statRead.defaults.resolvingSoftLink === 0 ); +_.assert( Self.prototype.statRead.defaults.resolvingTextLink === 0 ); + +// -- +// export +// -- + +_.FileProvider[ Self.shortName ] = Self; +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l5/Partial.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Partial_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Partial_s */ })(); + +/* */ /* begin of file FindMixin_s */ ( function FindMixin_s() { function FindMixin_s_naked() { ( function _FindMixin_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const FileRecord = _.files.FileRecord; +const Abstract = _.FileProvider.Abstract; +const Partial = _.FileProvider.Partial; +const fileRead = Partial.prototype.fileRead; + +_.assert( _.entity.lengthOf( _.files.ReadEncoders ) > 0 ); +_.assert( _.routineIs( _.files.FileRecord ) ); +_.assert( _.routineIs( Abstract ) ); +_.assert( _.routineIs( Partial ) ); +_.assert( _.routineIs( fileRead ) ); + +// + +/** + @class wFileProviderFindMixin + @class FileProvider + @namespace wTools + @module Tools/mid/Files +*/ + +const Parent = null; +const Self = wFileProviderFindMixin; +function wFileProviderFindMixin( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'FindMixin'; + +// -- +// etc +// -- + +function recordsOrder( records, orderingExclusion ) +{ + + _.assert( _.arrayIs( records ) ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + if( !orderingExclusion.length ) + return records; + + orderingExclusion = _.RegexpObject.Order( orderingExclusion || [] ); + + let removed = []; + let result = []; + let e = 0; + for( ; e < orderingExclusion.length ; e++ ) + result[ e ] = []; + + for( let r = 0 ; r < records.length ; r++ ) + { + let record = records[ r ]; + for( let e = 0 ; e < orderingExclusion.length ; e++ ) + { + let mask = orderingExclusion[ e ]; + let match = mask.test( record.relative ); + if( match ) + { + result[ e ].push( record ); + break; + } + } + if( e === orderingExclusion.length ) + removed.push( record ); + } + + return _.arrayAppendArrays( [], result ); +} + +// -- +// files find +// -- + +function _filesFindPrepare0( routine, args ) /* qqq : cover each case */ +{ + let o; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2, 'Expects one or two arguments' ); + + if( args[ 0 ] && args[ 0 ] instanceof _.files.FileRecordFilter ) + { + o = o || Object.create( null ); + o.filter = args[ 0 ]; + } + else if( _.routineIs( args[ 0 ] ) ) + { + o = o || Object.create( null ); + o.onUp = args[ 0 ]; + } + else if( _.object.isBasic( args[ 0 ] ) ) + { + o = args[ 0 ]; + } + else + { + o = Object.create( null ); + if( args[ 0 ] !== undefined ) + o.filePath = args[ 0 ]; + } + + if( args.length === 2 ) + { + if( args[ 1 ] && args[ 1 ] instanceof _.files.FileRecordFilter ) + { + _.assert( !o.filter ) + o.filter = args[ 1 ]; + } + else if( _.routineIs( args[ 1 ] ) ) + { + _.assert( !o.onUp ); + o.onUp = args[ 1 ]; + } + else _.assert( 0, 'Expects censor or callback onUp as the second argument' ); + } + + _.routine.options_( routine, o ); + + o.filter = o.filter || Object.create( null ); + + if( Config.debug ) + { + _.assert( arguments.length === 2 ); + _.assert( 1 <= args.length && args.length <= 3 ); + _.assert( o.basePath === undefined ); + _.assert( o.prefixPath === undefined ); + _.assert( o.postfixPath === undefined ); + _.assert( _.object.isBasic( o.filter ) ); + } + + return o; +} + +// + +function _filesFindPrepare1( routine, args ) +{ + let self = this; + let path = self.path; + let o = args[ 0 ]; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 ); + + /* */ + + // if( o.onUp === null ) + // o.onUp = []; + if( _.arrayIs( o.onUp ) ) + if( o.onUp.length === 0 ) + o.onUp = function( record, op ){ return record }; + else + o.onUp = _.routinesComposeAllReturningLast( o.onUp ); + _.assert( _.routineIs( o.onUp ) || o.onUp === null ); + + // if( o.onDown === null ) + // o.onDown = []; + if( _.arrayIs( o.onDown ) ) + if( o.onDown.length === 0 ) + o.onDown = function( record, op ){}; + else + o.onDown = _.routinesComposeReturningLast( o.onDown ); + _.assert( _.routineIs( o.onDown ) || o.onDown === null ); + + /* */ + + _.assert( o.filter instanceof _.files.FileRecordFilter ); + if( o.filter.formed < 5 ) + o.filter._formAssociations(); + + let hasGlob = o.filter.filePathHasGlob(); + + if( o.filter.recursive === null ) + { + if( o.mode === 'distinct' ) + o.filter.recursive = hasGlob ? 2 : 0; + else + o.filter.recursive = hasGlob ? 2 : 2; + } + + if( Config.debug ) + { + _.assert( o.recursive === undefined ); + _.assert( !self.system || o.filter.system === self.system ); + _.assert( o.filter.filePath === null || path.s.allAreNormalized( o.filter.filePath ) ); + } + + return o; +} + +// + +function _filesFindPrepare2( routine, args ) +{ + let self = this; + let path = self.path; + let o = args[ 0 ]; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 ); + + /* */ + + let hasGlob = o.filter.filePathHasGlob(); + + if( o.withDefunct === null ) + { + if( o.mode === 'distinct' ) + o.withDefunct = !hasGlob; + else + o.withDefunct = false; + } + + o.withTerminals = !!o.withTerminals; + + if( o.mode === 'distinct' && o.withDirs === null ) + { + o.withDirs = !hasGlob; + } + o.withDirs = !!o.withDirs; + + if( o.withStem === null ) + o.withStem = true; + o.withStem = !!o.withStem; + + if( Config.debug ) + { + _.assert + ( + o.filter.recursive === 0 || o.filter.recursive === 1 || o.filter.recursive === 2, + () => 'Incorrect value of recursive option ' + _.strQuote( o.filter.recursive ) + ', should be 0, 1 or 2' + ); + } + + return o; +} + +// + +function _filesFindFilterAbsorb( routine, args ) +{ + let self = this; + let path = self.path; + let o = args[ 0 ]; + + _.assert( !o.filter || !o.filter.formed <= 3, 'Filter is already formed, but should not be!' ) + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 ); + + o.filter = self.recordFilter( o.filter || {} ); + + if( o.filter.formed < 5 ) + if( o.filePath ) + { + if( o.filePath instanceof _.files.FileRecordFilter ) + { + o.filter.pathsExtend( o.filePath ).and( o.filePath ); + o.filePath = null; + } + else + { + o.filter.filePath = path.mapExtend( o.filter.filePath, o.filePath ); + } + o.filePath = null; + } + + /* in case of '' */ + o.filePath = null; + + return o; +} + +// + +function filesFindNominal_head( routine, args ) +{ + let self = this; + let path = self.path; + + let o = self._filesFindPrepare0( routine, args ); + self._filesFindFilterAbsorb( routine, [ o ] ); + self._filesFindPrepare1( routine, [ o ] ); + + if( !o.filter.formed || o.filter.formed < 5 ) + o.filter.form(); + _.assert( !!o.filter.effectiveProvider ); + o.filter.effectiveProvider._providerDefaultsApply( o ); + + if( !o.filePath ) + o.filePath = o.filter.filePathSimplest(); + + _.assert( o.filePath && path.isNormalized( o.filePath ), 'Expects normalized path {-o.filePath-}' ); + _.assert( o.filePath && path.isAbsolute( o.filePath ), 'Expects absolute path {-o.filePath-}' ); + + if( !o.factory ) + { + let o2 = + { + stemPath : o.filePath, + basePath : o.filter.formedBasePath[ o.filePath ], + }; + _.assert( _.strDefined( o2.basePath ), 'No base path for', o.filePath ); + o.factory = _.files.FileRecordFactory.TolerantFrom( o, o2 ).form(); + } + + if( Config.debug ) + { + + _.routine.assertOptions( routine, o ); + _.assert + ( + o.filter.recursive === 0 || o.filter.recursive === 1 || o.filter.recursive === 2, + () => 'Incorrect value of recursive option ' + _.strQuote( o.filter.recursive ) + ', should be 0, 1 or 2' + ); + _.assert( !self.system || o.filter.system === self.system ); + _.assert( !!o.filter.effectiveProvider ); + _.assert( _.routineIs( o.onUp ) || o.onUp === null ); + _.assert( _.routineIs( o.onDown ) || o.onDown === null ); + _.assert( o.filter.formed === 5, 'Expects formed filter' ); + _.assert( _.object.isBasic( o.filter.effectiveProvider ) ); + _.assert( _.mapIs( o.filter.formedBasePath ), 'Expects base path' ); + _.assert( o.filter.effectiveProvider instanceof _.FileProvider.Abstract ); + _.assert( o.filter.defaultProvider instanceof _.FileProvider.Abstract ); + _.assert( o.withTerminals === undefined ); + _.assert( o.withDirs === undefined ); + _.assert( o.withStem === undefined ); + _.assert( o.mandatory === undefined ); + _.assert( o.orderingExclusion === undefined ); + _.assert( o.outputFormat === undefined ); + _.assert( o.safe === undefined ); + _.assert( o.maskPreset === undefined ); + _.assert( o.mode === undefined ); + _.assert( o.result === undefined ); + _.assert( !!o.factory ); + _.assert( o.factory.basePath === o.filter.formedBasePath[ o.filePath ] ); + _.assert( o.factory.dirPath === null ); + _.assert( o.factory.effectiveProvider === o.filter.effectiveProvider ); + _.assert( o.factory.system === o.filter.system || o.filter.system === null ); + _.assert( o.factory.defaultProvider === o.filter.defaultProvider ); + + } + + return o; +} + +// + +function filesFindNominal_body( o ) +{ + let self = this; + let path = self.path; + + o.filter.effectiveProvider.assertProviderDefaults( o ); + _.routine.assertOptions( filesFindNominal_body, arguments ); + _.assert( !!o.factory ); + _.assert( _.routineIs( o.onUp ) || o.onUp === null ); + _.assert( _.routineIs( o.onDown ) || o.onDown === null ); + + /* */ + + Object.freeze( o ); + + let stemRecord = o.factory.record( o.filePath ); + _.assert( stemRecord.isStem === true ); + _.assert( o.factory.basePath === o.filter.formedBasePath[ o.filePath ] ); + _.assert( o.factory.dirPath === null ); + _.assert( o.factory.effectiveProvider === o.filter.effectiveProvider ); + _.assert( o.factory.system === o.filter.system || o.filter.system === null ); + _.assert( o.factory.defaultProvider === o.filter.defaultProvider ); + + forStem( stemRecord, o ); + + return o; + + /* */ + + function forStem( r, op ) + { + forDirectory( r, op ) + forTerminal( r, op ) + } + + /* */ + + function forDirectory( r, op ) + { + + if( !r.isDir ) + return; + if( !r.isTransient && !r.isActual ) + return; + + /* up */ + + if( handleUp( r, op ) === _.dont ) + { + handleDown( r, op ); + return false; + } + + /* read */ + + if( r.isTransient && op.filter.recursive ) + if( op.filter.recursive === 2 || r.isStem ) + { + /* Vova : real path should be used for soft/text link to a dir for two reasons: + - files from linked directory should be taken into account + - usage of r.absolute path for a link will lead to recursion on next forDirectory( file, op ), because dirRead will return same path( r.absolute ) + outputFormat : relative is used because absolute path should contain path to a link in head + */ + // let files = op.filter.effectiveProvider.dirRead({ filePath : r.absolute, outputFormat : 'absolute' }); + let files = op.filter.effectiveProvider.dirRead({ filePath : r.real, outputFormat : 'relative' }); + + if( files === null ) + { + if( o.factory.allowingMissed ) + { + debugger; + files = []; + } + else + { + debugger; + throw _.err( 'Failed to read directory', _.strQuote( r.absolute ) ); + } + } + + files = self.path.s.join( r.absolute, files ); + files = r.factory.records( files ); + + /* terminals */ + + for( let f = 0 ; f < files.length ; f++ ) + { + let file = files[ f ]; + forTerminal( file, op ); + } + + /* dirs */ + + for( let f = 0 ; f < files.length ; f++ ) + { + let file = files[ f ]; + forDirectory( file, op ); + } + + } + + /* down */ + + handleDown( r, op ); + + } + + /* */ + + function forTerminal( r, op ) + { + + if( r.isDir ) + return; + if( !r.isTransient && !r.isActual ) + return; + + handleUp( r, op ); + handleDown( r, op ); + + } + + /* - */ + + function handleUp( record, op ) + { + _.assert( arguments.length === 2 ); + if( op.onUp ) + { + let r = op.onUp.call( self, record, op ); + _.assert + ( + r === _.dont || r === record, + () => `Callback onUp should return original record or _.dont, but returned ${_.entity.exportStringDiagnosticShallow( r )}` + ); + return r; + } + return record; + } + + /* - */ + + function handleDown( record, op ) + { + _.assert( arguments.length === 2 ); + if( op.onDown ) + { + let r = op.onDown.call( self, record, op ); + _.assert + ( + r === undefined, + () => 'Callback onDown should return nothing( undefined ), but returned' + _.entity.exportStringDiagnosticShallow( r ) + // () => `Callback onDown should return nothing( undefined ), but returned ${_.entity.exportStringDiagnosticShallow( r )}` + /* qqq : make global replacement by string-templates where it is appropriate */ + ); + } + } + + /* - */ + +} + +var defaults = filesFindNominal_body.defaults = Object.create( null ); + +defaults.sync = 1; +defaults.filePath = null; +defaults.filter = null; +defaults.factory = null; +defaults.onUp = null; +defaults.onDown = null; + +var having = filesFindNominal_body.having = Object.create( null ); + +having.writing = 0; +having.reading = 1; +having.driving = 0; + +let filesFindNominal = _.routine.uniteCloning_replaceByUnite( filesFindNominal_head, filesFindNominal_body ); + +// + +function filesFindSingle_head( routine, args ) +{ + let self = this; + let path = self.path; + + let o = self._filesFindPrepare0( routine, args ); + self._filesFindFilterAbsorb( routine, [ o ] ); + self._filesFindPrepare1( routine, [ o ] ); + self._filesFindPrepare2( routine, [ o ] ); + + if( !o.filter.formed || o.filter.formed < 5 ) + o.filter.form(); + _.assert( !!o.filter.effectiveProvider ); + o.filter.effectiveProvider._providerDefaultsApply( o ); + + if( Config.debug ) + { + _.routine.assertOptions( routine, o ); + _.assert( !self.system || o.filter.system === self.system ); + _.assert( !!o.filter.effectiveProvider ); + _.assert( _.routineIs( o.onUp ) || o.onUp === null ); + _.assert( _.routineIs( o.onDown ) || o.onDown === null ); + _.assert( path.isNormalized( o.filePath ), 'Expects normalized path {-o.filePath-}' ); + _.assert( path.isAbsolute( o.filePath ), 'Expects absolute path {-o.filePath-}' ); + _.assert( o.filter.formed === 5, 'Expects formed filter' ); + _.assert( _.object.isBasic( o.filter.effectiveProvider ) ); + _.assert( _.mapIs( o.filter.formedBasePath ), 'Expects base path' ); + _.assert( _.boolLike( o.withTerminals ) ); + _.assert( _.boolLike( o.withDirs ) ); + _.assert( _.boolLike( o.withStem ) ); + _.assert( !!o.filter.effectiveProvider ); + _.assert( o.filter.effectiveProvider instanceof _.FileProvider.Abstract ); + _.assert( o.filter.defaultProvider instanceof _.FileProvider.Abstract ); + _.assert( o.mandatory === undefined ); + _.assert( o.orderingExclusion === undefined ); + _.assert( o.outputFormat === undefined ); + _.assert( o.outputFormat === undefined ); + _.assert( o.safe === undefined ); + _.assert( o.maskPreset === undefined ); + _.assert( o.mode === undefined ); + _.assert( o.result === undefined ); + _.assert( !!o.factory ); + } + + return o; +} + +// + +function filesFindSingle_body( o ) +{ + let self = this; + let path = self.path; + + _.routine.assertOptions( filesFindSingle_body, arguments ); + + let o2 = _.props.extend( null, o ); + delete o2.withTerminals; + delete o2.withDirs; + delete o2.withActual; + delete o2.withTransient; + delete o2.withStem; + delete o2.withDefunct; + delete o2.visitingCertain; + + o2.onUp = handleUp; + o2.onDown = handleDown; + + let result = self.filesFindNominal.body.call( self, o2 ); + return result; + + /* - */ + + function handleUp( record, op ) + { + + if( !o.visitingCertain && !record.isStem ) + { + let hasMask = o.filter.hasMask(); + if( !hasMask ) + return _.dont; + } + + let includingFile = record.isDir ? o.withDirs : o.withTerminals; + let withTransient = ( o.withTransient && record.isTransient ); + let withActual = ( o.withActual && record.isActual ); + let included = true; + included = included && ( withTransient || withActual ); + included = included && ( includingFile ); + included = included && ( o.withStem || !record.isStem ); + included = included && ( o.withDefunct || !!record.stat ); + included = included && ( o.withDefunct || record.isCycled !== true ); + included = included && ( o.withDefunct || record.isMissed !== true ); + record.included = included; + + _.assert( arguments.length === 2 ); + if( o.onUp ) + { + let r = o.onUp.call( self, record, o ); + _.assert + ( + r === _.dont || r === record, + () => 'Callback onUp should return original record or _.dont, but returned' + _.entity.exportStringDiagnosticShallow( r ) + ); + return r; + } + return record; + } + + /* - */ + + function handleDown( record, op ) + { + _.assert( arguments.length === 2 ); + if( o.onDown ) + { + let r = o.onDown.call( self, record, o ); + _.assert + ( + r === undefined, + () => 'Callback onDown should return nothing( undefined ), but returned' + _.entity.exportStringDiagnosticShallow( r ) + ); + } + } + +} + +_.assert( _.routineIs( filesFindNominal.body ) ); +_.routineExtend( filesFindSingle_body, filesFindNominal.body ); +_.assert( filesFindSingle_body.body === undefined ); + +var defaults = filesFindSingle_body.defaults = _.props.extend( null, filesFindSingle_body.defaults ); + +defaults.withTerminals = true; +defaults.withDirs = null; +defaults.withStem = true; +defaults.withDefunct = null; + +defaults.withActual = true; /* xxx */ +defaults.withTransient = false; /* xxx */ +defaults.visitingCertain = true; /* xxx */ + +let filesFindSingle = _.routine.uniteCloning_replaceByUnite( filesFindSingle_head, filesFindSingle_body ); + +// + +/** + * @summary Searches for files in the specified path `o.filePath`. + * @returns Returns flat array with FileRecord instances of found files. + * @param {Object} o Options map. + * + * @param {*} o.filePath + * @param {*} o.filter + * @param {*} o.withTerminals=1 + * @param {*} o.withDirs=0 + * @param {*} o.withStem=1 + * @param {*} o.withActual=1 + * @param {*} o.withTransient=0 + * @param {*} o.allowingMissed=0 + * @param {*} o.allowingCycled=0 + * @param {Boolean} o.revisiting=null Controls how visited files are processed. Possible values: + * 0 - visit and include each file once + * 1 - visit and include each file once, break from loop on first links cycle and continue search ignoring file at which cycle begins + * 2 - visit and include each file once, break from loop on first links cycle and continue search visiting file at which cycle begins + * 3 - don't keep records of visited files + * Defaults: option o.revisiting in set to "1" if links resolving is enabled, otherwise default is "3". + * @param {*} o.resolvingSoftLink=0 + * @param {*} o.resolvingTextLink=0 + * @param {*} o.maskPreset='default.exclude' + * @param {*} o.outputFormat='record' + * @param {*} o.safe=null + * @param {*} o.sync=1 + * @param {*} o.orderingExclusion=[] + * @param {*} o.sortingWithArray + * @param {*} o.verbosity + * @param {*} o.mandatory + * @param {*} o.result=[] + * @param {*} o.onUp=[] + * @param {*} o.onDown=[] + * + * @function filesFind + * @class wFileProviderFindMixin + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function filesFind_head( routine, args ) +{ + let self = this; + let path = self.path; + + let o = self._filesFindPrepare0( routine, args ); + + self._filesFindFilterAbsorb( routine, [ o ] ); + + if( Config.debug ) + { + + _.assert( _.longHas( [ 'legacy', 'distinct' ], o.mode ), () => 'Unknown mode ' + _.strQuote( o.mode ) ); + + if( 'outputFormat' in o ) + { + // let knownFormats = [ 'absolute', 'relative', 'real', 'record', 'nothing' ]; + _.assert + ( + // _.longHas( knownFormats, o.outputFormat ), + !!self.FindOutputFormat[ o.outputFormat ], + () => 'Unknown output format ' + _.entity.exportStringDiagnosticShallow( o.outputFormat ) + + '\nKnown output formats : ' + _.entity.exportString( _.props.keys( self.FindOutputFormat ) ) + ); + } + + } + + let hasGlob = o.filter.filePathHasGlob(); + + if( o.mandatory === null ) + { + if( o.mode === 'distinct' ) + o.mandatory = hasGlob; + else + o.mandatory = false; + } + + if( o.result === null ) + o.result = []; + + if( o.maskPreset ) + { + _.assert( o.maskPreset === 'default.exclude', 'Not supported preset', o.maskPreset ); + o.filter = o.filter || Object.create( null ); + if( !o.filter.formed || o.filter.formed < 5 ) + _.files.filterSafer( o.filter ); + } + + if( o.orderingExclusion === null ) + o.orderingExclusion = []; + + if( o.revisiting === null ) + if( o.resolvingSoftLink || o.resolvingTextLink ) + o.revisiting = 1; + else + o.revisiting = 3; + + _.assert( _.longHas( [ 0, 1, 2, 3 ], o.revisiting ) ); + _.assert( o.revisitingHardLinked === 0 || o.revisitingHardLinked === 1 ); + _.assert + ( + o.revisitingHardLinked === 1 || self.SupportsIno >= 1, + `Option revisitingHardLinked : 0 is supported only if file provider supports ino of file.` + + `\nBut file provider ${self.constructor.name} does not support ino of file.` + ); + + if( o.revisiting === 0 ) + if( o.visitedMap === null ) + o.visitedMap = Object.create( null ); + + if( o.revisitingHardLinked === 0 ) + if( o.visitedInosSet === null ) + o.visitedInosSet = new Set; + + if( o.revisiting === 1 || o.revisiting === 2 ) + if( o.visitedStack === null ) + o.visitedStack = []; + + self._filesFindPrepare1( routine, [ o ] ); + self._filesFindPrepare2( routine, [ o ] ); + + if( !o.filter.formed || o.filter.formed < 5 ) + o.filter.form(); + _.assert( !!o.filter.effectiveProvider ); + o.filter.effectiveProvider._providerDefaultsApply( o ); + + if( Config.debug ) + { + _.assert( !self.system || o.filter.system === self.system ); + _.assert( !!o.filter.effectiveProvider ); + } + + return o; +} + +function filesFind_body( o ) +{ + let self = this; + let path = self.path; + let counter = 0; + let ready = new _.Consequence().take( o ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( o.filePath === null ); + _.assert( o.filter.formed === 5 ); + _.assert( _.routineIs( o.onUp ) || o.onUp === null ); + _.assert( _.routineIs( o.onDown ) || o.onDown === null ); + + let time; + if( o.verbosity >= 1 ) + time = _.time.now(); + + if( o.verbosity >= 3 ) + self.logger.log( 'filesFind', _.entity.exportString( o, { levels : 2 } ) ); + + let pathMap = o.filter.formedFilePath; + + o.filePath = []; + + for( let src in pathMap ) + { + let dst = pathMap[ src ]; + if( _.boolLike( dst ) ) + continue; + o.filePath.push( src ); + } + + o.result = o.result || []; + + _.assert( _.strsAreAll( o.filePath ) ); + _.assert( !o.orderingExclusion.length || o.orderingExclusion.length === 0 || o.outputFormat === 'record' ); + + if( o.mandatory ) + if( _.entity.lengthOf( o.filePath ) !== _.entity.lengthOf( o.filter.filePath ) ) + { + for( let stemPath in o.filter.filePath ) + { + if( _.boolLike( o.filter.filePath[ stemPath ] ) ) + continue; + stemPath = path.fromGlob( stemPath ); + if( !self.fileExists( stemPath ) ) + throw _.err( 'Stem not found : ' + stemPath ); + } + } + + forStems( o.filePath, o ); + + return end(); + + /* - */ + + function forStems( stemPaths, op ) + { + + if( _.strIs( stemPaths ) ) + stemPaths = [ stemPaths ]; + stemPaths = _.longOnce( stemPaths ); + _.strsSort( stemPaths ); + _.assert( _.arrayIs( stemPaths ), 'Expects path or array of paths' ); + + let o2 = Object.assign( Object.create( null ), op ); + + delete o2.orderingExclusion; + delete o2.sortingWithArray; + delete o2.verbosity; + delete o2.mode; + delete o2.maskPreset; + delete o2.mandatory; + delete o2.outputFormat; + delete o2.safe; + delete o2.revisiting; + delete o2.revisitingHardLinked; + delete o2.visitedMap; + delete o2.visitedStack; + delete o2.visitedInosSet; + delete o2.result; + delete o2.resolvingSoftLink; + delete o2.resolvingTextLink; + delete o2.allowingMissed; + delete o2.allowingCycled; + + o2.onUp = onUp_functor( op ); + o2.onDown = onDown_functor( op ); + + for( let p = 0 ; p < stemPaths.length ; p++ ) ready.then( () => + { + let stemPath = stemPaths[ p ]; + return forStem( stemPath, o2 ) + }) + + } + + /* - */ + + function forStem( stemPath, o2 ) + { + let o3 = Object.assign( Object.create( null ), o2 ); + + _.assert( _.strIs( stemPath ) ); + + o3.filePath = stemPath; + + let o4 = + { + stemPath, + basePath : o2.filter.formedBasePath[ stemPath ], + resolvingSoftLink : o.resolvingSoftLink, + resolvingTextLink : o.resolvingTextLink, + allowingMissed : o.allowingMissed, + allowingCycled : o.allowingCycled, + safe : o.safe, + }; + _.assert( _.strDefined( o4.basePath ), 'No base path for', stemPath ); + o3.factory = _.files.FileRecordFactory.TolerantFrom( o3, o4 ).form(); + + _.assert( o3.factory.basePath === o3.filter.formedBasePath[ stemPath ] ); + _.assert( o3.factory.dirPath === null ); + _.assert( o3.factory.effectiveProvider === o3.filter.effectiveProvider ); + _.assert( o3.factory.system === o3.filter.system || o3.filter.system === null ); + _.assert( o3.factory.defaultProvider === o3.filter.defaultProvider ); + + let counterWas = counter; + + return _.Consequence.Try( () => + { + let r = self.filesFindSingle.body.call( self, o3 ); + return r; + }) + .then( ( op ) => + { + if( !o.mandatory ) + return op; + + if( o.result.length === 0 ) + { + debugger; + throw _.err( 'No file found at ' + stemPath ); + } + else if( counterWas === counter ) + { + if( !o.allowingMissed ) + { + debugger; + throw _.err( 'Stem does not exist ' + stemPath ); + } + } + + return op; + }) + .catch( ( err ) => + { + debugger; + throw _.err( err ); + }); + + } + + /* - */ + + function handleUp( record, op ) + { + + _.assert( arguments.length === 2, 'Expects single argument' ); + + if( record.stat ) + counter += 1; + + let visited = false; + + if( o.visitedInosSet && record.stat ) + { + _.assert( record.stat && self.isIno({ ino : record.stat.ino }) ); + if( o.visitedInosSet.has( record.stat.ino ) ) + return _.dont; + } + + if( o.revisiting === 1 ) + { + if( _.longHas( o.visitedStack, record.real ) ) + visited = true; + o.visitedStack.push( record.real ); + if( visited ) + return _.dont; + } + else if( o.revisiting === 2 ) + { + if( _.longHas( o.visitedStack, record.real ) ) + visited = true; + o.visitedStack.push( record.real ); + } + else if( o.visitedStack ) + { + o.visitedStack.push( record.real ); + } + + if( o.revisiting === 0 ) + { + if( o.visitedMap[ record.real ] ) + return _.dont; + } + + if( o.onUp ) + { + let r = o.onUp.call( self, record, o ); + _.assert + ( + r === _.dont || r === record, + () => 'Callback onUp should return original record or _.dont, but returned' + _.entity.exportStringDiagnosticShallow( r ) + ); + if( r === _.dont ) + return _.dont; + } + + if( o.visitedMap ) + o.visitedMap[ record.real ] = record; + + if( o.visitedInosSet && record.stat ) + { + _.assert( self.isIno({ ino : record.stat.ino }) ); + o.visitedInosSet.add( record.stat.ino ); + } + + if( visited ) + return 'dontButRecord'; + + return record; + } + + /* - */ + + function handleDown( record, op ) + { + + if( o.revisiting === 1 ) + { + _.assert( o.visitedStack[ o.visitedStack.length - 1 ] === record.real ); + o.visitedStack.pop(); + if( _.longHas( o.visitedStack, record.real ) ) + return; + } + else if( o.revisiting === 2 ) + { + _.assert( o.visitedStack[ o.visitedStack.length - 1 ] === record.real ); + o.visitedStack.pop(); + } + else if( o.visitedStack ) + { + _.assert( o.visitedStack[ o.visitedStack.length - 1 ] === record.real ); + o.visitedStack.pop(); + } + + if( o.revisiting === 0 ) + { + if( o.visitedMap[ record.real ] !== record ) + return; + } + + if( o.onDown ) + { + let r = o.onDown.call( self, record, o ); + _.assert + ( + r === undefined, + () => 'Callback onDown should return undefined' + _.entity.exportStringDiagnosticShallow( r ) + ); + } + + } + + /* - */ + + function onUp_functor( fop ) + { + let recordAdd; + + if( fop.outputFormat === 'absolute' ) + recordAdd = function addAbsolute( record, op ) + { + let r = handleUp.apply( this, arguments ); + if( r === _.dont ) + return _.dont; + if( record.included ) + fop.result.push( record.absolute ); + if( r === record ) + return record; + else + return _.dont; + } + else if( fop.outputFormat === 'relative' ) + recordAdd = function addRelative( record, op ) + { + let r = handleUp.apply( this, arguments ); + if( r === _.dont ) + return _.dont; + if( record.included ) + fop.result.push( record.relative ); + if( r === record ) + return record; + else + return _.dont; + } + else if( fop.outputFormat === 'real' ) + recordAdd = function addReal( record, op ) + { + let r = handleUp.apply( this, arguments ); + if( r === _.dont ) + return _.dont; + if( record.included ) + fop.result.push( record.real ); + if( r === record ) + return record; + else + return _.dont; + } + else if( fop.outputFormat === 'record' ) + recordAdd = function addRecord( record, op ) + { + let r = handleUp.apply( this, arguments ); + if( r === _.dont ) + return _.dont; + if( record.included ) + fop.result.push( record ); + if( r === record ) + return record; + else + return _.dont; + } + else if( fop.outputFormat === 'nothing' ) + recordAdd = function addNothing( record, op ) + { + let r = handleUp.apply( this, arguments ); + if( r === _.dont ) + return _.dont; + if( r === record ) + return record; + else + return _.dont; + } + else _.assert( 0, 'Unknown output format :', o.outputFormat ); + + return recordAdd; + } + + /* - */ + + function onDown_functor( fop ) + { + return handleDown; + } + + /* - */ + + function end() + { + ready.then( () => + { + + /* order */ + + o.result = self.recordsOrder( o.result, o.orderingExclusion ); + + /* sort */ + + if( o.sortingWithArray ) + { + + _.assert( _.arrayIs( o.sortingWithArray ) ); + + if( o.outputFormat === 'record' ) + o.result.sort( function( a, b ) + { + return _.regexpArrayIndex( o.sortingWithArray, a.relative ) - _.regexpArrayIndex( o.sortingWithArray, b.relative ); + }) + else + o.result.sort( function( a, b ) + { + return _.regexpArrayIndex( o.sortingWithArray, a ) - _.regexpArrayIndex( o.sortingWithArray, b ); + }); + + } + + /* mandatory */ + + if( o.mandatory ) + if( !o.result.length ) + { + debugger; + throw _.err( 'No file found at ' + path.commonTextualReport( o.filter.filePath || o.filePath ) ); + } + + /* timing */ + + if( o.verbosity >= 1 ) + self.logger.log( ' . Found ' + o.result.length + ' files at ' + o.filePath + ' in ', _.time.spent( time ) ); + + return o.result; + }); + + if( o.sync ) + return ready.sync(); + else + return ready; + } + +} + +_.assert( filesFindSingle.body.body === undefined ); +_.assert( filesFind_body.body === undefined ); +_.routineExtend( filesFind_body, filesFindSingle.body ); +_.assert( filesFindSingle.body.body === undefined ); +_.assert( filesFind_body.body === undefined ); + +var defaults = filesFind_body.defaults = _.props.extend( null, filesFind_body.defaults ); + +delete defaults.factory; + +defaults.sync = 1; +defaults.orderingExclusion = null; +defaults.sortingWithArray = null; +defaults.verbosity = null; +defaults.mandatory = null; +defaults.safe = null; +defaults.maskPreset = 'default.exclude'; +defaults.outputFormat = 'record'; +defaults.result = null; +defaults.mode = 'legacy'; /* qqq2 : xxx : change to distinct */ +defaults.revisiting = null; +defaults.revisitingHardLinked = 1; +defaults.visitedMap = null; +defaults.visitedStack = null; +defaults.visitedInosSet = null; +defaults.resolvingSoftLink = 0; +defaults.resolvingTextLink = 0; +defaults.allowingMissed = 0; +defaults.allowingCycled = 0; + +_.assert( defaults.maskAll === undefined ); +_.assert( defaults.glob === undefined ); + +_.assert( filesFind_body.body === undefined ); +let filesFind = _.routine.uniteCloning_replaceByUnite( filesFind_head, filesFind_body ); +_.assert( filesFind_body.body === undefined ); + +filesFind.having.aspect = 'entry'; + +// + +/** + * @description Short-cut for {@link module:Tools/mid/Files.wTools.FileProvider.FindMixin.filesFind}. + * Performs recursive search for files from specified path `o.filePath`. + * Includes terminals,directories and transient files into the result array. + * @param {Object} o Options map. + * + * @param {*} o.filePath + * @param {*} o.filter + * @param {*} o.withTerminals=1 + * @param {*} o.withDirs=1 + * @param {*} o.withStem=1 + * @param {*} o.withActual=1 + * @param {*} o.withTransient=1 + * @param {*} o.allowingMissed=1 + * @param {*} o.allowingCycled=1 + * @param {*} o.resolvingSoftLink=0 + * @param {*} o.resolvingTextLink=0 + * @param {*} o.maskPreset='default.exclude' + * @param {*} o.outputFormat='record' + * @param {*} o.safe=null + * @param {*} o.sync=1 + * @param {*} o.orderingExclusion=[] + * @param {*} o.sortingWithArray + * @param {*} o.verbosity + * @param {*} o.mandatory + * @param {*} o.result=[] + * @param {*} o.onUp=[] + * @param {*} o.onDown=[] + * + * @function filesFindRecursive + * @class wFileProviderFindMixin + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function filesFindRecursive_head( routine, args ) +{ + let self = this; + let o = self._filesFindPrepare0( routine, args ); + // self._filesFindFilterAbsorb( routine, [ o ] ); + if( o.filter.recursive === undefined || o.filter.recursive === null ) + o.filter.recursive = 2; + return self.filesFind.head.call( self, routine, [ o ] ); +} + +let filesFindRecursive = _.routine.uniteCloning_replaceByUnite( filesFindRecursive_head, filesFind.body ); + +var defaults = filesFindRecursive.defaults; +defaults.filePath = null; +// defaults.recursive = 2; +defaults.withTransient = 0; +defaults.withDirs = 1; +defaults.withTerminals = 1; +defaults.allowingMissed = 1; +defaults.allowingCycled = 1; + +// + +/** + * @description Short-cut for {@link module:Tools/mid/Files.wTools.FileProvider.FindMixin.filesFind}. + * Performs recursive search for files using glob pattern `o.filePath` using glob pattern. + * Includes terminals,directories into the result array. + * @param {Object} o Options map. + * + * @param {*} o.filePath + * @param {*} o.filter + * @param {*} o.withTerminals=1 + * @param {*} o.withDirs=1 + * @param {*} o.withStem=1 + * @param {*} o.withActual=1 + * @param {*} o.withTransient=0 + * @param {*} o.allowingMissed=0 + * @param {*} o.allowingCycled=0 + * @param {*} o.resolvingSoftLink=0 + * @param {*} o.resolvingTextLink=0 + * @param {*} o.maskPreset='default.exclude' + * @param {*} o.outputFormat='absolute' + * @param {*} o.safe=null + * @param {*} o.sync=1 + * @param {*} o.orderingExclusion=[] + * @param {*} o.sortingWithArray + * @param {*} o.verbosity + * @param {*} o.mandatory + * @param {*} o.result=[] + * @param {*} o.onUp=[] + * @param {*} o.onDown=[] + * + * @function filesGlob + * @class wFileProviderFindMixin + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function filesGlob( o ) +{ + let self = this; + + if( _.strIs( o ) ) + o = { filePath : o } + + // if( o.recursive === undefined ) + // o.recursive = 2; + + o.filter = o.filter || Object.create( null ); + + if( o.filter.recursive === undefined || o.filter.recursive === null ) + o.filter.recursive = 2; + + if( !o.filePath && !o.filter.filePath ) + { + o.filter.filePath = o.filter.recursive === 2 ? '**' : '*'; + // o.filter.filePath = o.recursive === 2 ? '**' : '*'; + } + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.object.isBasic( o ) ); + + let result = self.filesFind( o ); + + return result; +} + +_.routineExtend( filesGlob, filesFind ); + +var defaults = filesGlob.defaults; + +// defaults.outputFormat = 'absolute'; +// defaults.recursive = 2; +defaults.withTerminals = 1; +defaults.withDirs = 1; +defaults.withTransient = 0; + +// + +/** + * @description Functor for {@link module:Tools/mid/Files.wTools.FileProvider.FindMixin.filesFind} routine. + * Creates a filesFind routine with options saved in inner context. + * It allows to reuse created routine changing only necessary options and don't worry about other options. + * @param {Object} o Options map. Please see {@link module:Tools/mid/Files.wTools.FileProvider.FindMixin.filesFind} for options description. + * @function filesFinder + * @class wFileProviderFindMixin + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function filesFinder_functor( routine ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.routineIs( routine ) ); + _.routineExtend( finder, routine ); + return finder; + + function finder() + { + let self = this; + let path = self.path; + let op0 = self._filesFindPrepare0( routine, arguments ); + _.map.assertHasOnly( op0, finder.defaults ); + return er; + + function er() + { + let o = _.props.extend( null, op0 ); + o.filter = self.recordFilter( o.filter ); + if( o.filePath ) + { + o.filter.filePath = path.mapExtend( o.filter.filePath, o.filePath ); + o.filePath = null; + } + + for( let a = 0 ; a < arguments.length ; a++ ) + { + let op2 = arguments[ a ]; + + if( !_.object.isBasic( op2 ) ) + op2 = { filePath : op2 } + + op2.filter = self.recordFilter( op2.filter || Object.create( null ) ); + + if( op2.filePath ) + { + op2.filter.filePath = path.mapExtend( op2.filter.filePath, op2.filePath ); + op2.filePath = null; + } + + o.filter.and( op2.filter ); + o.filter.pathsExtendJoining( op2.filter ); + // o.filter.pathsJoin( op2.filter ); + + op2.filter = o.filter; + op2.filePath = o.filePath; + + _.props.extend( o, op2 ); + + } + + // debugger; + return routine.call( self, o ); + } + + } + +} + +let filesFinder = filesFinder_functor( filesFind ); +let filesGlober = filesFinder_functor( filesGlob ); + +// -- +// files find groups +// -- + +function filesFindGroups_head( routine, args ) +{ + let self = this; + let o = self._preFileFilterWithoutProviderDefaults.apply( self, arguments ); + return o; +} + +// + +/* +qqq : filesFindGroups requires tests + +don't forget option mandatory + +*/ + +function filesFindGroups_body( o ) +{ + let self = this; + let path = self.path; + let ready = new _.Consequence(); + + _.assert( o.src.formed === 3 ); + _.assert( o.dst.formed === 3 ); + + let r = Object.create( null ); + r.options = o; + r.pathsGrouped = path.mapGroupByDst( o.src.filePath ); + r.filesGrouped = Object.create( null ); + r.srcFiles = Object.create( null ); + r.errors = []; + + /* */ + + for( let dstPath in r.pathsGrouped ) ( function( dstPath ) + { + let srcPath = r.pathsGrouped[ dstPath ]; + let o2 = _.mapOnly_( null, o, self.filesFind.body.defaults ); + + ready.finallyGive( 1 ); + + o2.result = []; + o2.filter = o.src.clone(); + o2.filter.filePathSelect( srcPath, dstPath ); + _.assert( o2.filter.formed === 3 ); + + _.Consequence.Try( () => self.filesFind( o2 ) ) + .finally( ( err, files ) => + { + + if( err ) + { + r.errors.push( err ); + } + else + { + r.filesGrouped[ dstPath ] = files; + files.forEach( ( file ) => + { + if( _.strIs( file ) ) + r.srcFiles[ file ] = file; + else + r.srcFiles[ file.absolute ] = file; + }); + } + + ready.take( null ); + return null; + }); + + })( dstPath ); + + /* */ + + ready.take( null ); + ready.finally( () => + { + if( r.errors.length ) + { + r.errors.forEach( ( err, index ) => index > 0 ? _.errAttend( err ) : null ); /* yyy */ + if( o.throwing ) + throw r.errors[ 0 ]; + // throw _.err.apply( _, r.errors ) + } + return r; + }); + + + if( o.sync ) + return ready.sync(); + return ready; + // return ready.syncMaybe(); +} + +var defaults = filesFindGroups_body.defaults = _.props.extend( null, filesFind.defaults ); + +delete defaults.filePath; +delete defaults.filter; + +defaults.src = null; +defaults.dst = null; +defaults.sync = 1; +defaults.throwing = null; +defaults.mode = 'distinct'; + +// + +let filesFindGroups = _.routine.uniteCloning_replaceByUnite( filesFindGroups_head, filesFindGroups_body ); + +// + +function filesReadGroups_head( routine, args ) +{ + let self = this; + + // debugger; + + let o = self._preFileFilterWithoutProviderDefaults.apply( self, arguments ); + + // debugger; + + return o; +} + +function filesReadGroups_body( o ) +{ + let self = this; + let path = self.path; + let ready = self.filesFindGroups( o ); + let r; + + _.assert( o.src.formed === 3 ); + + /* */ + + ready = _.Consequence.From( ready ); + + ready.then( ( result ) => + { + r = result; + r.dataMap = Object.create( null ); + r.grouped = Object.create( null ); + + for( let dstPath in r.filesGrouped ) + { + let files = r.filesGrouped[ dstPath ]; + for( let f = 0 ; f < files.length ; f++ ) + fileRead( files[ f ], dstPath ); + } + + return r; + }); + + if( o.sync ) + return ready.sync(); + return ready; + + /* */ + + function fileRead( record, dstPath ) + { + let descriptor = r.grouped[ dstPath ]; + + if( !descriptor ) + { + descriptor = r.grouped[ dstPath ] = Object.create( null ); + descriptor.dstPath = dstPath; + descriptor.pathsGrouped = r.pathsGrouped[ dstPath ]; + descriptor.filesGrouped = r.filesGrouped[ dstPath ]; + descriptor.dataMap = Object.create( null ); + } + + try + { + r.dataMap[ record.absolute ] = self.fileRead({ filePath : record.absolute, sync : o.sync }); + ready.finallyGive( 1 ); + _.Consequence.From( r.dataMap[ record.absolute ] ) + .finally( ( err, data ) => + { + if( err ) + { + r.errors.push( err ); + return null; + } + r.dataMap[ record.absolute ] = data; + descriptor.dataMap[ record.absolute ] = data; + return null; + }) + .finally( ready ); + } + catch( err ) + { + r.errors.push( err ); + } + + } + +} + +filesReadGroups_body.defaults = Object.create( filesFindGroups.defaults ); + +let filesReadGroups = _.routine.uniteCloning_replaceByUnite( filesReadGroups_head, filesReadGroups_body ); + +// -- +// +// -- + +function _filesFiltersPrepare( routine, o ) +{ + let self = this; + + _.assert( arguments.length === 2 ); + + /* */ + + if( o.src === undefined || o.src === null ) + o.src = o.filter; + + o.src = self.recordFilter( o.src ); + o.dst = self.recordFilter( o.dst ); + + o.src.pairWithDst( o.dst ); + o.src.pairRefineLight(); + + if( o.filter ) /* qqq : cover please */ + { + o.src.and( o.filter ).pathsSupplement( o.filter ); + o.dst.and( o.filter ).pathsSupplement( o.filter ); + } + + if( o.src.recursive === null ) + o.src.recursive = 2; + o.dst.recursive = 2; + + /* */ + + _.assert( _.object.isBasic( o.src ) ); + _.assert( _.object.isBasic( o.dst ) ); + _.assert( o.src.formed <= 1 ); + _.assert( o.dst.formed <= 1 ); + _.assert( _.object.isBasic( o.src.defaultProvider ) ); + _.assert( _.object.isBasic( o.dst.defaultProvider ) ); + _.assert( !( o.src.effectiveProvider instanceof _.FileProvider.System ) ); + _.assert( !( o.dst.effectiveProvider instanceof _.FileProvider.System ) ); + _.assert( o.srcProvider === undefined ); + _.assert( o.dstProvider === undefined ); + _.assert( o.dst.recursive === 2 ); + +} + +// + +function _filesReflectPrepare( routine, args ) +{ + let self = this; + let o = args[ 0 ]; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 || args.length === 2 ); + + if( args.length === 2 ) + o = { dst : args[ 0 ], src : args[ 1 ] } + + _.routine.options_( routine, o ); + self._providerDefaultsApply( o ); + + if( o.onUp ) + o.onUp = _.routinesComposeAll( o.onUp ); + if( o.onDown ) + o.onDown = _.routinesComposeReturningLast( o.onDown ); + + if( o.result === null ) + o.result = []; + + if( o.includingDst === null || o.includingDst === undefined ) + o.includingDst = o.dstDeleting; + + self._filesFiltersPrepare( routine, o ); + + _.assert( o.srcPath === undefined ); + _.assert( o.dstPath === undefined ); + _.assert( o.src.isPaired( o.dst ) ); + _.assert( !o.dstDeleting || !!o.includingDst ); + _.assert( o.onDstName === null || _.routineIs( o.onDstName ) ); + _.assert( _.boolLike( o.includingDst ) ); + _.assert( _.boolLike( o.dstDeleting ) ); + _.assert( _.arrayIs( o.result ) ); + _.assert( _.routineIs( o.onUp ) || o.onUp === null ); + _.assert( _.routineIs( o.onDown ) || o.onDown === null ); + // _.assert( _.longHas( [ 'fileCopy', 'hardLink', 'hardLinkMaybe', 'softLink', 'softLinkMaybe', 'textLink', 'nop' ], o.linkingAction ), 'unknown kind of linkingAction', o.linkingAction ); + _.assert( !!self.ReflectAction[ o.linkingAction ], () => 'Unknown kind of linkingAction' + o.linkingAction ); + + return o; +} + +// + +function filesReflectEvaluate_head( routine, args ) +{ + let self = this; + let o = self._filesReflectPrepare( routine, args ); + + _.assert( o.filter === undefined ); + _.assert( o.rebasingLink === undefined ); + + return o; +} + +// + +function filesReflectEvaluate_body( o ) +{ + let self = this; + let actionMap = Object.create( null ); + let touchMap = Object.create( null ); + let dstDeleteMap = Object.create( null ); + let recordAdd = recordAdd_functor( o ); + let recordRemove = recordRemove_functor( o ); + let dstPath = o.dst.filePathSimplest( o.dst.filePathNormalizedGet() ); + + _.routine.assertOptions( filesReflectEvaluate_body, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( dstPath ) ); + _.assert( o.outputFormat === undefined ); + + let srcOptions = srcOptionsForm(); + let dstOptions = dstOptionsForm(); + let dstRecordFactory = dstFactoryForm(); + let dst = o.dst.effectiveProvider; + let src = o.src.effectiveProvider; + + _.assert( o.dst.system.hasProvider( o.dst.effectiveProvider ), 'System should have destination and source file providers' ); + _.assert( o.src.system.hasProvider( o.src.effectiveProvider ), 'System should have destination and source file providers' ); + _.assert( o.dst.system === o.src.system, 'System should have the same destination and source system' ); + _.assert( o.dst.effectiveProvider === dstRecordFactory.effectiveProvider ); + _.assert( o.dst.defaultProvider === dstRecordFactory.defaultProvider ); + _.assert( o.dst.system === dstRecordFactory.system || o.dst.system === null ); + _.assert( !!o.dst.effectiveProvider ); + _.assert( !!o.dst.defaultProvider ); + _.assert( !!o.src.effectiveProvider ); + _.assert( !!o.src.defaultProvider ); + _.assert( o.dst.effectiveProvider instanceof _.FileProvider.Abstract ); + _.assert( o.src.effectiveProvider instanceof _.FileProvider.Abstract ); + _.assert( dst.path.isAbsolute( dstPath ) ); + _.assert( o.src.isPaired( o.dst ) ); + _.assert( src.path.s.allAreNormalized( o.src.filePath ) ); + _.assert( dst.path.isNormalized( dstPath ) ); + _.assert( _.boolLike( o.mandatory ) ); + + /* find */ + + let found = self.filesFind( srcOptions ); + o.visitedMap = srcOptions.visitedMap; + + return o.result; + + /* src options */ + + function srcOptionsForm() + { + + if( !o.src.formed || o.src.formed < 5 ) + { + o.src.system = o.src.system || self; + o.src.form(); + } + + _.assert( o.srcPath === undefined ); + _.assert( o.dstPath === undefined ); + + let srcOptions = _.mapOnly_( null, o, self.filesFind.defaults ); + srcOptions.withStem = 1; + srcOptions.withTransient = 1; + srcOptions.withDefunct = 1; + srcOptions.allowingMissed = 1; + srcOptions.allowingCycled = 1; + srcOptions.verbosity = 0; + srcOptions.maskPreset = 0; + srcOptions.filter = o.src; + srcOptions.result = null; + srcOptions.onUp = [ handleSrcUp ]; + srcOptions.onDown = [ handleSrcDown ]; + + return srcOptions; + } + + /* dst options */ + + function dstOptionsForm() + { + + if( o.dst.formed < 5 ) + { + o.dst.system = o.dst.system || self; + o.dst.recursive = 2; + o.dst.form(); + } + + _.assert( o.dst.basePath === null || _.object.isBasic( o.dst.basePath ) ); + _.assert( _.object.isBasic( o.dst.formedBasePath ) ); + _.assert( !!o.dst.effectiveProvider ); + _.assert( !!o.dst.defaultProvider ); + + let dstOptions = _.props.extend( null, srcOptions ); + dstOptions.filter = o.dst; + dstOptions.filePath = o.dst.filePathSimplest( o.dst.filePathNormalizedGet() ); + dstOptions.withStem = 1; + dstOptions.revisiting = 3; + dstOptions.resolvingSoftLink = 0; + dstOptions.resolvingTextLink = 0; + dstOptions.maskPreset = 0; + dstOptions.verbosity = 0; + dstOptions.result = null; + dstOptions.onUp = []; + dstOptions.onDown = [ handleDstDown ]; + + _.assert( _.strIs( dstOptions.filePath ) ); + + return dstOptions; + } + + /* dst factory */ + + function dstFactoryForm() + { + + _.assert( _.strIs( dstPath ) ); + let dstOp = + { + basePath : o.dst.formedBasePath[ dstPath ] ? o.dst.formedBasePath[ dstPath ] : dstPath, + stemPath : dstPath, + filter : o.dst, + allowingMissed : 1, + allowingCycled : 1, + } + + if( _.arrayIs( dstOp.stemPath ) && dstOp.stemPath.length === 1 ) + dstOp.stemPath = dstOp.stemPath[ 0 ]; + + _.assert( !!dstOp.basePath, () => 'No base path for ' + _.strQuote( dstPath ) ); + let dstRecordFactory = _.files.FileRecordFactory.TolerantFrom( o, dstOp ).form(); + + _.assert( _.strIs( dstOp.basePath ) ); + _.assert + ( + dstRecordFactory.basePath === _.uri.parse( dstPath ).longPath + || dstRecordFactory.basePath === _.uri.parse( o.dst.formedBasePath[ dstPath ] ).longPath + ); + + return dstRecordFactory; + } + + /* add record to result array */ + + function recordAdd_functor( o ) + { + let routine; + + routine = function add( record ) + { + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( record.include === true ); + o.result.push( record ); + } + + return routine; + } + + /* remove record from result array */ + + function recordRemove_functor( o ) + { + let routine; + + routine = function remove( record ) + { + _.assert( arguments.length === 1, 'Expects single argument' ); + _.arrayRemoveElementOnceStrictly( o.result, record ); + } + + return routine; + } + + /* */ + + function recordMake( dstRecord, srcRecord, effectiveRecord ) + { + _.assert( dstRecord === effectiveRecord || srcRecord === effectiveRecord ); + let record = Object.create( null ); + record.dst = dstRecord; + record.src = srcRecord; + record.effective = effectiveRecord; + record.goingUp = true; + record.upToDate = false; + record.srcAction = null; + record.srcAllow = true; + record.reason = null; + record.action = null; + record.allow = true; + record.preserve = false; + record.deleteFirst = false; + record.touch = false; + record.include = true; + + dstRecord.associated = record; + srcRecord.associated = record; + + return record; + } + + /* */ + + function handleUp( record, op ) + { + + if( touchMap[ record.dst.absolute ] ) + touch( record, touchMap[ record.dst.absolute ] ); + _.assert( touchMap[ record.dst.absolute ] === record.touch || !record.touch ); + + _.sure( !_.strBegins( record.dst.absolute, '/../' ), () => 'Destination path ' + _.strQuote( record.dst.absolute ) + ' leads out of file system.' ); + + if( !record.src.isActual && !record.dst.isActual ) + { + if( !record.src.isDir && !record.dst.isDir ) + return end( false ); + } + + if( !o.includingDst && record.reason === 'dstDeleting' ) + return end( record ); + + if( !o.withDirs && record.effective.isDir ) + return end( record ); + + if( !o.withTerminals && !record.effective.isDir ) + return end( record ); + + _.assert( _.routineIs( o.onUp ) || o.onUp === null ); + _.assert( arguments.length === 2 ); + + let result = true; + if( o.onUp ) + { + let r = o.onUp.call( self, record, o ); + if( r === _.dont ) + return end( false ); + } + + handleUp2.call( self, record, o ); + + return end( record ); + + function end( result ) + { + if( result && record.include && ( o.includingNonAllowed || record.allow ) ) + { + recordAdd( record ); + } + else + { + record.include = false; + } + return result; + } + + } + + /* */ + + function handleUp2( record, op ) + { + + // if( _.strEnds( record.dst.absolute, debugPath ) ) + // debugger; + + let a = actionMap[ record.dst.absolute ]; + let t = touchMap[ record.dst.absolute ]; + + if( !o.writing ) + record.allow = false; + + if( record.reason !== 'srcLooking' && a ) + { + record.include = false; + return record + } + + // if( _.strEnds( record.dst.absolute, debugPath ) ) + // debugger; + + _.assert( arguments.length === 2 ); + + if( !record.src.stat ) + { + /* src does not exist or is not actual */ + + // if( 0 ) + // if( o.mandatory ) + // if( record.src.isStem ) + // throw _.err + // ( + // `Stem file does not exist: ${_.strQuote( record.src.absolute )}` + + // `\nTo fix it you may set option mandatory to false or exclude the file from filePath of source filter` + // ); + + if( record.reason === 'dstDeleting' && !record.dst.isActual ) + { + } + else if( record.reason === 'srcLooking' && record.dst.isActual && record.dst.isDir && !record.src.isActual && record.src.stat ) + { + record.include = false; + } + else if( ( !record.dst.stat && !record.src.isDir ) || ( record.dst.isTerminal && !record.dst.isActual ) ) + { + record.include = false; + } + + } + else if( record.src.isDir ) + { + + if( !record.dst.stat ) + { + /* src is dir, dst does not exist */ + + } + else if( record.dst.isDir ) + { + /* both src and dst are dir */ + + if( record.reason === 'srcLooking' && record.dst.isActual && !record.src.isActual && !record.src.isTransient ) + { + debugger; + record.include = false; + dstDelete( record, op ); + } + + } + else + { + /* src is dir, dst is terminal */ + + if( !record.dst.isActual ) + record.include = false; + + if( !record.src.isActual && record.dst.isActual ) + { + } + else if( !record.dst.isActual ) + { + record.goingUp = false; + ignore( record ); + } + else if( !o.dstRewriting || !o.dstRewritingByDistinct ) + { + record.goingUp = false; + record.allow = false; + dirMake( record ); + preserve( record ); + forbid( record ); + } + else + { + record.deleteFirst = true; + dirMake( record ); + } + + } + + } + else + { + + if( !record.dst.stat ) + { + /* src is terminal, dst does not exist */ + + /* checks if terminals with equal dst path are same before link */ + if( record.src.isTerminal ) + if( o.writing && o.dstRewriting && o.dstRewritingOnlyPreserving && a ) + checkSrcTerminalsSameDst( record, op ); + + link( record ); + + } + else if( record.dst.isDir ) + { + /* src is terminal, dst is dir */ + + if( !record.src.isActual && record.reason !== 'dstDeleting' ) + { + record.include = false; + } + else if( record.src.isActual ) + { + record.deleteFirst = true; + } + + } + else + { + /* both src and dst are terminals */ + + if( record.src.isActual ) + { + + if( shouldPreserve( record ) ) + record.preserve = true; + + if( !o.writing ) + record.allow = false; + + if( !o.dstRewriting ) + { + forbid( record ); + } + + link( record ); + + } + else + { + + if( record.reason !== 'srcLooking' && o.dstDeleting ) + fileDelete( record ); + else + record.include = false; + + } + + } + + } + + return record; + } + + /* */ + + function handleDown( record, op ) + { + + // if( _.strEnds( record.dst.absolute, debugPath ) ) + // debugger; + + if( touchMap[ record.dst.absolute ] ) + touch( record, touchMap[ record.dst.absolute ] ); + _.assert( touchMap[ record.dst.absolute ] === record.touch || !record.touch ); + + let srcExists = !!record.src.stat; + let dstExists = !!record.dst.stat; + + _.assert( !!record.dst && !!record.src ); + _.assert( arguments.length === 2 ); + + if( !record.include ) + return end( false ); + + if( !record.src.isActual && !record.src.isDir && record.reason === 'srcLooking' ) + return end( false ); + + if( !o.includingDst && record.reason === 'dstDeleting' ) + return end( record ); + + if( !o.withDirs && record.effective.isDir ) + return end( record ); + + if( !o.withTerminals && !record.effective.isDir ) + return end( record ); + + handleDown2.call( self, record, o ); + if( o.onDown ) + { + let r = o.onDown.call( self, record, o ); + _.assert + ( + r === undefined, + () => 'Callback onDown should return nothing( undefined ), but returned ' + _.entity.exportStringDiagnosticShallow( r ) + ); + } + + _.assert( record.action !== 'exclude' || record.touch === false, () => 'Attempt to exclude touched ' + record.dst.absolute ); + + if( record.action === 'exclude' ) + return end( false ); + + _.assert( touchMap[ record.dst.absolute ] === record.touch || !record.touch ); + + if( !srcExists && record.reason === 'srcLooking' ) + return end( false ); + + if( !record.src.isActual && !record.dst.isActual && !record.touch ) + return end( false ); + + if( !o.includingNonAllowed && !record.allow ) + return end( false ); + + return end( record.touch ); + + function end( result ) + { + if( result === false ) + { + if( record.include ) + recordRemove( record ); + record.include = false; + } + return result; + } + } + + /* */ + + function handleDown2( record, op ) + { + + // if( _.strEnds( record.dst.absolute, debugPath ) ) + // debugger; + + _.assert( arguments.length === 2 ); + _.assert( !!record.touch === !!touchMap[ record.dst.absolute ] ); + + if( record.reason === 'srcLooking' ) + { + if( !record.src.isActual || !record.src.stat ) + if( !record.touch || actionMap[ record.dst.absolute ] ) + { + if( !record.touch ) + { + action( record, 'exclude' ); + } + else if( actionMap[ record.dst.absolute ] === 'dirMake' ) + { + dirMake( record ); + preserve( record ); + } + _.assert( !!record.action, () => 'Not clear what action to apply to ' + record.src.absolute ); + return; + } + } + + if( !record.src.stat ) + { + /* src does not exist */ + + if( record.reason === 'dstRewriting' ) + { + /* if dst rewriting and src is included */ + if( !o.dstRewriting && record.src.isActual ) + { + forbid( record ); + } + } + else if( record.reason === 'dstDeleting' ) + { + /* if dst deleting or src is not included then treat as src does not exist */ + if( !o.dstDeleting ) + { + forbid( record ); + } + } + else if( !record.src.isActual ) + { + /* if dst deleting or src is not included then treat as src does not exist */ + if( !o.dstDeleting ) + { + debugger; + forbid( record ); + } + } + + _.assert( !record.action ); + _.assert( !record.srcAction ); + _.assert( !!record.reason ); + + if( record.reason === 'dstDeleting' && !record.dst.isActual && !record.touch ) + { + ignore( record ); + } + else if( record.reason !== 'dstDeleting' && ( !record.dst.isActual || !record.dst.stat ) && !record.touch ) + { + debugger; + forbid( record ); + action( record, 'exclude' ); + } + else + { + dirDeleteOrPreserve( record, 'ignore' ); + } + + } + else if( record.src.isDir ) + { + + if( !record.dst.stat ) + { + /* src is dir, dst does not exist */ + + if( !record.src.isActual ) + { + if( record.touch === 'constructive' ) + dirMake( record ); + else + action( record, 'exclude' ); + } + else + { + dirMake( record ); + } + + } + else if( record.dst.isDir ) + { + /* both src and dst are dir */ + + if( !record.src.isActual ) + { + + if( record.reason === 'srcLooking' && record.dst.isStem ) + { + dirMake( record ); + preserve( record ); + } + else + { + dirDeleteOrPreserve( record ); + } + + } + else + { + dirMake( record ); + } + + } + else + { + /* src is dir, dst is terminal */ + + if( o.dstRewritingOnlyPreserving ) + if( o.writing && o.dstRewriting && o.dstRewritingByDistinct ) + { + debugger; + throw _.err( 'Can\'t rewrite terminal file ' + record.dst.absolute + ' by directory ' + record.src.absolute + ', dstRewritingOnlyPreserving is enabled' ); + } + + if( !record.src.isActual && record.dst.isActual ) + if( record.touch === 'constructive' ) + { + record.deleteFirst = true; + dirMake( record ); + } + else + { + fileDelete( record ); + } + + _.assert( !record.src.isActual || !!record.touch ); + + } + + } + else + { + + if( !record.dst.stat ) + { + /* src is terminal file and dst does not exists */ + _.assert( record.action === o.linkingAction || _.strHas( o.linkingAction, 'Maybe' ) ); + } + else if( record.dst.isDir ) + { + /* src is terminal, dst is dir */ + + if( !o.writing || !o.dstRewriting || !o.dstRewritingByDistinct ) + { + forbid( record ); + } + else if( o.dstRewritingOnlyPreserving ) + { + if( record.dst.factory.effectiveProvider.filesHasTerminal( record.dst.absolute ) ) + { + debugger; + throw _.err( 'Can\'t rewrite directory ' + _.strQuote( record.dst.absolute ) + ' by terminal ' + _.strQuote( record.src.absolute ) + ', directory has terminal(s)' ); + } + } + + if( record.touch === 'constructive' ) + { + record.preserve = true; + dirMake( record ); + } + else + { + if( record.src.isActual ) + { + record.deleteFirst = true; + link( record ); + } + else + { + _.assert( record.deleteFirst === false ); + if( !o.dstDeleting ) + { + forbid( record ); + } + if( !record.dst.isActual && record.touch !== 'destructive' ) + { + debugger; + forbid( record ); + } + + dirDeleteOrPreserve( record ); + } + } + + } + else + { + /* both src and dst are terminals */ + + if( o.writing && o.dstRewriting && o.dstRewritingOnlyPreserving ) + if( !self.filesCanBeSame( record.src, record.dst, true ) ) + if( record.src.stat.size !== 0 || record.dst.stat.size !== 0 ) + { + debugger; + let same = self.filesCanBeSame( record.src, record.dst, true ); + throw _.err + ( + 'Can\'t rewrite terminal file ' + _.strQuote( record.dst.absolute ) + '\n' + + 'by terminal file ' + _.strQuote( record.src.absolute ) + '\n' + + 'files have different content' + ); + } + } + + } + + _.assert( !!record.reason ); + _.assert( !record.srcAction ); + _.assert( _.strIs( record.action ), () => 'Action for record ' + _.strQuote( record.src.relative ) + ' was not defined' ); + + srcDeleteMaybe( record ); + + return record; + } + + /* */ + + function handleDstUp( /* srcContext, reason, dst, dstRecord, op */ ) + { + let srcContext = arguments[ 0 ]; + let reason = arguments[ 1 ]; + let dst = arguments[ 2 ]; + let dstRecord = arguments[ 3 ]; + let op = arguments[ 4 ]; + + if( !dstRecord.included ) + return dstRecord; + + _.assert( arguments.length === 5 ); + _.assert( _.strIs( reason ) ); + let srcRecord = srcContext.record( dstRecord.relative ); + let record = recordMake( dstRecord, srcRecord, dstRecord ); + record.reason = reason; + + if( handleUp( record, op ) === false ) + record.include = false; + + return dstRecord; + } + + /* */ + + function handleDstDown( dstRecord, op ) + { + let record = dstRecord.associated; + + if( !dstRecord.included ) + return; + + handleDown( record, op ); + } + + /* */ + + function handleSrcUp( srcRecord, op ) + { + + if( !srcRecord.included ) + return srcRecord; + + let relative = srcRecord.relative; + if( o.onDstName ) + relative = o.onDstName.call( self, relative, dstRecordFactory, op, o, srcRecord ); + + let dstRecord = dstRecordFactory.record( relative ); + let record = recordMake( dstRecord, srcRecord, srcRecord ); + record.reason = 'srcLooking'; + + // let isSoftLink = record.dst.isSoftLink; + // + // if( o.filesGraph ) + // { + // if( record.dst.absolute === dstPath ) + // { + // debugger; + // o.filesGraph.dst.filePath = o.dst.filePath; + // o.filesGraph.src.filePath = o.src.filePath; + // o.filesGraph.actionBegin( o.dst.filePath + ' <- ' + o.src.filePath ); + // } + // if( !record.src.isDir ) + // { + // o.filesGraph.filesUpdate( record.dst ); + // o.filesGraph.filesUpdate( record.src ); + // if( o.filesGraph.fileIsUpToDate( record.dst ) ) + // record.upToDate = true; + // } + // } + + /* */ + + handleUp( record, op ); + + // if( _.strEnds( record.dst.absolute, debugPath ) ) + // debugger; + + if( record.include && record.src.isActual && record.src.stat ) + if( record.dst.isDir && !record.src.isDir ) + { + /* src is terminal, dst is dir */ + + _.assert( _.strIs( record.dst.factory.basePath ) ); + let filter2 = self.recordFilter + ({ + effectiveProvider : dstOptions.filter.effectiveProvider, + system : dstOptions.filter.system, + recursive : 2, + }); + filter2.filePath = null; + filter2.basePath = record.dst.factory.basePath; + + let dstOptions2 = _.props.extend( null, dstOptions ); + dstOptions2.filePath = record.dst.absolute; + dstOptions2.filter = filter2; + dstOptions2.filter.filePath = null; + dstOptions2.withStem = 0; + dstOptions2.mandatory = 0; + dstOptions2.withDefunct = 0; + dstOptions2.onUp = [ _.routineJoin( undefined, handleDstUp, [ srcRecord.factory, 'dstRewriting', filter2 ] ) ]; + + let found = self.filesFind( dstOptions2 ); + + } + + /* */ + + if( record.include && record.goingUp ) + return srcRecord; + else + return _.dont; + } + + /* */ + + function handleSrcDown( srcRecord, op ) + { + let record = srcRecord.associated; + + if( !srcRecord.included ) + return; + + // if( o.filesGraph && !record.src.isDir && !record.upToDate ) + // { + // record.dst.reset(); + // o.filesGraph.dependencyAdd( record.dst, record.src ); + // } + + dstDelete( record, op ); + handleDown( record, op ); + + // if( o.filesGraph ) + // { + // if( record.dst.absolute === dstPath ) + // o.filesGraph.actionEnd(); + // } + + } + + function dstDelete( record, op ) + { + + _.assert( !!record ); + if( !o.includingDst ) + return; + if( !record.dst.isDir || !record.src.isDir ) + return; + + _.assert( _.strIs( record.dst.factory.basePath ) ); + _.assert( _.strIs( record.src.factory.basePath ) ); + + let dstFiles = record.dst.factory.effectiveProvider.dirRead({ filePath : record.dst.absolute, outputFormat : 'absolute' }); + let dstRecords = record.dst.factory.records( dstFiles ); + let srcFiles = record.src.factory.effectiveProvider.dirRead({ filePath : record.src.absolute, outputFormat : 'absolute' }); + let srcRecords = record.src.factory.records( srcFiles ); + + for( let f = dstRecords.length-1 ; f >= 0 ; f-- ) + { + let dstRecord = dstRecords[ f ]; + let srcRecord = _.longLeft( srcRecords, dstRecord, ( r ) => r.relative ).element; + if( !srcRecord ) + continue; + if( !srcRecord.isActual ) + continue; + dstRecords.splice( f, 1 ); + } + + // if( _.strEnds( record.dst.absolute, debugPath ) ) + // debugger; + + for( let f = 0 ; f < dstRecords.length ; f++ ) + { + let dstRecord = dstRecords[ f ]; + + if( dstDeleteMap[ dstRecord.absolute ] ) + continue; + + dstDeleteTouch( dstRecord ); + + let dstOptions2 = _.props.extend( null, dstOptions ); + dstOptions2.filePath = dst.path.join( record.dst.factory.basePath, dstRecord.absolute ); + dstOptions2.filter = dstOptions2.filter.clone(); + dstOptions2.filter.filePath = null; + dstOptions2.filter.filePath = null; + dstOptions2.filter.basePath = record.dst.factory.basePath; + dstOptions2.filter.recursive = 2; + dstOptions2.mandatory = 0; + dstOptions2.withDefunct = 0; + dstOptions2.onUp = [ _.routineJoin( null, handleDstUp, [ record.src.factory, 'dstDeleting', null ] ) ]; + + let found = self.filesFind( dstOptions2 ); + + } + + } + + /* */ + + function dstDeleteTouch( record ) + { + + _.assert( _.strIs( dstPath ) ); + _.assert( _.strIs( record.absolute ) ); + _.assert( arguments.length === 1 ); + + let absolutePath = record.absolute; + dstDeleteMap[ absolutePath ] = 1; + + do + { + absolutePath = dst.path.detrail( dst.path.dir( absolutePath ) ); + dstDeleteMap[ absolutePath ] = 1; + } + while( absolutePath !== dstPath && absolutePath !== '/' ); + + } + + /* touch */ + + function action( record, action ) + { + + // if( _.strEnds( record.dst.absolute, debugPath ) ) + // debugger; + // if( _.strHas( record.dst.absolute, 'clean-special/out' ) ) + // debugger; + + _.assert( arguments.length === 2 ); + // _.assert( _.longHas( [ 'exclude', 'ignore', 'fileDelete', 'dirMake', 'fileCopy', 'softLink', 'hardLink', 'textLink', 'nop' ], action ), () => 'Unknown action ' + _.strQuote( action ) ); + _.assert( self.ReflecEvalAction[ action ] !== undefined, () => 'Unknown action ' + _.strQuote( action ) ); + + let absolutePath = record.dst.absolute; + let result = actionMap[ absolutePath ] === action; + + _.assert( record.action === null ); + record.action = action; + + if( action === 'exclude' || action === 'ignore' ) + { + _.assert( actionMap[ absolutePath ] === undefined ); + return result; + } + + actionMap[ absolutePath ] = action; + + return result + } + + /* touch */ + + function touch( record, kind ) + { + + // if( _.strEnds( record.dst.absolute, debugPath ) ) + // debugger; + + kind = kind || 'constructive'; + + _.assert( _.strIs( dstPath ) ); + _.assert( arguments.length === 2 ); + _.assert( _.longHas( [ 'src', 'constructive', 'destructive' ], kind ) ); + + let absolutePath = record.dst.absolute; + kind = touchAct( absolutePath, kind ); + + record.touch = kind; + + while( absolutePath !== dstPath && absolutePath !== '/' ) + { + absolutePath = dst.path.detrail( dst.path.dir( absolutePath ) ); + touchAct( absolutePath, kind ); + } + + if( kind === 'destructive' ) + { + for( let m in touchMap ) + if( _.strBegins( m, absolutePath ) ) + touchMap[ m ] = 'destructive'; + } + + } + + /* touchAct */ + + function touchAct( absolutePath, kind ) + { + + if( kind === 'src' && touchMap[ absolutePath ] ) + return touchMap[ absolutePath ]; + + if( kind === 'destructive' && touchMap[ absolutePath ] === 'constructive' ) + return touchMap[ absolutePath ]; + + touchMap[ absolutePath ] = kind; + + return kind; + } + + /* */ + + function dirHaveFiles( record ) + { + if( !record.dst.isDir ) + return false; + if( touchMap[ record.dst.absolute ] === 'constructive' ) + return true; + let files = record.dst.factory.effectiveProvider.dirRead({ filePath : record.dst.absolute, outputFormat : 'absolute' }); + files = files.filter( ( file ) => actionMap[ file ] !== 'fileDelete' ); + return !!files.length; + } + + /* */ + + function shouldPreserve( record ) + { + + if( !o.preservingSame ) + return false; + + if( record.upToDate ) + return true; + + if( o.linkingAction === 'fileCopy' ) /* xxx : qqq : investigate */ + { + if( self.filesCanBeSame( record.dst, record.src, true ) ) + return true; + } + + return false; + } + + /* */ + + function dirDeleteOrPreserve( record, preserveAction ) + { + _.assert( !record.action ); + if( !preserveAction ) + preserveAction = 'dirMake'; + + if( dirHaveFiles( record ) ) + { + /* preserve dir if it has filtered out files */ + if( preserveAction === 'dirMake' ) + { + dirMake( record ); + _.assert( record.preserve === true ); + } + else + ignore( record ); + } + else + { + if( !o.writing ) + record.allow = false; + + if( !o.dstDeletingCleanedDirs ) + if( record.dst.isDir && !record.dst.isActual ) + return ignore( record ); + + fileDelete( record ); + } + + return record; + } + + /* */ + + function preserve( record ) + { + _.assert( _.strIs( record.action ) ); + record.preserve = true; + touch( record, 'constructive' ); + return record; + } + + /* */ + + function link( record ) + { + _.assert( !record.action ); + _.assert( !record.upToDate ); + + if( !record.src.isActual ) + { + record.include = false; + return; + } + + let linkingAction = o.linkingAction; + if( _.strHas( linkingAction, 'Maybe' ) ) + { + if( src === dst ) + linkingAction = _.strRemoveEnd( linkingAction, 'Maybe' ); + else + linkingAction = 'fileCopy'; + } + + action( record, linkingAction ); + touch( record, 'constructive' ); + + return record; + } + + /* */ + + function dirMake( record ) + { + _.assert( !record.action ); + + if( record.dst.isDir || actionMap[ record.dst.absolute ] === 'dirMake' ) + record.preserve = true; + + action( record, 'dirMake' ); + touch( record, 'constructive' ); + + return record; + } + + /* */ + + function ignore( record ) + { + _.assert( !record.action ); + touch( record, 'constructive' ); + action( record, 'ignore' ); + record.preserve = true; + record.allow = false; + return record; + } + + /* */ + + function forbid( record ) + { + delete actionMap[ record.dst.absolute ]; + /* no need to delete it from touchMap */ + record.allow = false; + return record; + } + + /* */ + + function fileDelete( record ) + { + _.assert( !record.action ); + + action( record, 'fileDelete' ); + touch( record, 'destructive' ); + + if( record.reason === 'dstDeleting' && !o.dstDeleting ) + { + forbid( record ); + } + + } + + /* */ + + function srcDeleteMaybe( record ) + { + + if( !o.srcDeleting ) + return false; + if( !record.src.isActual ) + return false; + if( !record.allow ) + return false; + if( !record.include ) + return false; + + srcDelete( record ); + } + + /* delete src */ + + function srcDelete( record ) + { + + /* record.dst.isActual could be false */ + + _.assert( !!record.src.isActual ); + _.assert( !!record.include ); + _.assert( !!record.allow ); + _.assert( !!record.action ); + _.assert( !!o.srcDeleting ); + + // if( _.strEnds( record.dst.absolute, debugPath ) ) + // debugger; + + if( record.allow ) + if( !record.src.stat ) + { + } + else if( record.src.isDir ) + { + _.assert( record.action === 'dirMake' || record.action === 'fileDelete' ); + record.srcAction = 'fileDelete'; + record.srcAllow = !!o.writing; + touch( record, 'src' ) + } + else + { + record.srcAction = 'fileDelete'; + record.srcAllow = !!o.writing; + touch( record, 'src' ) + } + + } + + /* */ + + function checkSrcTerminalsSameDst( record, op ) + { + for( let i = op.result.length - 1; i >= 0; i-- ) + { + let result = op.result[ i ]; + if( result.dst.absolute === record.dst.absolute ) + { + if( result.src.isTerminal ) + { + if( !self.filesCanBeSame( result.src, record.src, true ) ) + if( result.src.stat.size !== 0 || record.src.stat.size !== 0 ) + { + debugger + throw _.err + ( + 'Cant\'t rewrite destination file by source file, because they have different content and option::dstRewritingOnlyPreserving is true\n' + + `\ndst: ${result.dst.absolute}` + + `\nsrc: ${result.src.absolute}` + ); + // throw _.err + // ( + // 'Source terminal files: \n' + _.strQuote( result.src.absolute ) + ' and ' + _.strQuote( record.src.absolute ) + '\n' + + // 'have same destination path: ' + _.strQuote( record.dst.absolute ) +', but different content.' + '\n' + + // 'Can\'t perform rewrite operation when option dstRewritingOnlyPreserving is enabled.' + // ); + } + } + break; + } + } + } +} + +let filesReflectPrimeDefaults = Object.create( null ); +var defaults = filesReflectPrimeDefaults; + +defaults.result = null; +defaults.visitedMap = null; +defaults.extra = null; +defaults.linkingAction = 'fileCopy'; +// defaults.xxx = 'both'; + +defaults.verbosity = 0; +defaults.mandatory = 1; +defaults.allowingMissed = 0; +defaults.allowingCycled = 0; +defaults.withTerminals = 1; +defaults.withDirs = 1; +defaults.includingNonAllowed = 1; +defaults.includingDst = null; +defaults.revisiting = null; +defaults.resolvingSoftLink = 0; +defaults.resolvingTextLink = 0; + +defaults.writing = 1; +defaults.srcDeleting = 0; +defaults.dstDeleting = 0; +defaults.dstDeletingCleanedDirs = 1; +defaults.dstRewriting = 1; +defaults.dstRewritingByDistinct = 1; +defaults.dstRewritingOnlyPreserving = 0; /* qqq2 xxx : rename to dstRewritingAllowingDiscrepancy and invert */ +defaults.preservingTime = 0; +defaults.preservingSame = 0; + +defaults.onUp = null; +defaults.onDown = null; +defaults.onDstName = null; + +var defaults = filesReflectEvaluate_body.defaults = Object.create( filesReflectPrimeDefaults ); /* xxx : xxx : remove all inheriting of defaults */ +// defaults.filesGraph = null; +defaults.src = null; +defaults.dst = null; + +var having = filesReflectEvaluate_body.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 0; + +let filesReflectEvaluate = _.routine.uniteCloning_replaceByUnite( filesReflectEvaluate_head, filesReflectEvaluate_body ); +filesReflectEvaluate.having.aspect = 'entry'; + +// + +function filesReflectSingle_head( routine, args ) +{ + let self = this; + let o = self._filesReflectPrepare( routine, args ); + + if( o.rebasingLink === false ) + o.rebasingLink = 0 + else if( o.rebasingLink === true ) + o.rebasingLink = 2; + + _.assert( _.longHas( [ 0, 1, 2 ], o.rebasingLink ) ); + _.assert( _.boolLike( o.throwing ) ); + + if( o.onWriteDstUp ) + o.onWriteDstUp = _.routinesCompose( o.onWriteDstUp ); + if( o.onWriteDstDown ) + o.onWriteDstDown = _.routinesCompose( o.onWriteDstDown ); + if( o.onWriteSrcUp ) + o.onWriteSrcUp = _.routinesCompose( o.onWriteSrcUp ); + if( o.onWriteSrcDown ) + o.onWriteSrcDown = _.routinesCompose( o.onWriteSrcDown ); + + return o; +} + +// + +function filesReflectSingle_body( o ) +{ + let self = this; + let path = self.path; + let srcToDstHash = null; + + _.routine.assertOptions( filesReflectSingle_body, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.boolLike( o.mandatory ) ); + _.assert( o.filter === undefined ); + _.assert( o.src.dst === o.dst ); + _.assert( o.dst.src === o.src ); + // _.assert( o.outputFormat === undefined ); + _.assert( _.boolLike( o.allowingMissed ) ); + + if( o.rebasingLink && o.visitedMap === null ) + { + o.visitedMap = Object.create( null ); + } + + let o2 = _.mapOnly_( null, o, self.filesReflectEvaluate.body.defaults ); + o2.result = []; + _.assert( _.arrayIs( o2.result ) ); + self.filesReflectEvaluate.body.call( self, o2 ); + _.assert( o2.result !== o.result ); + _.arrayAppendArray( o.result, o2.result ); + + let dirsMap = Object.create( null ); + let system = self.system || self; + let src = o.src.effectiveProvider; + let dst = o.dst.effectiveProvider; + + /* */ + + if( o.writing ) + forEach( writeDstUp1, writeDstDown1 ); + + if( o.writing ) + forEach( writeDstUp2, writeDstDown2 ); + + if( o.writing && o.srcDeleting ) + if( o.writing ) /* xxx : use this */ + forEach( writeSrcUp, writeSrcDown ); + + /* */ + + return end(); + + /* - */ + + function end() + { + + if( o.mandatory ) + if( !o2.result.length ) + { + _.assert( o.src.isPaired() ); + let mtr = o.src.moveTextualReport(); + debugger; + throw _.err( 'Error. No file moved :', mtr ); + } + + return o.result; + } + + /* */ + + function srcToDst( srcRecord ) + { + if( !srcToDstHash ) + { + srcToDstHash = new HashMap(); + for( let r = 0 ; r < o.result.length ; r++ ) + srcToDstHash.set( o.result[ r ].src, o.result[ r ].dst ); + } + return srcToDstHash.get( srcRecord ); + } + + /* */ + + function forEach( up, down ) + { + let filesStack = []; + + for( let r = 0 ; r < o.result.length ; r++ ) + { + let record = o.result[ r ]; + + while( filesStack.length && !_.strBegins( record.dst.absolute, filesStack[ filesStack.length-1 ].dst.absolute ) ) + down( filesStack.pop() ); + filesStack.push( record ); + + up( record ); + } + + while( filesStack.length ) + down( filesStack.pop() ); + + } + + /* */ + + function writeDstUp1( record ) + { + + if( o.onWriteDstUp ) + { + let onr = o.onWriteDstUp.call( self, record, o ); + _.assert( _.boolsAllAre( onr ) ); + onr = _.all( onr, ( e ) => e === _.dont ? false : e ); + _.assert( _.boolIs( onr ) ); + return onr; + } + + return true; + } + + /* */ + + function writeDstDown1( record ) + { + + if( record.deleteFirst ) + dstDelete( record ); + else if( record.action === 'fileDelete' ) + dstDelete( record ); + + } + + /* */ + + function writeDstUp2( record ) + { + + // let linkingAction = _.longHas( [ 'fileCopy', 'hardLink', 'softLink', 'textLink', 'nop' ], record.action ); + let linkingAction = !!self.ReflectMandatoryAction[ record.action ]; + if( linkingAction && record.allow && !path.isRoot( record.dst.absolute ) ) + { + + let dirPath = record.dst.dir; + if( !dirsMap[ dirPath ] ) + { + for( let d in dirsMap ) + if( _.strBegins( dirPath, d ) ) + { + dirsMap[ dirPath ] = true; + break; + } + if( !dirsMap[ dirPath ] ) + { + record.dst.factory.effectiveProvider.dirMake + ({ + recursive : 1, + rewritingTerminal : 0, + filePath : dirPath, + }); + dirsMap[ dirPath ] = true; + } + } + + } + + if( linkingAction ) + link( record ); + else if( record.action === 'fileDelete' ) + {} + else if( record.action === 'dirMake' ) + dstDirectoryMake( record ); + else if( record.action === 'ignore' ) + {} + else _.assert( 0, 'Not implemented action ' + record.action ); + + } + + /* */ + + function writeDstDown2( record ) + { + + if( o.onWriteDstDown ) + { + let onr = o.onWriteDstDown.call( self, record, o ); + _.assert( _.boolsAllAre( onr ) ); + onr = _.all( onr, ( e ) => e === _.dont ? false : e ); + _.assert( _.boolIs( onr ) ); + return onr; + } + + return true; + } + + /* */ + + function writeSrcUp( record ) + { + + if( o.onWriteSrcUp ) + { + let onr = o.onWriteSrcUp.call( self, record, o ); + _.assert( _.boolsAllAre( onr ) ); + onr = _.all( onr, ( e ) => e === _.dont ? false : e ); + _.assert( _.boolIs( onr ) ); + return onr + } + + /* */ + + return true; + // if( !onr ) + // return onr; + // return onr; + } + + /* */ + + function writeSrcDown( record ) + { + + srcDeleteMaybe( record ); + + if( o.onWriteSrcDown ) + { + let onr = o.onWriteSrcDown.call( self, record, o ); + _.assert( _.boolsAllAre( onr ) ); + onr = _.all( onr, ( e ) => e === _.dont ? false : e ); + _.assert( _.boolIs( onr ) ); + return onr; + } + + return true; + } + + /* */ + + function dstDirectoryMake( record ) + { + + if( !record.allow ) + return; + if( record.preserve ) + return; + + _.assert( !record.upToDate ); + _.assert( !!record.src.isActual || !!record.touch ); + _.assert( !!record.touch ); + _.assert( !!record.action ); + + let r = record.dst.factory.effectiveProvider.dirMake + ({ + recursive : 1, + rewritingTerminal : 0, + filePath : record.dst.absolute, + }); + record.performed = r; + + } + + /* */ + + function dstDelete( record ) + { + if( !record.allow ) + return; + if( record.dst.absolute === record.src.absolute ) + return; + + let r = record.dst.factory.effectiveProvider.fileDelete( record.dst.absolute ); + record.performed = r; + /* qqq : should be in v >= 3 log as : " - deleted ..." */ + + } + + /* */ + + function linkRebasing( record ) + { + + if( !o.rebasingLink ) + return false; + + let isSoftLink = record.src.isSoftLink; + let isTextLink = record.src.isTextLink; + + if( !isSoftLink && !isTextLink ) + if( ( o.resolvingSoftLink && self.usingSoftLink ) || ( o.resolvingTextLink && self.usingTextLink ) ) + { + debugger; + let stat = record.src.factory.effectiveProvider.statRead + ({ + filePath : record.src.absolute, + resolvingSoftLink : 0, + resolvingTextLink : 0, + }); + isSoftLink = stat.isSoftLink(); + isTextLink = stat.isTextLink(); + } + + if( isSoftLink && o.resolvingSrcSoftLink === 2 ) + return false; + + if( isTextLink && o.resolvingSrcTextLink === 2 ) + return false; + + if( !isSoftLink && !isTextLink ) + return false; + + let srcPath; + let srcAbsolute = record.src.real; + /* qqq : use ( resolvingMultiple / recursive ) option instead of if-else */ + + // debugger; + // if( _.strHas( srcAbsolute, 'terLink' ) ) + // debugger; + + let resolvingSrcSoftLink = self.usingSoftLink ? o.resolvingSrcSoftLink : 0; + let resolvingSrcTextLink = self.usingTextLink ? o.resolvingSrcTextLink : 0; + + if( o.rebasingLink === 2 ) + { + let resolved = src.pathResolveLinkFull + ({ + filePath : srcAbsolute, + resolvingSoftLink : 1, + resolvingTextLink : 1, + preservingRelative : 1, + relativeOriginalFile : 1, + throwing : o.throwing, + allowingMissed : o.allowingMissed, + allowingCycled : o.allowingCycled, + }); + if( !resolved ) + { + debugger; + return false; + } + srcAbsolute = resolved.absolutePath; + srcPath = resolved.filePath; + } + else if( o.rebasingLink === 1 ) + { + + if( resolvingSrcSoftLink || resolvingSrcTextLink ) + { + + let resolved = src.pathResolveLinkFull + ({ + filePath : srcAbsolute, + resolvingSoftLink : resolvingSrcSoftLink ? 1 : 0, + resolvingTextLink : resolvingSrcTextLink ? 1 : 0, + preservingRelative : 1, + relativeOriginalFile : 1, + throwing : o.throwing, + allowingMissed : o.allowingMissed, + allowingCycled : o.allowingCycled, + }); + if( !resolved ) + { + debugger; + return false; + } + srcAbsolute = resolved.absolutePath; + srcPath = resolved.filePath; + + } + + if( ( !resolvingSrcSoftLink && self.usingSoftLink ) || ( !resolvingSrcTextLink && self.usingTextLink ) ) + { + let resolved = src.pathResolveLinkStep + ({ + filePath : srcAbsolute, + resolvingSoftLink : 1, + resolvingTextLink : 1, + preservingRelative : 1, + relativeOriginalFile : 1, + throwing : o.throwing, + allowingMissed : o.allowingMissed, + allowingCycled : o.allowingCycled, + }); + + srcPath = resolved.filePath; + srcAbsolute = path.join( srcAbsolute, srcPath ); + } + + } + else _.assert( 0 ); + + if( !o.visitedMap[ srcAbsolute ] ) + debugger; + if( !o.visitedMap[ srcAbsolute ] ) + return false + + if( path.isAbsolute( srcPath ) ) + debugger; + + let srcRecord = o.visitedMap[ srcAbsolute ]; + let dstRecord = srcToDst( srcRecord ); + if( record.src === dstRecord ) + debugger; + if( record.src === dstRecord ) + return false; + + record.src = record.src.factory.record( srcAbsolute ); + + // if( path.isAbsolute( srcPath ) ) + // { + // debugger; + // path.join( dstRecord.absolute, path.relative( srcRecord.absolute, srcAbsolute ) ); + // } + + let action = isSoftLink ? 'softLink' : 'textLink'; + + if( action === 'softLink' ) + { + if( o.resolvingSrcSoftLink === 2 ) + linkWithAction( record, record.dst.absolutePreferred, srcPath, 'fileCopy' ); + else + linkWithAction( record, record.dst.absolutePreferred, srcPath, action, 1 ); + } + else if( action === 'textLink' ) + { + if( o.resolvingSrcTextLink === 2 ) + linkWithAction( record, record.dst.absolutePreferred, srcPath, 'fileCopy' ); + else + linkWithAction( record, record.dst.absolutePreferred, srcPath, action, 1 ); + } + + return true; + } + + /* */ + + function linkWithAction( /* record, dstPath, srcPath, action, allowingMissed */ ) + { + let record = arguments[ 0 ]; + let dstPath = arguments[ 1 ]; + let srcPath = arguments[ 2 ]; + let action = arguments[ 3 ]; + let allowingMissed = arguments[ 4 ]; + + let r; + + if( action === 'nop' ) + { + record.performed = 'nop'; + return false; + } + + if( action === 'fileCopy' ) + { + /* qqq : should return true / false / null. false if no change is done! */ + r = system.fileCopy + ({ + dstPath, + srcPath, + makingDirectory : 0, + allowingMissed : allowingMissed || o.allowingMissed, + allowingCycled : o.allowingCycled, + resolvingSrcSoftLink : o.resolvingSrcSoftLink, + resolvingSrcTextLink : o.resolvingSrcTextLink, + resolvingDstSoftLink : o.resolvingDstSoftLink, + resolvingDstTextLink : o.resolvingDstTextLink, + breakingDstHardLink : o.breakingDstHardLink, + }); + } + else if( action === 'hardLink' ) + { + /* qqq : should not change time of file if it is already linked. check tests */ + /* qqq : should return true / false / null. false if no change is done! */ + + r = dst.hardLink + ({ + dstPath, + srcPath, + makingDirectory : 0, + allowingMissed : allowingMissed || o.allowingMissed, + allowingCycled : o.allowingCycled, + resolvingSrcSoftLink : o.resolvingSrcSoftLink, + resolvingSrcTextLink : o.resolvingSrcTextLink, + resolvingDstSoftLink : o.resolvingDstSoftLink, + resolvingDstTextLink : o.resolvingDstTextLink, + breakingSrcHardLink : o.breakingSrcHardLink, + breakingDstHardLink : o.breakingDstHardLink, + }); + + } + else if( action === 'softLink' ) + { + /* qqq : should not change time of file if it is already linked. check tests */ + /* qqq : should return true / false / null. false if no change is done! */ + if( path.isRelative( srcPath ) ) + debugger; + r = system.softLink + ({ + dstPath, + srcPath, + makingDirectory : 0, + allowingMissed : allowingMissed || o.allowingMissed, + allowingCycled : o.allowingCycled, + resolvingSrcSoftLink : o.resolvingSrcSoftLink, + resolvingSrcTextLink : o.resolvingSrcTextLink, + resolvingDstSoftLink : o.resolvingDstSoftLink, + resolvingDstTextLink : o.resolvingDstTextLink, + }); + } + else if( action === 'textLink' ) + { + /* qqq : should not change time of file if it is already linked. check tests */ + /* qqq : should return true / false / null. false if no change is done! */ + r = system.textLink + ({ + dstPath, + srcPath, + makingDirectory : 0, + allowingMissed : allowingMissed || o.allowingMissed, + allowingCycled : o.allowingCycled, + resolvingSrcSoftLink : o.resolvingSrcSoftLink, + resolvingSrcTextLink : o.resolvingSrcTextLink, + resolvingDstSoftLink : o.resolvingDstSoftLink, + resolvingDstTextLink : o.resolvingDstTextLink, + }); + } + else _.assert( 0 ); + + if( _.consequenceIs( r ) ) + r.then( () => record.performed = r ); + else + record.performed = r; + + return true; + } + + /* */ + + function link( record ) + { + + _.assert( !record.upToDate ); + _.assert( !!record.src.isActual ); + _.assert( !!record.touch ); + _.assert( !!record.action ); + + if( !record.allow || record.preserve ) + return; + + if( record.action === 'nop' ) + { + record.performed = 'nop'; + return false; + } + + let action = record.action; + + if( linkRebasing( record ) ) + return true; + + return linkWithAction( record, record.dst.absolutePreferred, record.src.absolutePreferred, action ); + } + + /* */ + + function srcDeleteMaybe( record ) + { + if( !record.srcAllow || !record.srcAction ) + return false; + srcDelete( record ); + } + + /* delete src */ + + function srcDelete( record ) + { + + /* record.dst.isActual could be false */ + + _.assert( !!record.src.isActual ); + _.assert( !!record.include ); + _.assert( !!record.allow ); + _.assert( !!record.action ); + _.assert( !!o.srcDeleting ); + _.assert( record.srcAction === 'fileDelete' ); + + if( record.allow ) + if( !record.src.stat || !record.src.isActual ) + { + _.assert( 0, 'not tested' ); + } + else if( record.src.isDir ) + { + _.assert( record.action === 'dirMake' || record.action === 'fileDelete' ); + if( !record.src.factory.effectiveProvider.dirRead( record.src.absolute ).length ) + { + record.src.factory.effectiveProvider.fileDelete( record.src.absolute ); + } + else + { + record.srcAllow = false; + } + } + else + { + _.assert( record.action === 'fileCopy' || record.action === 'hardLink' || record.action === 'softLink' || record.action === 'textLink' || record.action === 'nop' ); + record.src.factory.effectiveProvider.fileDelete( record.src.absolute ); + } + + } + +} + +let filesReflectAdvancedDefaults = Object.create( null ); +var defaults = filesReflectAdvancedDefaults; + +defaults.onWriteDstUp = null; +defaults.onWriteDstDown = null; +defaults.onWriteSrcUp = null; +defaults.onWriteSrcDown = null; + +defaults.breakingSrcHardLink = null; +defaults.resolvingSrcSoftLink = null; +defaults.resolvingSrcTextLink = null; +defaults.breakingDstHardLink = null; +defaults.resolvingDstSoftLink = null; +defaults.resolvingDstTextLink = null; +defaults.rebasingLink = 0; +defaults.sync = null; +defaults.throwing = null; + +var defaults = filesReflectSingle_body.defaults = Object.create( filesReflectEvaluate.defaults ); +_.props.extend( defaults, filesReflectAdvancedDefaults ); +// defaults.outputFormat = 'record'; +defaults.outputFormat = 'nothing'; /* xxx : qqq : optimization, controls records creation in filesReflectSingle */ + +var having = filesReflectSingle_body.having = Object.create( null ); +having.writing = 0; +having.reading = 1; +having.driving = 0; + +let filesReflectSingle = _.routine.uniteCloning_replaceByUnite( filesReflectSingle_head, filesReflectSingle_body ); +filesReflectSingle.having.aspect = 'entry'; + +_.assert( filesReflectSingle.defaults.sync !== undefined ); + +// + +function filesReflect_head( routine, args ) +{ + let self = this; + let path = self.path; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 || args.length === 2 ); + + let o = args[ 0 ] + if( args.length === 2 ) + o = { reflectMap : { [ args[ 1 ] ] : args[ 0 ] } } + + self.filesReflectSingle.head.call( self, routine, args ); + + if( Config.debug ) + { + + let srcFilePath = o.src.filePathSimplest(); + let dstFilePath = o.dst.filePathSimplest(); + + _.assert( o.reflectMap === null || srcFilePath === null || srcFilePath === '' ); + _.assert( o.reflectMap === null || dstFilePath === null || dstFilePath === '' ); + _.assert( o.src.isPaired( o.dst ) ); + _.assert + ( + o.filter === null || o.filter.filePath === null || o.filter.filePath === undefined + || _.path.map.identical( o.filter.filePath, o.src.filePath ), + ); + + let knownFormats = [ 'src.absolute', 'src.relative', 'dst.absolute', 'dst.relative', 'record', 'nothing' ]; + _.assert + ( + _.longHas( knownFormats, o.outputFormat ), + () => 'Unknown output format ' + _.entity.exportStringDiagnosticShallow( o.outputFormat ) + + '\nKnown output formats : ' + _.entity.exportString( knownFormats ) + ); + + } + + if( o.reflectMap ) + { + if( Config.debug ) + if( !path.isEmpty( o.src.filePath ) ) + { + let filePath1 = path.mapExtend( null, o.src.filePath ); + let filePath2 = path.mapExtend( null, o.reflectMap ); + debugger; /* xxx */ + _.assert( _.path.map.identical( filePath1, filePath2 ) ); + } + o.src.filePath = o.reflectMap; + o.reflectMap = null; + } + + o.src.pairWithDst( o.dst ); + o.src.pairRefineLight(); + o.dst._formPaths(); + o.src._formPaths(); + + _.assert( _.mapIs( o.src.filePath ), 'Cant deduce source filter' ); + _.assert( _.mapIs( o.dst.filePath ), 'Cant deduce destination filter' ); + _.assert( o.src.filePath === o.dst.filePath ); + _.assert( o.reflectMap === null ); + _.assert( o.dstPath === undefined ); + _.assert( o.srcPath === undefined ); + _.assert( o.src.formed <= 3 ); + _.assert( o.dst.formed <= 3 ); + + return o; +} + +// + +/** + * @summary Reflects files from source to the destination using `o.reflectMap`. + * @description Reflect map contains key:value pairs. In signle pair key is a source path and value is a destination path. + * @param {Object} o Options map. + * @param {Object} o.reflectMap Map with keys as source path and values as destination path. + * @param {Object} o.filesGraph + * @param {Object} o.filter + * @param {Object} o.rc + * @param {Object} o.dst + * @param {Array} o.result + * @param {String} o.outputFormat='record' + * @param {Number} o.verbosity=0 + * @param {Boolean} o.allowingMissed=0 + * @param {Boolean} o.allowingCycled=0 + * @param {Boolean} o.withTerminals=1 + * @param {Boolean} o.withDirs=1 + * @param {Boolean} o.includingNonAllowed=1 + * @param {Boolean} o.includingDst + * @param {String} o.linkingAction='fileCopy' + * @param {Boolean} o.writing=1 + * @param {Boolean} o.srcDeleting=0 + * @param {Boolean} o.dstDeleting=0 + * @param {Boolean} o.dstDeletingCleanedDirs=1 + * @param {Boolean} o.dstRewriting=1 + * @param {Boolean} o.dstRewritingByDistinct=1 + * @param {Boolean} o.dstRewritingOnlyPreserving=0 + * @param {Boolean} o.preservingTime=0 + * @param {Boolean} o.preservingSame=0 + * @param {*} o.extral + * @param {Boolean} o.revisiting=null Controls how visited files are processed. Possible values: + * 0 - visit and include each file once + * 1 - visit and include each file once, break from loop on first links cycle and continue search ignoring file at which cycle begins + * 2 - visit and include each file once, break from loop on first links cycle and continue search visiting file at which cycle begins + * 3 - don't keep records of visited files + * Defaults: option o.revisiting in set to "1" if links resolving is enabled, otherwise default is "3". + * @param {Function} o.onUp + * @param {Function} o.onDown + * @param {Function} o.onDstName + * @param {Boolean} o.rebasingLink=0 Controls link rebasing during copy. Possible values: + * 0 - keep link as is, destination path will lead to source file + * 1 - rebase link, try to make destination file lead to other destination file if last was handled in same call of filesReflect + * 2 - rebase and resolve link, try to create copy of a file referenced by a link + * @function filesReflect + * @class wFileProviderFindMixin + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function filesReflect_body( o ) +{ + let self = this; + let path = self.path; + let cons = []; + let time; + + if( o.verbosity >= 1 ) + time = _.time.now(); + + _.routine.assertOptions( filesReflect_body, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( o.src.formed === 3 ); + _.assert( o.dst.formed === 3 ); + _.assert( o.dst.src === o.src ); + _.assert( o.src.dst === o.dst ); + _.assert( _.mapIs( o.src.filePath ) ); + _.assert( o.src.isPaired( o.dst ) ); + + /* */ + + let filePath = o.src.filePathMap( o.src.filePath, 1 ); + let groupedByDstMap = path.mapGroupByDst( filePath ); + for( let dstPath in groupedByDstMap ) + { + + let srcPath = groupedByDstMap[ dstPath ]; + let o2 = _.mapOnly_( null, o, self.filesReflectSingle.body.defaults ); + + o2.result = []; + + o2.dst = o2.dst.clone(); + o2.src = o2.src.clone(); + o2.src.pairWithDst( o2.dst ); + o2.src.filePathSelect( srcPath, dstPath ); + + let src = o2.src.effectiveProvider; + _.assert( _.routineIs( src.filesReflectSingle ), () => 'Method filesReflectSingle is not implemented' ); + let r = src.filesReflectSingle.body.call( src, o2 ); + cons.push( r ); + + if( _.consequenceIs( r ) ) + r.ifNoErrorThen( ( arg ) => _.arrayAppendArray( o.result, o2.result ) ); + else + _.arrayAppendArray( o.result, o2.result ); + + } + + /* */ + + if( _.any( cons, ( ready ) => _.consequenceIs( ready ) ) ) + { + let ready = + new _.Consequence() + .take( null ) + .andKeep( cons ); + + ready.ifNoErrorThen( end ); + return ready; + } + + return end(); + + /* */ + + function end() + { + + if( o.mandatory && o.outputFormat !== 'nothing' ) /* xxx : review option mandatory */ + if( !o.result.length ) + { + _.assert( o.src.isPaired() ); + let mtr = o.src.moveTextualReport(); + debugger; + throw _.err( 'Error. No file moved :', mtr ); + } + + /* qqq xxx : implement tests to cover log + Implement and use LoggerToString for that. + */ + + let result = o.result; + + if( o.verbosity >= 1 ) + result = result.filter( ( record ) => record.performed ); + + if( o.verbosity >= 3 ) + { + + result.forEach( ( record ) => + { + if( record.action === 'fileDelete' ) + { + self.logger.log( ` - ${ record.action } ${ record.dst.absolute }` ); + } + else + { + let mtr = path.moveTextualReport( record.dst.absolute, record.src.absolute ); + self.logger.log( ` + ${ record.action } ${ mtr }` ); + } + }); + + /* qqq xxx : verbosity > 3 should log each modified file, but not more + */ + + } + + if( o.verbosity >= 1 ) + if( result.length ) + { + _.assert( o.src.isPaired() ); + let mtr = o.src.moveTextualReport(); + self.logger.log( ` + Reflect ${ result.length } files ${ mtr } in ${ _.time.spent( time ) }` ); + } + + if( o.outputFormat !== 'record' ) + { + const resultForm = + { + 'src.absolute' : pathsForm, + 'dst.absolute' : pathsForm, + 'src.relative' : pathsForm, + 'dst.relative' : pathsForm, + 'nothing' : nothingForm, + }; + if( !( o.outputFormat in resultForm ) ) + _.assert( 0, `Unknown output format : ${ o.outputFormat }` ); + else + result = resultForm[ o.outputFormat ]( o.result, o.outputFormat ); + + // if( o.outputFormat === 'src.relative' ) + // { + // for( let r = 0 ; r < o.result.length ; r++ ) + // o.result[ r ] = o.result[ r ].src.relative; + // } + // else if( o.outputFormat === 'src.absolute' ) + // { + // for( let r = 0 ; r < o.result.length ; r++ ) + // o.result[ r ] = o.result[ r ].src.absolute; + // } + // else if( o.outputFormat === 'dst.relative' ) + // { + // for( let r = 0 ; r < o.result.length ; r++ ) + // o.result[ r ] = o.result[ r ].dst.relative; + // } + // else if( o.outputFormat === 'dst.absolute' ) + // { + // for( let r = 0 ; r < o.result.length ; r++ ) + // o.result[ r ] = o.result[ r ].dst.absolute; + // } + // else if( o.outputFormat === 'nothing' ) + // { + // o.result.splice( 0, o.result.length ); + // } + // else _.assert( 0, 'Unknown output format :', o.outputFormat ); + } + + return o.result; + } + + /* */ + + function pathsForm( src, format ) + { + format = format.split( '.' ); + for( let i = 0 ; i < src.length ; i++ ) + src[ i ] = o.result[ i ][ format[ 0 ] ][ format[ 1 ] ]; + return src; + } + + /* */ + + function nothingForm( src ) + { + src.splice( 0, src.length ); + return src; + } +} + +var defaults = filesReflect_body.defaults = Object.create( filesReflectEvaluate.defaults ); + +_.props.extend( defaults, filesReflectAdvancedDefaults ); + +defaults.filter = null; +defaults.reflectMap = null; +// defaults.outputFormat = 'record'; +defaults.outputFormat = 'nothing'; + +let filesReflect = _.routine.uniteCloning_replaceByUnite( filesReflect_head, filesReflect_body ); + +_.assert( _.boolLike( filesReflect_body.defaults.mandatory ) ); + +// + +function filesReflector_functor( routine ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.routineIs( routine ) ); + _.routineExtend( reflector, routine ); + return reflector; + + function reflector() + { + let self = this; + let op0 = self._filesFindPrepare0( routine, arguments ); + _.map.assertHasOnly( op0, reflector.defaults ); + return er; + + function er() + { + let o = _.props.extend( null, op0 ); + o.filter = self.recordFilter( o.filter ); + o.src = self.recordFilter( o.src ); + o.dst = self.recordFilter( o.dst ); + + for( let a = 0 ; a < arguments.length ; a++ ) + { + let op2 = arguments[ a ]; + + if( _.strIs( op2 ) ) + op2 = { src : { filePath : { [ op2 ] : null } } } + + op2.filter = op2.filter || Object.create( null ); + op2.src = op2.src || Object.create( null ); + if( op2.src.filePath === undefined ) + op2.src.filePath = ''; + + op2.dst = op2.dst || Object.create( null ); + + o.filter.and( op2.filter ).pathsExtendJoining( op2.filter ); + o.src.and( op2.src ).pathsExtendJoining( op2.src ); + o.dst.and( op2.dst ).pathsExtendJoining( op2.dst ); + + op2.filter = o.filter; + op2.src = o.src; + op2.dst = o.dst; + + _.props.extend( o, op2 ); + } + + return routine.call( self, o ); + } + + } + +} + +let filesReflector = filesReflector_functor( filesReflect ); + +// + +function filesReflectTo_head( routine, args ) +{ + let self = this; + let path = self.path; + let o = args[ 0 ]; + + if( args[ 1 ] !== undefined || !_.mapIs( args[ 0 ] ) ) + o = { dstProvider : args[ 0 ], dst : ( args.length > 1 ? args[ 1 ] : routine.defaults.dst ) } + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( 1 === args.length || 2 === args.length ); + _.routine.options_( routine, o ); + _.assert( o.dstProvider instanceof _.FileProvider.Abstract, () => 'Expects file provider {- o.dstProvider -}, but got ' + _.entity.strType( o.dstProvider ) ); + // _.assert( path.s.isAbsolute( o.dst ), 'Expects simple path string {- o.dst -}' ); + // _.assert( path.s.isAbsolute( o.src ), 'Expects simple path string {- o.src -}' ); + + return o; +} + +// + +function filesReflectTo_body( o ) +{ + let self = this; + let src = self; + let dst = o.dstProvider; + let system, result; + + if( src instanceof _.FileProvider.System ) + src = src.providerForPath( o.src ); + + _.assert( !( src instanceof _.FileProvider.System ) && src instanceof _.FileProvider.Abstract, 'Source provider should be an instance of _.FileProvider.Abstract' ) + _.routine.assertOptions( filesReflectTo_body, arguments ); + _.assert( !src.system || !dst.system || src.system === dst.system, 'not implemented' ); + + if( src.system ) + { + system = src.system; + } + else if( dst.system ) + { + system = dst.system; + } + else + { + system = new _.FileProvider.System({ empty : 1 }); + } + + let srcProtocol = src.protocol; + let dstProtocol = dst.protocol; + let srcRegistered = system.providersWithProtocolMap[ src.protocol ] === src; + let dstRegistered = system.providersWithProtocolMap[ dst.protocol ] === dst; + + // debugger; + // if( !src.protocol ) + // src.protocol = system.protocolNameGenerate( 0 ); + // if( !dst.protocol ) + // dst.protocol = system.protocolNameGenerate( 1 ); + + if( !src.protocol ) + src.protocol = src.constructor.shortName + src.id; + if( !dst.protocol ) + dst.protocol = dst.constructor.shortName + dst.id; + + try + { + + if( !srcRegistered ) + src.providerRegisterTo( system ); + if( !dstRegistered ) + dst.providerRegisterTo( system ); + + _.assert( src.system === dst.system ); + + // let filePath = { [ src.path.globalFromPreferred( o.srcPath ) ] : dst.path.globalFromPreferred( o.dstPath ) } + // let filePath = { [ src.path.globalFromPreferred( o.src ) ] : dst.path.globalFromPreferred( o.dst ) } + + if( Config.debug ) + { + let dstProvider = system.providerForPath( dst.path.globalFromPreferred( o.dst ) ); + _.assert + ( + dstProvider === dst, + `Dst path: ${o.dst} reffers to different dst provider: ${dstProvider.protocol}, routine expects: ${dst.protocol}` + ); + } + + o.src = src.recordFilter( o.src ); + o.dst = dst.recordFilter( o.dst ); + + let o2 = _.mapOnly_( null, o, filesReflect.defaults ); + o2.outputFormat = 'record'; /* Dmytro : maybe can be removed and changed tests */ + + // o2.reflectMap = filePath; + // delete o2.src; + // delete o2.dst; + + result = system.filesReflect( o2 ); + + _.assert( !_.consequenceIs( result ), 'not implemented' ); + + } + catch( err ) + { + debugger; + throw _.err( err ); + } + finally + { + if( !srcRegistered ) + src.providerUnregister(); + if( !dstRegistered ) + dst.providerUnregister(); + if( !srcRegistered && !dstRegistered ) + system.finit(); + } + + return result; +} + +var defaults = filesReflectTo_body.defaults = Object.create( filesReflectPrimeDefaults ); + +_.props.extend( defaults, filesReflectAdvancedDefaults ); + +defaults.mandatory = 0; +defaults.dstProvider = null; +defaults.dst = '/'; +defaults.src = '/'; + +let filesReflectTo = _.routine.uniteCloning_replaceByUnite( filesReflectTo_head, filesReflectTo_body ); + +// + +function filesExtract_head( routine, args ) +{ + let self = this; + let path = self.path; + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { src : o } + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( args.length === 1 ); + _.routine.options_( routine, o ); + // _.assert( path.isAbsolute( o.filePath ) ); + + return o; +} + +// + +function filesExtract_body( o ) +{ + let self = this; + + _.assert( o.dstProvider === null ); + + if( o.dstProvider === null ) + o.dstProvider = new _.FileProvider.Extract(); + + let result = self.filesReflectTo( o ) + + _.assert( !_.consequenceIs( result ), 'not implemented' ); + + return o.dstProvider; +} + +var defaults = filesExtract_body.defaults = Object.create( filesReflectTo.defaults ); + +let filesExtract = _.routine.uniteCloning_replaceByUnite( filesExtract_head, filesExtract_body ); + +// + +function filesFindSame_body( o ) +{ + let self = this; + let logger = self.logger; + let r = o.result = o.result || Object.create( null ); + + /* result */ + + _.assert( arguments.length === 1 ); + _.assert( _.object.isBasic( r ) ); + _.assert( _.strIs( o.filePath ) ); + _.assert( o.outputFormat === 'record' ); + + /* time */ + + let time; + if( o.usingTiming ) + time = _.time.now(); + + /* find */ + + let findOptions = _.mapOnly_( null, o, filesFind.defaults ); + findOptions.outputFormat = 'record'; + findOptions.result = []; + r.unique = self.filesFind.body.call( self, findOptions ); + + /* adjust found */ + + for( let f1 = 0 ; f1 < r.unique.length ; f1++ ) + { + let file1 = r.unique[ f1 ]; + + if( !file1.stat ) + { + r.unique.splice( f1, 1 ); + f1 -= 1; + continue; + } + + if( file1.isDir ) + { + r.unique.splice( f1, 1 ); + f1 -= 1; + continue; + } + + if( !file1.stat.size > o.maxSize ) + { + r.unique.splice( f1, 1 ); + f1 -= 1; + continue; + } + + } + + /* compare */ + + r.similarArray = []; + r.similarMaps = Object.create( null ); + r.similarGroupsArray = []; + r.similarGroupsMap = Object.create( null ); + r.similarFilesInTotal = 0; + r.linkedFilesMap = Object.create( null ); + r.linkGroupsArray = []; + + /* */ + + for( let f1 = 0 ; f1 < r.unique.length ; f1++ ) + { + let file1 = r.unique[ f1 ] + let path1 = o.relativePaths ? file1.relative : file1.absolute; + + for( let f2 = f1 + 1 ; f2 < r.unique.length ; f2++ ) + { + + let file2 = r.unique[ f2 ]; + let path2 = o.relativePaths ? file2.relative : file2.absolute; + let minSize = Math.min( file1.stat.size, file2.stat.size ); + let maxSize = Math.max( file1.stat.size, file2.stat.size ); + + if( _.files.stat.areHardLinked( file1.stat, file2.stat ) ) + { + linkAdd(); + continue; + } + + if( minSize / maxSize < o.similarityLimit ) + continue; + + if( !file1.stat.hash ) + file1.stat.hash = _.strLattersSpectre( self.fileRead( file1.absolute ) ); + if( !file2.stat.hash ) + file2.stat.hash = _.strLattersSpectre( self.fileRead( file2.absolute ) ); + + if( self.verbosity >= 4 ) + self.logger.log( '. strLattersSpectresSimilarity', path1, path2 ); + let similarity = _.strLattersSpectresSimilarity( file1.stat.hash, file2.stat.hash ); + + if( similarity < o.similarityLimit ) + continue; + + similarityAdd( similarity ); + + } + + } + + /* */ + + similarGroupsRefine(); + linkGroupsRefine(); + + return o.result; + + /* */ + + function similarityAdd( similarity ) + { + + let d = Object.create( null ); + d.path1 = path1; + d.path2 = path2; + d.similarity = similarity; + d.id = r.similarArray.length; + r.similarArray.push( d ); + + let similarMap = r.similarMaps[ path1 ] = r.similarMaps[ path1 ] || Object.create( null ); + similarMap[ path2 ] = d; + similarMap = r.similarMaps[ path2 ] = r.similarMaps[ path2 ] || Object.create( null ); + similarMap[ path1 ] = d; + + let group1 = r.similarGroupsMap[ path1 ]; + let group2 = r.similarGroupsMap[ path2 ]; + + if( !group1 ) + r.similarFilesInTotal += 1; + + if( !group2 ) + r.similarFilesInTotal += 1; + + if( group1 && group2 ) + { + if( group1 === group2 ) + return; + groupMove( group1, group2 ); + } + + let group = group1 || group2; + + if( !group ) + { + group = Object.create( null ); + group.paths = []; + group.paths.push( path1 ); + group.paths.push( path2 ); + r.similarGroupsArray.push( group ); + } + else if( !group1 ) + { + _.arrayAppendOnceStrictly( group.paths, path1 ); + } + else if( !group2 ) + { + _.arrayAppendOnceStrictly( group.paths, path2 ); + } + + r.similarGroupsMap[ path1 ] = group; + r.similarGroupsMap[ path2 ] = group; + + // if( r.similarGroupsMap[ path2 ] ) + // { + // debugger; + // if( r.similarGroupsMap[ similarGroup1 ] ) + // similarGroup1 = groupMove( path2, similarGroup1 ); + // } + // else + // { + // r.similarFilesInTotal += 1; + // + // if( !r.similarGroupsMap[ similarGroup1 ] ) + // { + // _.arrayAppendOnceStrictly( r.similarGroupsArray, similarGroup1 ); + // r.similarGroupsMap[ similarGroup1 ] = []; + // r.similarFilesInTotal += 1; + // } + // + // let group = r.similarGroupsMap[ similarGroup1 ] + // _.arrayAppendOnce( group, path1 ); + // _.arrayAppendOnce( group, path2 ); + // + // } + + } + + /* */ + + function groupMove( dst, src ) + { + debugger; + + _.arrayAppendArrayOnceStrictly( dst.paths, src.paths ); + _.arrayRemoveElementOnceStrictly( r.similarGroupsArray, src ); + + // if( _.strIs( r.similarGroupsMap[ dst ] ) ) + // debugger; + // if( _.strIs( r.similarGroupsMap[ dst ] ) ) + // dst = r.similarGroupsMap[ dst ]; + // _.assert( _.arrayIs( r.similarGroupsMap[ src ] ) ); + // _.assert( _.arrayIs( r.similarGroupsMap[ dst ] ) ); + // for( let i = 0 ; i < r.similarGroupsMap[ src ].length ; i++ ) + // { + // debugger; + // let srcElement = r.similarGroupsMap[ src ][ i ]; + // _.assert( _.strIs( r.similarGroupsMap[ srcElement ] ) || srcElement === src ); + // _.arrayAppendOnceStrictly( r.similarGroupsMap[ dst ], srcElement ); + // r.similarGroupsMap[ srcElement ] = dst; + // } + // _.arrayRemoveElementOnceStrictly( r.similarGroupsArray, src ); + + return dst; + } + + /* */ + + function similarGroupsRefine() + { + for( let g in r.similarGroupsMap ) + { + let group = r.similarGroupsMap[ g ]; + group.id = r.similarGroupsArray.indexOf( group ); + r.similarGroupsMap[ g ] = group.id; + } + } + + /* */ + + function linkAdd() + { + let d1 = r.linkedFilesMap[ path1 ]; + let d2 = r.linkedFilesMap[ path2 ]; + _.assert( !d1 || !d2, 'Two link descriptors for the same instance of linked file', path1, path2 ); + let d = d1 || d2; + if( !d ) + { + d = Object.create( null ); + d.paths = []; + d.paths.push( path1 ); + d.paths.push( path2 ); + r.linkGroupsArray.push( d ); + } + else if( !d1 ) + { + _.arrayAppendOnceStrictly( d.paths, path1 ); + } + else + { + _.arrayAppendOnceStrictly( d.paths, path2 ); + } + r.linkedFilesMap[ path1 ] = d; + r.linkedFilesMap[ path2 ] = d; + } + + /* */ + + function linkGroupsRefine() + { + for( let f in r.linkedFilesMap ) + { + let d = r.linkedFilesMap[ f ]; + d.id = r.linkGroupsArray.indexOf( d ) + r.linkedFilesMap[ f ] = d.id; + } + } + +} + +_.routineExtend( filesFindSame_body, filesFindRecursive.body ); + +var defaults = filesFindSame_body.defaults; +defaults.maxSize = 1 << 22; +// defaults.lattersFileSizeLimit = 1048576; +defaults.similarityLimit = 0.95; + +// defaults.usingFast = 1; +// defaults.usingContentComparing = 1; +// defaults.usingTakingNameIntoAccountComparingContent = 1; +// defaults.usingLinkedCollecting = 0; +// defaults.usingSameNameCollecting = 0; + +defaults.investigatingLinking = 1; +defaults.investigatingSimilarity = 1; +defaults.usingTiming = 0; +defaults.relativePaths = 0; + +defaults.result = null; + +let filesFindSame = _.routine.uniteCloning_replaceByUnite( filesFind.head, filesFindSame_body ); + +filesFindSame.having.aspect = 'entry'; + +// -- +// delete +// -- + +function filesDelete_head( routine, args ) +{ + let self = this; + args = _.longSlice( args ); + let o = self.filesFind.head.call( self, routine, args ); + return o; +} + +/* +qqq : +- add extended test routine +- cover option deletingEmptyDirs +- cover returned result, records of non-exitent files should not be in the result + +- if deletingEmptyDirs : 1 then + +/a/x +/a/b +/a/b/c +/a/b/c/f1 +/a/b/c/f2 + +filesDelete [ /a/b/c/f1, /a/b/c/f2 ] should delete + +/a/b +/a/b/c +/a/b/c/f1 +/a/b/c/f2 + +*/ + +function filesDelete_body( o ) +{ + let self = this; + let provider = o.filter.effectiveProvider; + let path = self.path; + let ready, time; + + if( o.verbosity >= 1 ) + time = _.time.now(); + + if( !o.sync ) + ready = new _.Consequence().take( null ); + + if( o.late ) + o.visitingCertain = 0; + + _.assert( !o.withTransient, 'Transient files should not be included' ); + _.assert( o.resolvingTextLink === 0 || o.resolvingTextLink === false ); + _.assert( o.resolvingSoftLink === 0 || o.resolvingSoftLink === false ); + _.assert( _.numberIs( o.safe ) ); + _.assert( o.filter.formed === 5 ); + _.assert( arguments.length === 1 ); + + /* */ + + let o2 = _.mapOnly_( null, o, provider.filesFind.defaults ); + o2.verbosity = 0; + o2.outputFormat = 'record'; + o2.withTransient = 1; + _.assert( !!o.withDirs ); + _.assert( !!o.withActual ); + _.assert( !o.withTransient ); + _.assert( o.result === o2.result ); + + /* */ + + if( o.sync ) + { + provider.filesFind.body.call( provider, o2 ) + handleResult(); + if( o.deletingEmptyDirs ) + deleteEmptyDirs(); + if( o.writing ) + { + if( o.late ) + handleLateWriting(); + else + handleWriting(); + } + return end(); + } + else + { + ready.then( () => provider.filesFind.body.call( provider, o2 ) ); + ready.then( () => handleResult() ); + if( o.deletingEmptyDirs ) + ready.then( () => deleteEmptyDirs() ); + if( o.writing ) + { + if( o.late ) + ready.then( () => handleLateWriting() ); + else + ready.then( () => handleWriting() ); + } + ready.then( () => end() ); + return ready; + } + + /* - */ + + function handleLateWriting() + { + let opened = false; + + if( o.tempPath === null ) + { + debugger; + o.tempPath = path.tempOpen( o.result[ 0 ].absolute ); + opened = true; + } + + let late = []; + let deleteDirName = 'delete' + '-' + _.idWithDateAndTime(); + for( let f = o.result.length-1 ; f >= 0 ; f-- ) + { + let record = o.result[ f ]; + if( !record.included || !record.isActual ) + continue; + if( record.absolute === '/' ) + continue; + + let dstPath = path.join( o.tempPath, deleteDirName, record.relative ); + late.push( dstPath ); + + debugger; + self.fileRename + ({ + srcPath : record.absolute, + dstPath, + }) + + } + + _.time.out( 100, () => + { + debugger; + if( opened ) + path.tempClose( o.tempPath ); + else + late.forEach( ( dstPath ) => self.filesDelete( dstPath ) ); + debugger; + }); + + return true; + } + + /* - */ + + function handleWriting() + { + for( let f = o.result.length-1 ; f >= 0 ; f-- ) + { + let record = o.result[ f ]; + if( record.included && record.isActual ) + if( record.absolute !== '/' ) + fileDelete( record ); + } + return true; + } + + /* - */ + + function handleResult() + { + for( let f1 = 0 ; f1 < o.result.length ; f1++ ) + { + let file1 = o.result[ f1 ]; + + if( file1.isActual ) + { + + if( !file1.isDir ) + continue; + + if( file1.isTransient ) + { + /* delete dir if: + recursive : 0 + its empty + terminals from dir will be included in result + */ + + if( !o.filter.recursive ) + continue; + if( o.filter.recursive === 2 && o.withTerminals ) + continue; + if( provider.dirIsEmpty( file1.absolute ) ) + continue; + } + } + + o.result.splice( f1, 1 ); + f1 -= 1; + + if( !file1.isActual || !file1.isTransient ) + for( let f2 = f1 ; f2 >= 0 ; f2-- ) + { + let file2 = o.result[ f2 ]; + // if( file2.relative === '.' ) /* qqq : ? */ + if( _.strBegins( file1.absolute, file2.absolute ) ) + { + o.result.splice( f2, 1 ); + f1 -=1 ; + } + } + } + + return true; + } + + /* - */ + + function end() + { + + if( o.verbosity > 1 || ( o.verbosity === 1 && o.result.length ) ) + { + let spentTime = _.time.now() - time; + debugger; + let groupsMap = path.group({ keys : o.filter.filePath, vals : o.result }); + let textualReport = path.groupTextualReport + ({ + explanation : o.writing ? ' - Deleted ' : ' - Will delete ', + groupsMap, + verbosity : o.verbosity, + spentTime, + }); + if( textualReport ) + provider.logger.log( textualReport ); + } + + if( o.outputFormat === 'absolute' ) + o.result = _.select( o.result, '*/absolute' ); + else if( o.outputFormat === 'relative' ) + o.result = _.select( o.result, '*/relative' ); + else _.assert( o.outputFormat === 'record' ); + + return o.result; + } + + /* */ + + function fileDelete( file ) + { + if( o.sync ) + _fileDelete( file ); + else + ready.then( () => _fileDelete( file ) ); + } + + /* */ + + function _fileDelete( file ) + { + let o2 = + { + filePath : file.absolute, + throwing : o.throwing, + verbosity : 0, + safe : o.safe, + sync : o.sync, + } + + let r = file.factory.effectiveProvider.fileDelete( o2 ); + if( r === null ) + if( o.verbosity ) + provider.logger.log( ' ! Cant delete ' + file.absolute ); + return r; + } + + /* - */ + + function deleteEmptyDirs() + { + + if( !o.result.length ) + return true; + + let dirsPath = path.traceToRoot( o.result[ 0 ].dir ); + let factory = o.result[ 0 ].factory; + let filesMap = Object.create( null ); + + _.each( o.result, ( r ) => filesMap[ r.absolute ] = r ); + + for( let d = dirsPath.length-1 ; d >= 0 ; d-- ) + { + let dirPath = dirsPath[ d ]; + let files = provider.dirRead({ filePath : dirPath, outputFormat : 'absolute' }); + + for( let f = files.length-1 ; f >= 0 ; f-- ) + { + let file = files[ f ]; + if( !filesMap[ file ] ) + break; + files.splice( f, 1 ) + } + + if( files.length ) + break; + + _.assert( !filesMap[ dirPath ] ) + + let file = factory.record( dirPath ); + file.isActual = true; + file.isTransient = true; + file.included = true; + + filesMap[ dirPath ] = file; + + o.result.unshift( file ) + } + + return true; + } + +} + +_.assert( _.routineIs( filesFind.body ) ); +_.routineExtend( filesDelete_body, filesFind.body ); + +var defaults = filesDelete_body.defaults; +defaults.outputFormat = 'record'; +defaults.sync = 1; +defaults.withTransient = 0; +defaults.withDirs = 1; +defaults.withTerminals = 1; +defaults.resolvingSoftLink = 0; +defaults.resolvingTextLink = 0; +defaults.allowingMissed = 1; +defaults.allowingCycled = 1; +defaults.verbosity = null; +defaults.maskPreset = 0; +defaults.throwing = null; +defaults.safe = null; +defaults.writing = 1; +defaults.late = 0; +defaults.tempPath = null; +defaults.deletingEmptyDirs = 0; + +_.assert( filesFind.defaults.deletingEmptyDirs === undefined ); +_.assert( filesFind.body.defaults.deletingEmptyDirs === undefined ); +_.assert( filesDelete_body.defaults.deletingEmptyDirs === 0 ); +_.assert( filesDelete_body.body === undefined ); + +/* +qqq : implement and cover option late for method filesDelete. +*/ + +// + +let filesDelete = _.routine.uniteCloning_replaceByUnite( filesFindRecursive.head, filesDelete_body ); +filesDelete.having.aspect = 'entry'; + +var defaults = filesDelete.defaults; +var having = filesDelete.having; + +_.assert( !!defaults ); +_.assert( !!having ); +_.assert( !!filesDelete.defaults.withDirs ); + +// + +function filesDeleteTerminals_body( o ) +{ + let self = this; + + _.routine.assertOptions( filesDeleteTerminals_body, arguments ); + _.assert( o.withTerminals ); + _.assert( !o.withDirs ); + _.assert( !o.withTransient, 'Transient files should not be included' ); + _.assert( o.resolvingTextLink === 0 || o.resolvingTextLink === false ); + _.assert( o.resolvingSoftLink === 0 || o.resolvingSoftLink === false ); + _.assert( _.numberIs( o.safe ) ); + _.assert( arguments.length === 1 ); + + /* */ + + let o2 = _.mapOnly_( null, o, self.filesFind.defaults ); + + o2.onDown = _.arrayAppendElement( _.array.as( o.onDown ), handleDown ); + if( _.arrayIs( o2.onDown ) ) + o2.onDown = _.routinesComposeReturningLast( o2.onDown ); + + let files = self.filesFind.body.call( self, o2 ); + + return files; + + /* */ + + function handleDown( record ) + { + if( o.writing ) + if( record.isActual && !record.isDirectory && record.included ) + self.fileDelete + ({ + filePath : record.absolute, + throwing : o.throwing, + verbosity : o.verbosity, + }); + } + +} + +_.routineExtend( filesDeleteTerminals_body, filesDelete.body ); + +var defaults = filesDeleteTerminals_body.defaults; + +defaults.withTerminals = 1; +defaults.withDirs = 0; +defaults.withTransient = 0; + +let filesDeleteTerminals = _.routine.uniteCloning_replaceByUnite( filesFindRecursive.head, filesDeleteTerminals_body ); + +// + +function filesDeleteEmptyDirs_body( o ) +{ + let self = this; + + /* */ + + _.routine.assertOptions( filesDeleteEmptyDirs_body, arguments ); + _.assert( !o.withTerminals ); + _.assert( o.withDirs ); + _.assert( !o.withTransient ); + + /* */ + + let o2 = _.mapOnly_( null, o, self.filesFind.defaults ); + + o2.onDown = _.arrayAppendElement( _.array.as( o.onDown ), handleDown ); + if( _.arrayIs( o2.onDown ) ) + o2.onDown = _.routinesComposeReturningLast( o2.onDown ); + + let files = self.filesFind.body.call( self, o2 ); + + return files; + + /* */ + + function handleDown( record ) + { + + if( !record.included ) + return; + + try + { + + let sub = self.dirRead( record.absolute ); + if( !sub ) + debugger; + + if( !sub.length ) + self.fileDelete({ filePath : record.absolute, throwing : o.throwing, verbosity : o.verbosity }); + + } + catch( err ) + { + if( o.throwing ) + throw _.err( err ); + } + + } + +} + +_.routineExtend( filesDeleteEmptyDirs_body, filesFind.body ); + +var defaults = filesDeleteEmptyDirs_body.defaults; +defaults.throwing = false; +defaults.verbosity = null; +defaults.outputFormat = 'absolute'; +defaults.withTerminals = 0; +defaults.withDirs = 1; +defaults.withTransient = 0; + +let filesDeleteEmptyDirs = _.routine.uniteCloning_replaceByUnite( filesFindRecursive.head, filesDeleteEmptyDirs_body ); + +// -- +// other find +// -- + +function filesRead_head( routine, args ) +{ + let self = this; + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { filePath : args[ 0 ] } + + _.assert( args.length === 1 ); + _.assert( arguments.length === 2 ); + + o = self.filesFind.head.call( self, routine, [ o ] ); + + return o; +} + +function filesRead_body( o ) +{ + let self = this; + let path = self.path; + let result = Object.create( null ); + result.dataMap = Object.create( null ); + result.dataArray = []; + result.errors = []; + + _.assert( o.outputFormat === undefined ); + + let o2 = _.mapOnly_( null, o, self.filesFind.defaults ); + o2.outputFormat = 'record'; + let ready = _.Consequence.From( self.filesFind.body.call( self, o2 ) ); + + ready.then( ( files ) => + { + let ready = _.Consequence().take( result ); + + result.files = files; + + for( let i = 0 ; i < files.length ; i++ ) + ready.also( () => fileRead( files[ i ] ) ); + + return ready; + }); + + ready.finally( ( err, arg ) => + { + if( err ) + { + if( o.throwing ) + throw _.err( err ); + else + result.errors.push( _.err( err ) ); + } + if( result.errors.length ) + if( o.throwing ) + throw _.err( result.errors[ 0 ] ); + return result; + }); + + if( o.sync ) + return ready.sync(); + return ready; + + /* */ + + function fileRead( record, dstPath ) + { + let r = null; + let index = result.dataArray.length; + + try + { + let o2 = _.mapOnly_( null, o, self.fileRead.defaults ); + o2.filePath = record.absolute; + o2.outputFormat = 'data'; + r = _.Consequence.From( self.fileRead( o2 ) ); + + r.finally( ( err, data ) => + { + if( err ) + { + err = _.err( err, `\nFailed to read ${record.absolute}` ); + err.filePath = record.absolute; + result.errors.push( err ); + return null; + } + result.dataMap[ record.absolute ] = data; + result.dataArray[ index ] = data; + return null; + }); + + } + catch( err ) + { + debugger; + let error = _.err( err, `\nFailed to read ${record.absolute}` ); + error.filePath = record.absolute; + result.errors.push( error ); + } + + return r; + } + +} + +var defaults = filesRead_body.defaults = _.props.extend( null, Partial.prototype.fileRead.defaults, filesFind.defaults ); + +defaults.sync = 1; +defaults.throwing = null; +defaults.mode = 'distinct'; +defaults.resolvingSoftLink = 1; +defaults.resolvingTextLink = 1; +defaults.withDirs = 0; + +delete defaults.outputFormat; + +let filesRead = _.routine.uniteCloning_replaceByUnite( filesRead_head, filesRead_body ); + +// + +function filesRename_head( routine, args ) +{ + let self = this; + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { filePath : args[ 0 ] } + + o = self.filesFind.head.call( self, routine, [ o ] ); + + _.assert( args.length === 1 ); + _.assert( arguments.length === 2 ); + _.assert( _.routineIs( o.onRename ) ); + _.assert( _.routineIs( self[ o.linkingAction ] ), `Unknown linkingAction method ${o.linkingAction}` ); + + return o; +} + +function filesRename_body( o ) +{ + let self = this; + let path = self.path; + let result = Object.create( null ); + result.dataMap = Object.create( null ); + result.dataArray = []; + result.errors = []; + + _.assert( o.outputFormat === undefined ); + + let o3 = _.mapOnly_( null, o, self[ o.linkingAction ].defaults ); + let o2 = _.mapOnly_( null, o, self.filesFind.defaults ); + o2.outputFormat = 'record'; + o2.onDown = onDown; + return self.filesFind.body.call( self, o2 ); + + function onDown( r ) + { + let dstPath = o.onRename( r, o ); + _.assert( dstPath === undefined || path.isAbsolute( dstPath ), '{- o.onRename -} should return undefined or absolute path of destination' ); + if( dstPath !== undefined ) + { + let o4 = Object.assign( Object.create( null ), o3 ); + o4.srcPath = r.absolute; + o4.dstPath = dstPath; + r.effectiveProvider[ o.linkingAction ]( o4 ); + r.absolute = dstPath; + } + if( o.onDown ) + return o.onDown( ... arguments ); + } + +} + +var defaults = filesRename_body.defaults = _.props.extend( null, Partial.prototype.fileRename.defaults, filesFind.defaults ); + +defaults.sync = 1; +defaults.throwing = null; +defaults.mode = 'distinct'; +defaults.linkingAction = 'fileRename'; +defaults.resolvingSoftLink = 1; +defaults.resolvingTextLink = 1; +defaults.withDirs = 0; +defaults.onRename = null; + +delete defaults.outputFormat; + +let filesRename = _.routine.uniteCloning_replaceByUnite( filesRename_head, filesRename_body ); + +// + +function softLinksBreak_body( o ) +{ + let self = this; + + // o = self.filesFind.head.call( self, softLinksBreak, arguments ); + + _.routine.assertOptions( softLinksBreak_body, arguments ); + _.assert( o.outputFormat === 'record' ); + + /* */ + + let optionsFind = _.mapOnly_( null, o, filesFind.defaults ); + optionsFind.onDown = _.arrayAppendElement( _.array.as( optionsFind.onDown ), function( record ) + { + + debugger; + throw _.err( 'not tested' ); + + if( o.breakingSoftLink && record.isSoftLink ) + self.softLinkBreak( record.absolute ); + if( o.breakingTextLink && record.isTextLink ) + self.softLinkBreak( record.absolute ); + + }); + + let files = self.filesFind.body.call( self, optionsFind ); + + return files; +} + +// _.routineExtend( softLinksBreak, filesFind ); + +// var defaults = softLinksBreak_body.defaults; + +_.routineExtend( softLinksBreak_body, filesFind.body ); + +var defaults = softLinksBreak_body.defaults; + +defaults.outputFormat = 'record'; +defaults.breakingSoftLink = 1; +defaults.breakingTextLink = 0; +// defaults.recursive = 2; + +let softLinksBreak = _.routine.uniteCloning_replaceByUnite( filesFindRecursive.head, softLinksBreak_body ); + +// + +function softLinksRebase_body( o ) +{ + let self = this; + // o = self.filesFind.head.call( self, softLinksRebase, arguments ); + + _.routine.assertOptions( softLinksRebase_body, arguments ); + _.assert( o.outputFormat === 'record' ); + _.assert( !o.resolvingSoftLink ); + + /* */ + + let optionsFind = _.mapOnly_( null, o, filesFind.defaults ); + optionsFind.onDown = _.arrayAppendElement( _.array.as( optionsFind.onDown ), function( record ) + { + + if( !record.isSoftLink ) + return; + + record.isSoftLink; + let resolvedPath = self.pathResolveSoftLink( record.absolutePreferred ); + let rebasedPath = self.path.rebase( resolvedPath, o.oldPath, o.newPath ); + self.fileDelete({ filePath : record.absolutePreferred, verbosity : 0 }); + self.softLink + ({ + dstPath : record.absolutePreferred, + srcPath : rebasedPath, + allowingMissed : 1, + allowingCycled : 1, + }); + + _.assert( !!self.statResolvedRead({ filePath : record.absolutePreferred, resolvingSoftLink : 0 }) ); + + }); + + let files = self.filesFind.body.call( self, optionsFind ); + + return files; +} + +_.routineExtend( softLinksRebase_body, filesFind.body ); + +var defaults = softLinksRebase_body.defaults; + +// _.routineExtend( softLinksRebase, filesFind ); +// var defaults = softLinksRebase_body.defaults; + +defaults.outputFormat = 'record'; +defaults.oldPath = null; +defaults.newPath = null; +// defaults.recursive = 2; +defaults.resolvingSoftLink = 0; + +let softLinksRebase = _.routine.uniteCloning_replaceByUnite( filesFindRecursive.head, softLinksRebase_body ); + +// + +/* +qqq : has poor coverage! please improve. +qqq : optimize +*/ + +function filesHasTerminal( filePath ) +{ + let self = this; + _.assert( arguments.length === 1 ); + + let terminal = false; + + debugger; + self.filesFindRecursive + ({ + filePath, + withStem : 1, + withDirs : 1, + withTerminals : 1, + onUp, + resolvingSoftLink : 0, + resolvingTextLink : 0, + // recursive : 2 + }) + + return terminal; + + /* */ + + function onUp( record ) + { + debugger; + if( terminal ) + return _.dont; + if( record.stat && !record.isDir ) + terminal = record; + return record; + } +} + +// -- +// resolver +// -- + +function filesResolve( o ) +{ + let self = this; + let result; + o = _.routine.options_( filesResolve, arguments ); + + _.assert( _.object.isBasic( o.translator ) ); + + let globPath = o.translator.realFor( o.globPath ); + let globOptions = _.mapOnly_( null, o, self.filesGlob.defaults ); + + globOptions.filter = globOptions.filter || Object.create( null ); + globOptions.filePath = globPath; + globOptions.filter.basePath = o.translator.realRootPath; + globOptions.outputFormat = o.outputFormat; + + _.assert( !!self ); + + result = self.filesGlob( globOptions ); + + return result; +} + +_.routineExtend( filesResolve, filesGlob ); + +var defaults = filesResolve.defaults; +defaults.globPath = null; +defaults.translator = null; +defaults.outputFormat = 'record'; + +// -- +// relations +// -- + +let ReflectAction = +{ + 'fileCopy' : 'fileCopy', + 'hardLink' : 'hardLink', + 'hardLinkMaybe' : 'hardLinkMaybe', + 'softLink' : 'softLink', + 'softLinkMaybe' : 'softLinkMaybe', + 'textLink' : 'textLink', + 'nop' : 'nop', +} + +let ReflectMandatoryAction = +{ + 'fileCopy' : 'fileCopy', + 'hardLink' : 'hardLink', + 'softLink' : 'softLink', + 'textLink' : 'textLink', + 'nop' : 'nop', +} + +let ReflecEvalAction = +{ + 'exclude' : 'exclude', + 'ignore' : 'ignore', + 'fileDelete' : 'fileDelete', + 'dirMake' : 'dirMake', + 'fileCopy' : 'fileCopy', + 'softLink' : 'softLink', + 'hardLink' : 'hardLink', + 'textLink' : 'textLink', + 'nop' : 'nop', +} + +let FindOutputFormat = +{ + 'absolute' : 'absolute', + 'relative' : 'relative', + 'real' : 'real', + 'record' : 'record', + 'nothing' : 'nothing', +} + +let Composes = +{ +} + +let Aggregates = +{ +} + +let Associates = +{ +} + +let Restricts = +{ +} + +let Statics = +{ + ReflectAction, + ReflectMandatoryAction, + ReflecEvalAction, + FindOutputFormat, +} + +// -- +// declare +// -- + +let Supplement = +{ + + // etc + + recordsOrder, + + // find + + _filesFindPrepare0, + _filesFindPrepare1, + _filesFindPrepare2, + _filesFindFilterAbsorb, + + filesFindNominal, + filesFindSingle, + filesFind, + filesFindRecursive, + filesGlob, + + filesFinder_functor, + filesFinder, + filesGlober, + + // + + filesFindGroups, + filesReadGroups, + + // reflect + + _filesFiltersPrepare, + _filesReflectPrepare, + + filesReflectEvaluate, + filesReflectSingle, + filesReflect, /* xxx qqq : write test of filesReflect into itself with goal to change extensions */ + + filesReflector_functor, + filesReflector, + + filesReflectTo, + filesExtract, + + // same + + filesFindSame, + + // delete + + filesDelete, + filesDeleteTerminals, + filesDeleteEmptyDirs, + + // other find + + filesRead, /* qqq : cover please */ + filesRename, /* qqq : cover please */ + + softLinksBreak, + softLinksRebase, + filesHasTerminal, + + // resolver + + filesResolve, + + // + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + +} + +// + +_.classDeclare +({ + cls : Self, + supplement : Supplement, + withMixin : true, + withClass : true, +}); + +_.FileProvider = _.FileProvider || Object.create( null ); +_.FileProvider[ Self.shortName ] = Self; + +_.assert( !!_.FileProvider.FindMixin.prototype.filesDelete.defaults.withDirs ); + +Self.mixin( Partial ); + +_.assert( !!_.FileProvider.Partial.prototype.filesDelete.defaults.withDirs ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l6/FindMixin.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l6' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, FindMixin_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file FindMixin_s */ })(); + +/* */ /* begin of file System_s */ ( function System_s() { function System_s_naked() { ( function _System_s_() +{ + +'use strict'; + +/** + @classdesc Class that allows file manipulations between different file providers using global paths. + @class wFileSystem + @namespace wTools.FileProvider + @module Tools/mid/Files +*/ + +const _global = _global_; +const _ = _global_.wTools; +const Routines = Object.create( null ); +const FileRecord = _.files.FileRecord; +const Parent = _.FileProvider.Partial; +const Self = wFileSystem; +function wFileSystem( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'System'; + +_.assert( _.routineIs( _.uri.join ) ); +_.assert( _.routineIs( _.uri.normalize ) ); +_.assert( _.routineIs( _.uri.isNormalized ) ); + +// -- +// inter +// -- + +function init( o ) +{ + let self = this; + Parent.prototype.init.call( self, o ); + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( o ) + if( o.defaultOrigin !== undefined ) + { + throw _.err( 'not tested' ); + } + + if( o && o.providers ) + { + self.providersRegister( o.providers ); + } + else if( !o || !o.empty ) + if( _.fileProvider ) + { + self.providerRegister( _.fileProvider ); + self.providerDefaultSet( _.fileProvider ); + } + + _.assert( self.providers === undefined ); +} + +// -- +// provider +// -- + +/** + @summary Changes default file provider. + @description Sets default provider to `null` if no argument provided. + @param {Object} [provider] Provider to set as default. + @function providerDefaultSet + @class wTools.FileProvider.wFileSystem + @namespace wTools.FileProvider + @module Tools/mid/Files +*/ + +function providerDefaultSet( provider ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( provider === null || provider instanceof _.FileProvider.Abstract ); + + if( provider ) + { + + _.assert( _.arrayIs( provider.protocols ) && provider.protocols.length > 0 ); + _.assert( _.strIs( provider.originPath ) ); + + self.defaultProvider = provider; + self.defaultProtocol = provider.protocols[ 0 ]; + self.defaultOrigin = provider.originPath; + + } + else + { + + self.defaultProvider = null; + self.defaultProtocol = null; + self.defaultOrigin = null; + + } + +} + +/** + @summary Short-cut for {@link module:Tools/mid/Files.wTools.FileProvider.wFileSystem.providerRegister}. Registers several file providers. + @param {Object|Object[]} fileProvider Provider(s) to register. + @function providerRegister + @class wTools.FileProvider.wFileSystem + @namespace wTools.FileProvider + @module Tools/mid/Files +*/ + +// + +function providersRegister( src ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( src instanceof _.FileProvider.Abstract ) + { + self.providerRegister( src ); + } + else if( _.arrayIs( src ) ) + { + for( let p = 0 ; p < src.length ; p++ ) + self.providerRegister( src[ p ] ); + } + else + { + _.assert( 0, 'Unknown kind of argument', src ); + } + + return self; +} + +// + +/** + @summary Adds provider to the inner registry. + @description Provider should have protocol and origin path defined. + @param {Object} fileProvider Provider to register. + @function providerRegister + @class wTools.FileProvider.wFileSystem + @namespace wTools.FileProvider + @module Tools/mid/Files +*/ + +function providerRegister( fileProvider ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert + ( + fileProvider instanceof _.FileProvider.Abstract, + () => `Expects file providers, but got ${_.entity.strType( fileProvider )}` + ); + _.assert( _.arrayIs( fileProvider.protocols ) ); + _.assert + ( + _.strDefined( fileProvider.protocol ), + () => `Cant register file provider without {-protocol-} defined ${fileProvider.qualifiedName}` + ); + _.assert( _.strDefined( fileProvider.originPath ) ); + _.assert + ( + fileProvider.protocols && fileProvider.protocols.length > 0, + () => `Cant register file provider without protocols "${fileProvider.qualifiedName}"` + ); + /* qqq : make usre template string is used everywhere */ + + let protocolMap = self.providersWithProtocolMap; + for( let p = 0 ; p < fileProvider.protocols.length ; p++ ) + { + let protocol = fileProvider.protocols[ p ]; + if( protocolMap[ protocol ] ) + _.assert + ( + !protocolMap[ protocol ] || protocolMap[ protocol ] === fileProvider, + () => _.strQuote( fileProvider.qualifiedName ) + ' is trying to reserve protocol ' + _.strQuote( protocol ) + ', which is reserved by ' + _.strQuote( protocolMap[ protocol ].qualifiedName ) + ); + protocolMap[ protocol ] = fileProvider; + } + + _.assert( !fileProvider.system || fileProvider.system === self, () => 'File provider ' + fileProvider.qualifiedName + ' already has a system ' + fileProvider.system.qualifiedName ); + fileProvider.system = self; + + return self; +} + +// + +/** + @summary Removes provider from the inner registry. + @description Provider must be registered in current system. + @param {Object} fileProvider Provider to unregister. + @function providerUnregister + @class wTools.FileProvider.wFileSystem + @namespace wTools.FileProvider + @module Tools/mid/Files +*/ + +function providerUnregister( fileProvider ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( fileProvider instanceof _.FileProvider.Abstract ); + _.assert( self.providersWithProtocolMap[ fileProvider.protocol ] === fileProvider ); + _.assert( fileProvider.system === self ); + + delete self.providersWithProtocolMap[ fileProvider.protocol ]; + fileProvider.system = null; + + return self; +} + +// + +/** + @summary Selects file provider for specified global path. + @description Returns default file provider if system doesn't have provider for specified path. + @param {String} url Source url. + @function providerForPath + @class wTools.FileProvider.wFileSystem + @namespace wTools.FileProvider + @module Tools/mid/Files +*/ + +function providerForPath( url ) +{ + let self = this; + let path = self.path; + + if( _.strIs( url ) ) + url = path.parse( url ); + + _.assert( _.mapIs( url ) ); + _.assert( ( url.protocols && url.protocols.length ) ? _.routineIs( url.protocols[ 0 ].toLowerCase ) : true ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + /* */ + + let protocol = url.protocol || self.defaultProtocol; + + _.assert( _.strIs( protocol ) || protocol === null ); + + if( protocol ) + protocol = protocol.toLowerCase(); + + if( self.providersWithProtocolMap[ protocol ] ) + { + return self.providersWithProtocolMap[ protocol ]; + } + + /* */ + + return self.defaultProvider; +} + +// + +function protocolNameGenerate( skip ) +{ + let self = this; + let number = 1; + let name; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + skip = skip || 0; + skip += 1; + + do + { + name = 'pro' + number; + number += 1; + if( !self.providersWithProtocolMap[ name ] ) + skip -= 1; + } + while( skip > 0 ) + + return name; +} + +// + +/** + @summary Returns true if current system has specified file `provider` in the registry. + @param {Object} provider File provider to check. + @function hasProvider + @class wTools.FileProvider.wFileSystem + @namespace wTools.FileProvider + @module Tools/mid/Files +*/ + +function hasProvider( provider ) +{ + let self = this; + _.assert( arguments.length === 1 ); + return !!self.providersWithProtocolMap[ provider.protocol ]; +} + +// -- +// adapter +// -- + +function _recordFactoryFormEnd( recordFactory ) +{ + let self = this; + + _.assert( recordFactory instanceof _.files.FileRecordFactory ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( recordFactory.effectiveProvider instanceof _.FileProvider.Abstract, 'No provider for base path', recordFactory.basePath, 'found' ); + // _.assert( !_.path.isGlobal( recordFactory.basePath ) ); + // _.assert( recordFactory.stemPath === null || !_.path.isGlobal( recordFactory.stemPath ) ); + + return recordFactory; +} + +// + +function _recordFormBegin( record ) +{ + let self = this; + + _.assert( record instanceof _.files.FileRecord ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + return record; +} + +// // +// +// function _recordPathForm( record ) +// { +// let self = this; +// _.assert( record instanceof _.files.FileRecord ); +// _.assert( arguments.length === 1, 'Expects single argument' ); +// +// return record; +// } + +// + +function _recordFormEnd( record ) +{ + let self = this; + _.assert( record instanceof _.files.FileRecord ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + return record; +} + +// + +function _recordAbsoluteGlobalMaybeGet( record ) +{ + let self = this; + _.assert( record instanceof _.files.FileRecord ); + _.assert( arguments.length === 1, 'Expects single argument' ); + return record.absoluteGlobal; +} + +// + +function _recordRealGlobalMaybeGet( record ) +{ + let self = this; + _.assert( record instanceof _.files.FileRecord ); + _.assert( arguments.length === 1, 'Expects single argument' ); + return record.realGlobal; +} + +// + +function fieldPush() +{ + let self = this; + + Parent.prototype.fieldPush.apply( self, arguments ); + + if( self.providersWithProtocolMap ) + for( let or in self.providersWithProtocolMap ) + { + let provider = self.providersWithProtocolMap[ or ]; + provider.fieldPush.apply( provider, arguments ) + } + +} + +// + +function fieldPop() +{ + let self = this; + + Parent.prototype.fieldPop.apply( self, arguments ); + + if( self.providersWithProtocolMap ) + for( let or in self.providersWithProtocolMap ) + { + let provider = self.providersWithProtocolMap[ or ]; + provider.fieldPop.apply( provider, arguments ); + } + +} + +// -- +// path +// -- + +/** + @summary Converts global path `filePath` to local. + @param {String} filePath Global path. + @function preferredFromGlobalAct + @class wTools.FileProvider.wFileSystem + @namespace wTools.FileProvider + @module Tools/mid/Files +*/ + +function preferredFromGlobalAct( filePath ) +{ + let self = this; + _.assert( arguments.length === 1, 'Expects single argument' ); + return self._pathLocalize( filePath ).localPath; +} + +// + +function _pathLocalize( filePath ) +{ + let self = this; + let path = self.path; + let r = self._pathLocalizeMaybe( filePath ); + + _.sure( _.object.isBasic( r.provider ), () => 'No provider for path ' + _.strQuote( filePath ) ); + + return r; +} + +// + +function _pathLocalizeMaybe( filePath ) +{ + let self = this; + let path = self.path; + let r = Object.create( null ); + r.originalPath = filePath; + r.parsedPath = r.originalPath; + + _.assert( _.strIs( filePath ), 'Expects string' ); + _.assert( arguments.length === 1 ); + + self._pathRelocalize( r, null ); + + return r; +} + +// + +function _pathRelocalize( r, provider ) +{ + let self = this; + let path = self.path; + + _.assert( _.strIs( r.originalPath ), 'Expects string' ); + _.assert( _.strIs( r.parsedPath ) || _.mapIs( r.parsedPath ), 'Expects map or string parsedPath' ); + _.assert( arguments.length === 2 ); + + if( _.strIs( r.parsedPath ) ) + r.parsedPath = path.parse( path.normalize( r.parsedPath ) ); + + if( !r.provider ) + if( provider ) + r.provider = provider; + if( !r.provider ) + r.provider = self.providerForPath( r.parsedPath ); + + if( r.provider ) + r.localPath = r.provider.path.preferredFromGlobal( r.parsedPath ); + else + r.localPath = r.originalPath; + + _.assert( _.strIs( r.localPath ) ); + + return r; +} + +// + +function _pathPrepend( provider, filePath ) +{ + let self = this; + let path = self.path; + + _.assert( arguments.length === 2 ); + _.assert( _.strIs( filePath ) || filePath === null ); + + if( filePath === null ) + return filePath; + if( !provider.originPath ) + return filePath; + if( provider.originPath === self.defaultOrigin ) + // if( provider instanceof _.FileProvider.Default && provider.originPath === self.defaultOrigin ) + return filePath; + if( _.strBegins( filePath, provider.originPath ) ) + return filePath; + + return path.join( provider.originPath, filePath ); +} + +// + +function pathNativizeAct( filePath ) +{ + let self = this; + let r = self._pathLocalize( self, filePath ); + r.localPath = r.provider.path.nativize( r.localPath ); + _.assert( 0, 'not implemented' ); + _.assert( _.object.isBasic( r.provider ), 'No provider for path', filePath ); + _.assert( arguments.length === 1 ); +} + +// + +function pathAllowedAct( filePath ) +{ + let self = this; + let r = self._pathLocalize( filePath ); + return r.provider.pathAllowedAct( r.localPath ); +} + +// + +/** + @summary Returns current working directory of default provider. + @description Changes current working directory if new path is provided. + @function pathCurrentAct + @class wTools.FileProvider.wFileSystem + @namespace wTools.FileProvider + @module Tools/mid/Files +*/ + +function pathCurrentAct() +{ + let self = this; + + if( self.defaultProvider ) + return self.defaultProvider.path.current.apply( self.defaultProvider.path, arguments ); + + _.assert( 0, 'Default provider is not set for the ', self.qualifiedName ); +} + +// + +function pathDirTempAct() +{ + let self = this; + + if( self.defaultProvider ) + return self.defaultProvider.path.dirTemp.apply( self.defaultProvider.path, arguments ); + + _.assert( 0, 'Default provider is not set for the ', self.qualifiedName ); +} + +// + +function pathNativizeAct( filePath ) +{ + let self = this; + let r = self._pathLocalize( filePath ); + if( r && r.provider ) + return r.provider.pathNativizeAct.call( r.provider, r.localPath ); + if( self.defaultProvider ) + return self.defaultProvider.path.dirTemp.apply( self.defaultProvider.path, arguments ); + return filePath; +} + +// + +function pathResolveLinkFull_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let r = self._pathLocalize( o.filePath ); + o.filePath = r.localPath; + + let result = r.provider.pathResolveLinkFull.body.call( r.provider, o ); + + if( o.sync ) + { + return handleResult( result ); + } + else + { + result.then( handleResult ); + return result; + } + + /* */ + + function handleResult( result ) + { + if( result === null ) + return null; + + // xxx + result.filePath = self._pathPrepend( r.provider, result.filePath ); + result.relativePath = self._pathPrepend( r.provider, result.relativePath ); + result.absolutePath = self._pathPrepend( r.provider, result.absolutePath ); + + // result.filePath = self.path.join( r.provider.originPath, result.filePath ); + // result.relativePath = self.path.join( r.provider.originPath, result.relativePath ); + // result.absolutePath = self.path.join( r.provider.originPath, result.absolutePath ); + + /* xxx : qqq : cover pathResolveLinkFull, take into account all branches of _pathPrepend. use: + + a.fileProvider = _.FileProvider.System({ providers : [] }); + _.FileProvider.Git().providerRegisterTo( a.fileProvider ); + _.FileProvider.Npm().providerRegisterTo( a.fileProvider ); + _.FileProvider.Http().providerRegisterTo( a.fileProvider ); + let defaultProvider = _.FileProvider.Default(); + defaultProvider.providerRegisterTo( a.fileProvider ); + a.fileProvider.defaultProvider = defaultProvider; + + */ + + return result; + } +} + +// _.assert( _.entity.identicalShallow( Parent.prototype.pathResolveLinkFull.body.defaults, Parent.prototype.pathResolveLinkFull.defaults ) ); +_.routineExtend( pathResolveLinkFull_body, Parent.prototype.pathResolveLinkFull.body ); + +let pathResolveLinkFull = _.routine.uniteCloning_replaceByUnite( Parent.prototype.pathResolveLinkFull.head, pathResolveLinkFull_body ); + +// + +function pathResolveLinkTail_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let r = self._pathLocalize( o.filePath ); + o.filePath = r.localPath; + + let result = r.provider.pathResolveLinkTail.body.call( r.provider, o ); + + if( result === null ) + return null; + + if( result.filePath === null ) + return null; + + result.filePath = self._pathPrepend( r.provider, result.filePath ); + result.absolutePath = self._pathPrepend( r.provider, result.absolutePath ); + + // result.filePath = self.path.join( r.provider.originPath, result.filePath ); + // result.absolutePath = self.path.join( r.provider.originPath, result.absolutePath ); + /* qqq : cover pathResolveLinkTail, take into account all branches of _pathPrepend */ + + return result; +} + +_.routineExtend( pathResolveLinkTail_body, Parent.prototype.pathResolveLinkTail.body ); + +let pathResolveLinkTail = _.routine.uniteCloning_replaceByUnite( Parent.prototype.pathResolveLinkTail.head, pathResolveLinkTail_body ); + +// + +function pathResolveSoftLink_body( o ) +{ + const self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + const filePath = o.filePath; + const r = self._pathLocalize( o.filePath ); + + o.filePath = r.localPath; + + let result = r.provider.pathResolveSoftLink.body.call( r.provider, o ); + + if( result === null ) + return result; + + _.assert( !!result ); + + result = self._pathPrepend( r.provider, result ); /* qqq : cover pathResolveSoftLink, take into account all branches of _pathPrepend */ + // result = self.path.join( r.provider.originPath, result ); + + if( result === filePath ) + // if( result === o.filePath ) + { + // _.assert( 0, 'not tested' ); + return r.originalPath; + } + + return result; +} + +_.routineExtend( pathResolveSoftLink_body, Parent.prototype.pathResolveSoftLink.body ); + +let pathResolveSoftLink = _.routine.uniteCloning_replaceByUnite( Parent.prototype.pathResolveSoftLink.head, pathResolveSoftLink_body ); + +// + +function pathResolveTextLink_body( o ) +{ + const self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + const filePath = o.filePath; + const r = self._pathLocalize( o.filePath ); + + o.filePath = r.localPath; + + let result = r.provider.pathResolveTextLink.body.call( r.provider, o ); + + if( result === null ) + return result; + + _.assert( !!result ); + + result = self._pathPrepend( r.provider, result ); + // result = self.path.join( r.provider.originPath, result ); + /* qqq : cover pathResolveTextLink, take into account all branches of _pathPrepend */ + + // if( result === o.filePath ) + if( result === filePath ) + { + // _.assert( 0, 'not tested' ); + return r.originalPath; + } + + return result; +} + +_.routineExtend( pathResolveTextLink_body, Parent.prototype.pathResolveTextLink.body ); + +let pathResolveTextLink = _.routine.uniteCloning_replaceByUnite( Parent.prototype.pathResolveTextLink.head, pathResolveTextLink_body ); + +// + +function fileRead_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + + o.filePath = self.pathResolveLinkFull + ({ + filePath : o.filePath, + resolvingSoftLink : o.resolvingSoftLink, + resolvingTextLink : o.resolvingTextLink, + }); + + o.filePath = o.filePath.absolutePath; + + let r = self._pathLocalize( o.filePath ); + let o2 = _.props.extend( null, o ); + + o2.resolvingSoftLink = 0; + o2.filePath = r.localPath; + let result = r.provider.fileRead.body.call( r.provider, o2 ); + + return result; +} + +_.routineExtend( fileRead_body, Parent.prototype.fileRead.body ); + +const fileRead = _.routine.uniteCloning_replaceByUnite( Parent.prototype.fileRead.head, fileRead_body ); + +// -- +// linker +// -- + +function _link_functor( fop ) +{ + fop = _.routine.options_( _link_functor, arguments ); + + let routine = fop.routine; + let routineName = routine.name; + let allowingMissedSrc = fop.allowingMissedSrc; + + _.assert( _.routineIs( fop.onDifferentProviders ) || _.boolIs( fop.onDifferentProviders ) ); + _.assert( _.strDefined( routineName ) ); + _.assert( _.object.isBasic( routine.defaults ) ); + _.assert( routine.paths === undefined ); + _.assert( _.object.isBasic( routine.having ) ); + + _.routineExtend( hubLink, routine ); + + if( fop.onDifferentProviders === true ) + fop.onDifferentProviders = function handleDifferentProviders( op ) + { + } + + let onDifferentProviders = fop.onDifferentProviders; + let defaults = hubLink.defaults; + + _.assert( defaults.srcPath !== undefined ); + _.assert( defaults.dstPath !== undefined ); + + return hubLink; + + /* */ + + function hubLink( o ) + { + let self = this; + let op = Object.create( null ); + op.continue = true; + op.options = _.props.extend( null, o ); + op.routineName = routineName; + op.end = function end() + { + op.continue = false; + return op.result; + } + + _.assert( arguments.length === 1, 'Expects single argument' ); + + /* */ + + // op.originalDst = self._pathLocalize( op.options.originalDstPath ); + // if( allowingMissedSrc ) + // op.originalSrc = self._pathLocalizeMaybe( op.options.originalSrcPath ); + // else + // op.originalSrc = self._pathLocalize( op.options.originalSrcPath ); + // + // _.assert( !!op.originalDst.provider, 'No provider for path', op.options.originalDstPath ); + // _.assert( allowingMissedSrc || !!op.originalSrc.provider, 'No provider for path', op.options.originalSrcPath ); + // + // op.options.originalDstPath = op.originalDst.localPath; + // + // if( op.originalDst.provider !== op.originalSrc.provider ) + // { + // } + // else + // { + // op.options.originalSrcPath = op.originalSrc.localPath; + // } + + /* */ + + // op.relativeDst = self._pathLocalize( op.options.relativeDstPath ); + // if( allowingMissedSrc ) + // op.relativeSrc = self._pathLocalizeMaybe( op.options.relativeSrcPath ); + // else + // op.relativeSrc = self._pathLocalize( op.options.relativeSrcPath ); + + op.relativeDst = self._pathLocalizeMaybe( op.options.relativeDstPath ); + op.relativeSrc = self._pathLocalizeMaybe( op.options.relativeSrcPath ); + + if( !op.relativeSrc.provider && op.relativeDst.provider ) + self._pathRelocalize( op.relativeSrc, op.relativeDst.provider ); + if( op.relativeSrc.provider && !op.relativeDst.provider ) + self._pathRelocalize( op.relativeDst, op.relativeSrc.provider ); + + if( op.relativeDst.provider.pathMocking && op.relativeDst.provider.pathMock !== undefined ) + op.relativeDst.localPath = op.relativeDst.provider.pathMock( op.relativeDst.localPath ); + + _.assert( !!op.relativeDst.provider, 'No provider for path', op.options.relativeDstPath ); + _.assert( allowingMissedSrc || !!op.relativeSrc.provider, 'No provider for path', op.options.relativeSrcPath ); + + /* */ + + op.dst = self._pathLocalizeMaybe( op.options.dstPath ); + op.src = self._pathLocalizeMaybe( op.options.srcPath ); + + if( !op.src.provider && op.dst.provider ) + self._pathRelocalize( op.src, op.dst.provider ); + if( op.src.provider && !op.dst.provider ) + self._pathRelocalize( op.dst, op.src.provider ); + + if( op.dst.provider.pathMocking && op.relativeDst.provider.pathMock !== undefined ) + op.dst.localPath = op.dst.provider.pathMock( op.dst.localPath ); + + _.assert( !!op.dst.provider, 'No provider for path', op.options.dstPath ); + _.assert( allowingMissedSrc || !!op.src.provider, 'No provider for path', op.options.srcPath ); + + /* */ + + op.options.dstPath = op.dst.localPath; + op.options.relativeDstPath = op.relativeDst.localPath; + + if( op.dst.provider !== op.src.provider ) + { + op.options.relativeDstPath = op.options.dstPath; + op.options.relativeSrcPath = op.options.srcPath; + + if( onDifferentProviders ) + { + onDifferentProviders.call( self, op ); + if( !op.continue ) + return op.result; + } + else + { + throw _.err( 'Cant ' + routineName + ' files of different file providers :\n' + op.options.dstPath + '\n' + op.options.srcPath ); + } + } + else + { + op.options.srcPath = op.src.localPath; + op.options.relativeSrcPath = op.relativeSrc.localPath; + } + + op.result = op.dst.provider[ routineName ]( op.options ); + return op.end(); + } + +} + +_link_functor.defaults = +{ + routine : null, + onDifferentProviders : false, + allowingMissedSrc : false, +} + +// + +let hardLinkAct = _link_functor({ routine : Parent.prototype.hardLinkAct }); +let fileRenameAct = _link_functor({ routine : Parent.prototype.fileRenameAct }); + +let softLinkAct = _link_functor +({ + routine : Parent.prototype.softLinkAct, + onDifferentProviders : true, + allowingMissedSrc : true, +}); +let textLinkAct = _link_functor +({ + routine : Parent.prototype.textLinkAct, + onDifferentProviders : true, + allowingMissedSrc : true, +}); + +// + +function _fileCopyActDifferent( op ) +{ + let self = this; + let path = self.path; + let o = op.options; + + if( op.src.provider.isTextLink( op.src.localPath ) ) + { + _.assert( 0, 'Expects terminal file, not text link' ); + } + + if( op.src.provider.isSoftLink( op.src.localPath ) ) + { + _.assert( 0, 'Expects terminal file, not soft link' ); + // let resolvedPath = op.src.provider.pathResolveSoftLink( op.src.localPath ); + // c.result = op.dst.provider.softLink + // ({ + // dstPath : op.dst.localPath, + // srcPath : path.join( op.src.parsedPath.origin, resolvedPath ), + // sync : o.sync, + // allowingMissed : 1, + // }); + // return op.end(); + } + + /* + for extract resolving should be on + otherwise extract does not resolve intermediate directories + */ + + let read = null; + if( op.src.provider._fileCopyPrepare ) + read = op.src.provider._fileCopyPrepare({ dstProvider : op.dst.provider, srcProvider : op.src.provider, options : o, data : read }); + if( op.dst.provider._fileCopyPrepare ) + read = op.dst.provider._fileCopyPrepare({ dstProvider : op.dst.provider, srcProvider : op.src.provider, options : o, data : read }); + + if( read === null ) + read = op.src.provider.fileRead + ({ + filePath : op.src.localPath, + resolvingTextLink : 1, + resolvingSoftLink : 1, + encoding : 'meta.original', + sync : o.sync, + }); + + if( o.sync ) + { + op.result = op.dst.provider.fileWrite + ({ + filePath : op.dst.localPath, + data : read, + encoding : 'meta.original', + }); + + dstPathValidate(); + } + else + { + op.result = read.then( ( read ) => + { + return op.dst.provider.fileWrite + ({ + filePath : op.dst.localPath, + data : read, + sync : 0, + encoding : 'meta.original', + }); + }) + .then( ( arg ) => + { + dstPathValidate(); + return arg; + }) + } + + return op.end(); + + /* */ + + function dstPathValidate() + { + if( op.dst.provider.pathMocking !== undefined ) + if( !op.dst.provider.fileExists( op.dst.localPath ) ) + op.options.context.options.dstPath = op.dst.provider.pathUnmock( op.dst.localPath, 1 ); + } +} + +let fileCopyAct = _link_functor +({ + routine : Parent.prototype.fileCopyAct, + onDifferentProviders : _fileCopyActDifferent, +}); + +// -- +// link +// -- + +function hardLinkBreak_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let r = self._pathLocalize( o.filePath ); + let o2 = _.props.extend( null, o ); + + o2.filePath = r.localPath; + + return r.provider.hardLinkBreak.body.call( r.provider, o2 ); +} + +_.routineExtend( hardLinkBreak_body, Parent.prototype.hardLinkBreak.body ); + +let hardLinkBreak = _.routine.uniteCloning_replaceByUnite( Parent.prototype._preFilePathScalarWithProviderDefaults, hardLinkBreak_body ); + +// + +function areHardLinkedAct( o ) +{ + let self = this; + + _.routine.assertOptions( areHardLinkedAct, arguments ); + _.assert( o.filePath.length === 2, 'Expects exactly two arguments' ); + + let dst = self._pathLocalize( o.filePath[ 0 ] ); + let src = self._pathLocalize( o.filePath[ 1 ] ); + + _.assert( !!dst.provider, 'No provider for path', o.filePath[ 0 ] ); + _.assert( !!src.provider, 'No provider for path', o.filePath[ 1 ] ); + + if( dst.provider !== src.provider ) + return false; + + return dst.provider.areHardLinkedAct({ filePath : [ dst.localPath, src.localPath ] }); +} + +_.routineExtend( areHardLinkedAct, Parent.prototype.areHardLinkedAct ); + +// + +function dirMake_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + + let r = self._pathLocalize( o.filePath ); + let o2 = _.props.extend( null, o ); + o2.filePath = r.localPath; + return r.provider.dirMake.body.call( r.provider, o2 ); +} + +_.routineExtend( dirMake_body, Parent.prototype.dirMake.body ); + +let dirMake = _.routine.uniteCloning_replaceByUnite( Parent.prototype.dirMake.head, dirMake_body ); + +// -- +// accessor +// -- + +function _preferredProviderGet( src ) +{ + let self = this; + _.assert( arguments.length === 0 ); + return self.defaultProvider; +} + +// + +function _defaultProviderGet( src ) +{ + let self = this; + _.assert( arguments.length === 0 ); + return self[ defaultProviderSymbol ]; +} + +// + +function _defaultProviderSet( src ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( src ) + { + _.assert( src instanceof _.FileProvider.Abstract ); + self[ defaultProviderSymbol ] = src; + self[ defaultProtocolSymbol ] = src.protocol; + self[ defaultOriginSymbol ] = src.originPath; + self.UsingBigIntForStat = src.UsingBigIntForStat; + } + else + { + _.assert( src === null ) + self[ defaultProviderSymbol ] = null; + self[ defaultProtocolSymbol ] = null; + self[ defaultOriginSymbol ] = null; + } + +} + +// + +function _defaultProtocolSet( src ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( src ) + { + _.assert( _.strIs( src ) ); + self[ defaultProtocolSymbol ] = src; + self[ defaultOriginSymbol ] = src + '://'; + } + else + { + _.assert( src === null ) + self[ defaultProtocolSymbol ] = null; + self[ defaultOriginSymbol ] = null; + } + +} + +// + +function _defaultOriginSet( src ) +{ + let self = this; + let path = self.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( src ) + { + _.assert( _.strIs( src ) ); + _.assert( path.isGlobal( src ) ); + let protocol = _.strRemoveEnd( src, '://' ); + _.assert( !path.isGlobal( protocol ) ); + self[ defaultProtocolSymbol ] = protocol; + self[ defaultOriginSymbol ] = src; + } + else + { + _.assert( src === null ) + self[ defaultProtocolSymbol ] = null; + self[ defaultOriginSymbol ] = null; + } + +} + +// // +// +// function _verbosityChange() +// { +// let self = this; +// +// _.assert( arguments.length === 0, 'Expects no arguments' ); +// +// for( var f in self.providersWithProtocolMap ) +// { +// const fileProvider = self.providersWithProtocolMap[ f ]; +// fileProvider.verbosity = self.verbosity; +// } +// +// } + +// -- +// meta +// -- + +function _Setup1() +{ + let self = this; + + let KnownRoutineFields = + { + name : null, + head : null, + body : null, + defaults : null, + // paths : null, + having : null, + encoders : null, + operates : null, + vectorized : null, + } + + for( let r in Parent.prototype ) (function() + { + let name = r; + let original = Parent.prototype[ r ]; + + if( !original ) + return; + + var having = original.having; + + if( !having ) + return; + + _.assert( !!original ); + _.map.assertHasOnly( original, KnownRoutineFields ); + + if( having.hubRedirecting === 0 || having.hubRedirecting === false ) + return; + + if( !having.driving ) + return; + + if( having.kind === 'path' ) + return; + + if( having.kind === 'inter' ) + return; + + if( having.kind === 'record' ) + return; + + if( having.aspect === 'body' ) + return; + + if( original.defaults ) + _.assert( _.object.isBasic( original.operates ) ); + if( original.operates ) + _.assert( _.object.isBasic( original.defaults ) ); + + let hubResolving = having.hubResolving; + let havingBare = having.driving; + var operates = original.operates; + let operatesLength = operates ? _.props.keys( operates ).length : 0; + let head = original.head; + let body = original.body; + + /* */ + + function resolve( o ) + { + let self = this; + let provider = self; + let filePath; + + for( let p in operates ) + if( o[ p ] ) + { + if( operatesLength === 1 ) + { + let r; + + if( hubResolving ) + o[ p ] = self.pathResolveLinkFull + ({ + filePath : o[ p ], + resolvingSoftLink : o.resolvingSoftLink || false, + resolvingTextLink : o.resolvingTextLink || false, + }); + + if( operates[ p ].allowingMissed ) + r = self._pathLocalizeMaybe( o[ p ] ); + else + r = self._pathLocalize( o[ p ] ); + + filePath = o[ p ]; + provider = r.provider; + o[ p ] = r.localPath; + + } + else + { + if( o[ p ] instanceof _.files.FileRecord ) + continue; + + o[ p ] = self.path.preferredFromGlobal( o[ p ] ); + } + } + + _.assert( _.object.isBasic( provider ), 'No provider for path', filePath ); + return provider; + } + + /* */ + + let _routine = + { + [ r + 'System' ] : function( o ) + { + let self = this; + + if( arguments.length === 1 && wrap.defaults ) + { + if( _.strIs( o ) ) + o = { filePath : o } + } + + if( head ) + o = head.call( this, wrap, arguments ); + + let o2 = _.props.extend( null, o ); + + if( !head && wrap.defaults ) + if( !wrap.having || !wrap.having.driving ) + _.routine.options_( wrap, o2 ); + + let provider = self; + + provider = resolve.call( self, o2 ); + + if( provider === self ) + { + _.assert( _.routineIs( original ), 'No original method for', name ); + return original.call( provider, o2 ); + } + else + { + _.assert( _.routineIs( provider[ name ] ) ); + return provider[ name ].call( provider, o2 ); + } + } + } + + let wrap = Routines[ r ] = _routine[ r + 'System' ]; + _.routineExtend( wrap, original ); + + })(); + +} + +// + +function Init() +{ + + _.mapExtendDstNotOwn( Self.prototype, FilteredRoutines ); + + let missingMap = Object.create( null ); + for( let r in Routines ) + { + _.assert( !!Self.prototype[ r ], 'routine', r, 'does not exist in prototype' ); + if( !_.mapOnlyOwnKey( Self.prototype, r ) && Routines[ r ] !== Self.prototype[ r ] ) + missingMap[ r ] = 'Routines.' + r; + } + + _.assert + ( + !_.props.keys( missingMap ).length > 0, + () => 'Routine(s) were not written into Extension explicitly\n' + + _.entity.exportString( missingMap, { stringWrapper : '' } ) + ); + _.assert( !FilteredRoutines.pathResolveLinkFull ); + _.assert( !( 'pathResolveLinkFull' in FilteredRoutines ) ); + _.map.assertHasNoUndefine( FilteredRoutines ); + _.map.assertHasNoUndefine( Extension ); + _.map.assertHasNoUndefine( Self ); + _.assert( _.prototype.has( Self.prototype.Path, _.uri ) ); + _.assert( Self.Path === Self.prototype.Path ); +} + +// + +_Setup1(); + +// + +let FilteredRoutines = +{ + + // path + + pathResolveSoftLinkAct : Routines.pathResolveSoftLinkAct, + pathResolveTextLinkAct : Routines.pathResolveTextLinkAct, + + // read + + fileReadAct : Routines.fileReadAct, + streamReadAct : Routines.streamReadAct, + hashReadAct : Routines.hashReadAct, + dirReadAct : Routines.dirReadAct, + statReadAct : Routines.statReadAct, + fileExistsAct : Routines.fileExistsAct, + rightsReadAct : Routines.rightsReadAct, + + // write + + fileWriteAct : Routines.fileWriteAct, + streamWriteAct : Routines.streamWriteAct, + timeWriteAct : Routines.timeWriteAct, + fileDeleteAct : Routines.fileDeleteAct, + dirMakeAct : Routines.dirMakeAct, + rightsWriteAct : Routines.rightsWriteAct, + + // lock + + fileLockAct : Routines.fileLockAct, + fileUnlockAct : Routines.fileUnlockAct, + fileIsLockedAct : Routines.fileIsLockedAct, + + // link + + hardLinkBreakAct : Routines.hardLinkBreakAct, + softLinkBreakAct : Routines.softLinkBreakAct, + + filesCanBeSame : Routines.filesCanBeSame, + filesAreSameForSure : Routines.filesAreSameForSure + +} + +// -- +// path +// -- + +let Path = _.uri.CloneExtending({ fileProvider : Self }); +_.assert( _.prototype.has( Path, _.uri ) ); + +// -- +// relations +// -- + +let defaultProviderSymbol = Symbol.for( 'defaultProvider' ); +let defaultProtocolSymbol = Symbol.for( 'defaultProtocol' ); +let defaultOriginSymbol = Symbol.for( 'defaultOrigin' ); + +/** + * @typedef {Object} Fields + * @property {String} defaultProtocol + * @property {Object} providersWithProtocolMap={} + * @property {Object} defaultProvider + * @property {Boolean} safe=0 + * @class wFileSystem + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +/** + * @typedef {Object} Medials + * @property {Boolean} empty=0 + * @property {Object[]} providers + * @property {String} defaultOrigin + * @class wFileSystem + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +let Composes = +{ + + defaultProtocol : null, + providersWithProtocolMap : _.define.own({}), + + safe : 0, + +} + +let Aggregates = +{ +} + +let Associates = +{ + defaultProvider : null, +} + +let Restricts = +{ +} + +let Medials = +{ + empty : 0, + providers : null, + defaultOrigin : null, +} + +let Accessors = +{ + defaultProvider : 'defaultProvider', + defaultProtocol : 'defaultProtocol', + defaultOrigin : 'defaultOrigin', + preferredProvider : { get : _preferredProviderGet, set : false, combining : 'rewrite' }, +} + +let Statics = +{ + Path, +} + +let Forbids = +{ + providersWithOriginMap : 'providersWithOriginMap', +} + +// -- +// declare +// -- + +let Extension = +{ + + init, + + // provider + + providerDefaultSet, + providerRegister, + providerUnregister, + providersRegister, + providerForPath, + protocolNameGenerate, + hasProvider, + + // adapter + + _recordFactoryFormEnd, + _recordFormBegin, + // _recordPathForm, + _recordFormEnd, + + _recordAbsoluteGlobalMaybeGet, + _recordRealGlobalMaybeGet, + + fieldPush, + fieldPop, + + // path + + preferredFromGlobalAct, + _pathLocalize, + _pathLocalizeMaybe, + _pathRelocalize, + _pathPrepend, + + pathCurrentAct, + pathDirTempAct, + pathNativizeAct, + pathAllowedAct, + + pathResolveLinkFull, + pathResolveLinkTail, + pathResolveSoftLink, + pathResolveTextLink, + + // read + + fileRead, + + // linker + + _link_functor, + + hardLinkAct, + fileRenameAct, + + softLinkAct, + textLinkAct, + + fileCopyAct, + + // link + + hardLinkBreak, + + areHardLinkedAct, + + // + + dirMake, + + // accessor + + _preferredProviderGet, + _defaultProviderGet, + _defaultProviderSet, + _defaultProtocolSet, + _defaultOriginSet, + + // + + Composes, + Aggregates, + Associates, + Restricts, + Medials, + Accessors, + Statics, + Forbids, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Extension, +}); + +Init(); + +// -- +// export +// -- + +_.FileProvider[ Self.shortName ] = Self; + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l6/System.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l6' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, System_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file System_s */ })(); + +/* */ /* begin of file ConfigMixin_s */ ( function ConfigMixin_s() { function ConfigMixin_s_naked() { ( function _ConfigMixin_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const FileRecord = _.files.FileRecord; +const Abstract = _.FileProvider.Abstract; +const Partial = _.FileProvider.Partial; +const Find = _.FileProvider.FindMixin; +const fileRead = Partial.prototype.fileRead; + +_.assert( _.entity.lengthOf( _.files.ReadEncoders ) > 0 ); +_.assert( _.routineIs( _.files.FileRecord ) ); +_.assert( _.routineIs( Abstract ) ); +_.assert( _.routineIs( Partial ) ); +_.assert( _.routineIs( Find ) ); +_.assert( _.routineIs( fileRead ) ); + +// + +/** + @classdesc Mixin to add operations on group of files with very specific purpose. For example, it has a method to search for text in files. + @class wFileProviderConfigMixin + @namespace wTools.FileProvider + @module Tools/mid/Files +*/ + +const Parent = null; +const Self = wFileProviderConfigMixin; +function wFileProviderConfigMixin( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'ConfigMixin'; + +// -- +// read +// -- + +// function configRead2( o ) +// { +// +// let self = this; +// o = o || Object.create( null ); +// +// if( _.strIs( o ) ) +// { +// o = { name : o || null }; +// } +// +// if( o.dir === undefined ) +// o.dir = self.path.normalize( self.path.effectiveMainDir() ); +// +// if( o.result === undefined ) +// o.result = Object.create( null ); +// +// _.routine.options_( configRead2, o ); +// +// if( !o.name ) +// { +// o.name = 'config'; +// self._configRead2( o ); +// o.name = 'public'; +// self._configRead2( o ); +// o.name = 'private'; +// self._configRead2( o ); +// } +// else +// { +// self._configRead2( o ); +// } +// +// return o.result; +// } +// +// configRead2.defaults = +// { +// name : null, +// dir : null, +// result : null, +// } +// +// var having = configRead2.having = Object.create( null ); +// +// having.writing = 0; +// having.reading = 1; +// having.driving = 0; +// +// // +// +// function _configRead2( o ) /* zzz : remove? */ +// { +// let self = this; +// let read; +// +// // _.include( 'wProcess' ); +// +// if( o.name === undefined ) +// o.name = 'config'; +// +// let terminal = self.path.join( o.dir, o.name ); +// +// /**/ +// +// if( typeof Coffee !== 'undefined' ) +// { +// let fileName = terminal + '.coffee'; +// if( self.statResolvedRead( fileName ) ) +// { +// +// read = self.fileReadSync( fileName ); +// read = Coffee.eval( read, +// { +// filename : fileName, +// }); +// _.props.extend( o.result, read ); +// +// } +// } +// +// /**/ +// +// let fileName = terminal + '.json'; +// if( self.statResolvedRead( fileName ) ) +// { +// +// read = self.fileReadSync( fileName ); +// read = JSON.parse( read ); +// _.props.extend( o.result, read ); +// +// } +// +// /**/ +// +// fileName = terminal + '.s'; +// if( self.statResolvedRead( fileName ) ) +// { +// +// debugger; +// read = self.fileReadSync( fileName ); +// read = _.exec( read ); +// _.props.extend( o.result, read ); +// +// } +// +// return o.result; +// } +// +// _configRead2.defaults = configRead2.defaults; + +// + +/** + * @description Finds config files that have name of files from `o.filePath`. + * Mixes name of files from `o.filePath` with different extensions to find config files that can be read by availbale read encoders. + * Returns results as array or map. + * @param {Object} o Options map. + * @param {Array|String} o.filePath Source paths. + * @param {String} o.outputFormat='array', Possible formats: array, map. + * @function configFind + * @class wFileProviderConfigMixin + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +/* +qqq : cover configFind +*/ + +function configFind_body( o ) +{ + let self = this; + let path = self.path; + let result = o.outputFormat === 'array' ? [] : Object.create( null ); + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.longHas( [ 'array', 'map' ], o.outputFormat ) ); + + let exts = Object.create( null ); + + // debugger; + // let encoders = _.files.encoder.deduce({ feature : { reader : true }, single : 0 }); + // debugger; + + for( let e in _.files.ReadEncoders ) + { + let encoder = _.files.ReadEncoders[ e ]; + if( encoder === null ) + continue; + _.assert( _.object.is( encoder ), `Read encoder ${e} is missing` ); + if( encoder.exts ) + { + for( let s = 0 ; s < encoder.exts.length ; s++ ) + exts[ encoder.exts[ s ] ] = e; + } + } + + o.filePath = _.array.as( o.filePath ); + _.assert( _.strsAreAll( o.filePath ) ); + + /* */ + + _.each( exts, ( encoderName, ext ) => + { + _.each( o.filePath, ( filePath ) => + { + _.assert( _.strIs( ext ) ); + _.assert( _.strIs( filePath ) ); + let filePath2 = _.strAppendOnce( filePath, '.' + ext ); + if( self.statRead( filePath2 ) ) + { + let element = + { + particularPath : filePath2, + abstractPath : filePath, + encoding : exts[ ext ], + ext, + } + if( o.outputFormat === 'array' ) + { + result.push( element ); + } + else + { + _.sure( result[ filePath ] === undefined, () => 'Several configs exists for ' + _.strQuote( filePath ) ); + result[ filePath ] = element; + } + } + }); + }); + + /* */ + + return result; +} + +var defaults = configFind_body.defaults = Object.create( null ); +defaults.filePath = null; +defaults.outputFormat = 'array'; +// defaults.recursive = 1; + +let configFind = _.routine.uniteCloning_replaceByUnite( Partial.prototype._preFilePathVectorWithProviderDefaults, configFind_body ); + +// + +// function _fileRead_head( routine, args ) +// { +// let self = this; +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// _.assert( args && args.length === 1 ); +// +// let o = args[ 0 ]; +// +// if( self.path.like( o ) ) +// o = { filePath : self.path.from( o ) }; +// +// _.routine.options_( routine, o ); +// +// o.filePath = self.path.normalize( o.filePath ); +// +// _.assert( self.path.isAbsolute( o.filePath ), 'Expects absolute path {-o.filePath-}, but got', o.filePath ); +// +// if( o.verbosity === null ) +// o.verbosity = _.numberClamp( self.verbosity - 4, 0, 9 ); +// +// self._providerDefaultsApply( o ); +// +// return o; +// } + +// + +/* +qqq : add test +*/ + +/** + * @summary Read config files one by one and extends result with fields from each config file. + * @description Finds config files if they were not provided through option `o.found`. + * @param {Object} o Options map. + * @param {Array|String} o.filePath Source paths. + * @param {Array|Object} o.found Container to store found config files. + * @param {String} o.many='all' Checks if each of files `o.filePath` have at least one config file. + * @function configRead + * @class wFileProviderConfigMixin + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function configRead_body( o ) +{ + let self = this; + let result = null; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.longHas( [ 'all', 'any' ], o.many ) ); + + if( !o.found ) + o.found = self.configFind({ filePath : o.filePath }); + + /* */ + + if( o.many === 'all' ) + { + let filePath = _.array.as( o.filePath ).slice(); + let found = o.found.slice(); + + for( let f1 = filePath.length-1 ; f1 >= 0 ; f1-- ) + { + let filePath1 = filePath[ f1 ]; + for( let f2 = found.length-1 ; f2 >= 0 ; f2-- ) + if( found[ f2 ].abstractPath === filePath1 || found[ f2 ].particularPath === filePath1 ) + { + filePath.splice( f1, 1 ); + found.splice( f2, 1 ); + continue; + } + } + + for( let f1 = filePath.length-1 ; f1 >= 0 ; f1-- ) + { + let filePath1 = filePath[ f1 ]; + //debugger; + if( !o.throwing && o.throwing !== null && o.throwing !== undefined ) + return null; + throw _.err( 'None config was found\n', _.strQuote( filePath1 ) ); + } + + for( let f2 = found.length-1 ; f2 >= 0 ; f2-- ) + { + debugger; + if( !o.throwing && o.throwing !== null && o.throwing !== undefined ) + return null; + throw _.err( 'Some configs were loaded several times\n', _.strQuote( found[ f2 ].particularPath ) ); + } + + } + + /* */ + + if( o.found && o.found.length ) + { + + for( let f = 0 ; f < o.found.length ; f++ ) + { + let file = o.found[ f ]; + + let o2 = _.props.extend( null, o ); + o2.filePath = file.particularPath; + o2.encoding = file.encoding; + // if( o2.verbosity >= 2 ) + // o2.verbosity = 5; + delete o2.many; + delete o2.found; + + let read = self.fileRead( o2 ); + + if( read === undefined ) + read = Object.create( null ); + + _.sure( _.mapIs( read ), () => 'Expects map, but read ' + _.entity.exportStringDiagnosticShallow( result ) + ' from ' + o2.filePath ); + + if( result === null ) + result = read; + else + result = _.mapExtendRecursive( result, read ); + + } + + } + + /* */ + + if( result === null || result === undefined ) + { + debugger; + if( o.throwing ) + throw _.err( 'Found no config at', () => o.filePath + '.*' ); + result = null; + } + + /* */ + + return result; +} + +_.routineExtend( configRead_body, fileRead.body ); + +var defaults = configRead_body.defaults; + +defaults.encoding = null; +defaults.many = 'all'; +defaults.found = null; + +// + +var configRead = _.routine.uniteCloning_replaceByUnite( Partial.prototype._preFilePathVectorWithProviderDefaults, configRead_body ); + +configRead.having.aspect = 'entry'; + +// + +function configUserPath( o ) +{ + let self = this; + let path = self.path; + + if( !_.mapIs( o ) ) + o = { name : o || configUserPath.defaults.name } + + o = _.routine.options_( configUserPath, o ); + _.assert( _.strDefined( o.name ) ); + + if( o.filePath ) + return o.filePath; + + let userPath = path.dirUserHome(); + o.filePath = path.join( userPath, o.dirPath, o.name ); + + return o.filePath; +} + +configUserPath.defaults = +{ + filePath : null, + dirPath : '.', + name : '.wenv.yml', +} + +// + +function configUserRead( o ) +{ + let self = this; + let path = self.path; + + if( !_.mapIs( o ) ) + o = { name : o || configUserRead.defaults.name } + + o = _.routine.options_( configUserRead, o ); + + let o2 = _.mapOnly_( null, o, self.configUserPath.defaults ); + let filePath = self.configUserPath( o2 ); + + if( !self.fileExists( filePath ) ) + return null; + + if( o.locking ) + self.configUserLock({ filePath }); + + return self.configRead + ({ + filePath, + throwing : 0, + }); + +} + +configUserRead.defaults = +{ + ... configUserPath.defaults, + locking : 0, +} + +// + +function configUserWrite( o ) +{ + let self = this; + let path = self.path; + + if( !_.mapIs( o ) ) + o = { name : arguments[ 0 ], structure : ( arguments.length > 1 ? arguments[ 1 ] : null ) } + o = _.routine.options_( configUserWrite, o ); + _.assert( o.structure !== null ); + + let o2 = _.mapOnly_( null, o, self.configUserPath.defaults ); + let filePath = self.configUserPath( o2 ); + + /* qqq : cover option encoding of method fileWrite */ + /* qqq : cover encoding : _.unknown of method fileWrite */ + let result = self.fileWrite + ({ + filePath, + data : o.structure, + encoding : _.unknown, + sync : 1, + }); + + _.assert( !_.consequenceLike( result ) ); + + if( o.unlocking ) + self.configUserUnlock({ filePath }); + + return result; +} + +configUserWrite.defaults = +{ + ... configUserPath.defaults, + structure : null, + unlocking : 0, +} + +// + +function configUserLock( o ) +{ + let self = this; + let path = self.path; + + if( !_.mapIs( o ) ) + o = { name : arguments[ 0 ] } + o = _.routine.options_( configUserLock, o ); + + let filePath = self.configUserPath( o ); + + return self.fileLock({ filePath }); +} + +configUserLock.defaults = +{ + ... configUserPath.defaults, +} + +// + +function configUserUnlock( o ) +{ + let self = this; + let path = self.path; + + if( !_.mapIs( o ) ) + o = { name : arguments[ 0 ] } + o = _.routine.options_( configUserUnlock, o ); + + let filePath = self.configUserPath( o ); + + return self.fileUnlock({ filePath }); +} + +configUserUnlock.defaults = +{ + ... configUserPath.defaults, +} + +// -- +// storage +// -- + +function storageNameFrom( o ) +{ + let self = this; + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageName : arguments[ 0 ] }; + o = _.routine.options_( storageNameFrom, o ); + + _.assert( _.strIs( o.storageDir ), 'Expects defined {- o.storageDir -}' ); + + return self.path.normalize( o.storageDir ); +} + +storageNameFrom.defaults = +{ + storageName : null, + storagePath : null, + storageDir : null, +} + +// + +function storagePathFrom( o ) +{ + let self = this; + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageName : arguments[ 0 ] }; + o = _.routine.options_( storagePathFrom, o ); + + if( o.storagePath === null ) + o.storagePath = self.configUserPath( o.storageName ); + + return o.storagePath; +} + +storagePathFrom.defaults = +{ + ... storageNameFrom.defaults, +} + +// + +function storageNameMapFrom( o ) +{ + let self = this; + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageName : arguments[ 0 ] }; + o = _.routine.options_( storageNameMapFrom, o ); + + if( o.storageName === null ) + o.storageName = self.storageNameFrom( o ); + if( o.storagePath === null ) + o.storagePath = self.storagePathFrom( o ); + + return o; +} + +storageNameMapFrom.defaults = +{ + ... storageNameFrom.defaults, +} + +// + +function storageRead( o ) +{ + let self = this; + try + { + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageDir : arguments[ 0 ] }; + o = _.routine.options_( storageRead, o ); + + _.assert( _.strIs( o.storageDir ), 'Expects defined {- o.storageDir -}' ); + + self.storageNameMapFrom( o ); + + if( !self.fileExists( o.storagePath ) ) + return null; + + let result = self.filesRead + ({ + filePath : self.path.join( o.storagePath, '**' ), + encoding : _.unknown, + }); + + return result.dataMap; + } + catch( err ) + { + throw _.err( err, `\nFailed to read storage::${o.storageName} at ${o.storagePath}` ); + } +} + +storageRead.defaults = +{ + ... storageNameMapFrom.defaults, +} + +// + +function storageDel( o ) +{ + let self = this; + + try + { + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageDir : arguments[ 0 ] }; + o = _.routine.options_( storageDel, o ); + + _.assert( _.strIs( o.storageDir ), 'Expects defined {- o.storageDir -}' ); + + let o2 = _.mapOnly_( null, o, self.storageNameMapFrom.defaults ); + self.storageNameMapFrom( o2 ); + _.props.extend( o, o2 ); + + if( self.fileExists( o.storagePath ) ) + self.filesDelete + ({ + filePath : o.storagePath, + verbosity : o.verbosity ? 3 : 0, + }); + + } + catch( err ) + { + throw _.err( err, `\nFailed to delete storage::${o.storageName} at ${o.storagePath}` ); + } + +} + +storageDel.defaults = +{ + ... storageNameMapFrom.defaults, + verbosity : 0, +} + +// + +function storageProfileNameFrom( o ) +{ + let self = this; + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageName : arguments[ 0 ] }; + o = _.routine.options_( storageProfileNameFrom, o ); + + _.assert( _.strIs( o.storageDir ), 'Expects defined {- o.storageDir -}' ); + _.assert( _.strIs( o.profileDir ), 'Expects defined {- o.profileDir -}' ); + + if( o.storageName === null ) + o.storageName = self.path.join + ( + o.storageDir, + o.profileDir, + ); + + return o.storageName; +} + +storageProfileNameFrom.defaults = +{ + storageDir : null, + profileDir : 'default', + storageName : null, + storagePath : null, +} + +// + +function storageProfilePathFrom( o ) +{ + let self = this; + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageName : arguments[ 0 ] }; + o = _.routine.options_( storageProfilePathFrom, o ); + + if( o.storagePath === null ) + o.storagePath = self.configUserPath( o.storageName ); + + return o.storagePath +} + +storageProfilePathFrom.defaults = +{ + ... storageProfileNameFrom.defaults, +} + +// + +function storageProfileNameMapFrom( o ) +{ + let self = this; + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageName : arguments[ 0 ] }; + o = _.routine.options_( storageProfileNameMapFrom, o ); + + if( o.storageName === null ) + o.storageName = self.storageProfileNameFrom( o ); + if( o.storagePath === null ) + o.storagePath = self.storageProfilePathFrom( o ); + + return o; +} + +storageProfileNameMapFrom.defaults = +{ + ... storageProfileNameFrom.defaults, +} + +// + +function storageProfileRead( o ) +{ + let self = this; + try + { + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageDir : arguments[ 0 ] }; + o = _.routine.options_( storageProfileRead, o ); + + _.assert( _.strIs( o.storageDir ), 'Expects defined {- o.storageDir -}' ); + _.assert( _.strIs( o.profileDir ), 'Expects defined {- o.profileDir -}' ); + + self.storageProfileNameMapFrom( o ); + + if( !self.fileExists( o.storagePath ) ) + return null; + + let result = self.filesRead + ({ + filePath : self.path.join( o.storagePath, '**' ), + encoding : _.unknown, + }); + + return result.dataMap; + } + catch( err ) + { + throw _.err( err, `\nFailed to read storage::${o.storageName} at ${o.storagePath}` ); + } +} + +storageProfileRead.defaults = +{ + ... storageProfileNameMapFrom.defaults, +} + +// + +function storageProfileDel( o ) +{ + let self = this; + + try + { + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageDir : arguments[ 0 ] }; + o = _.routine.options_( storageProfileDel, o ); + + _.assert( _.strIs( o.storageDir ), 'Expects defined {- o.storageDir -}' ); + _.assert( _.strIs( o.profileDir ), 'Expects defined {- o.profileDir -}' ); + + let o2 = _.mapOnly_( null, o, self.storageProfileNameMapFrom.defaults ); + self.storageProfileNameMapFrom( o2 ); + _.props.extend( o, o2 ); + + if( self.fileExists( o.storagePath ) ) + self.filesDelete + ({ + filePath : o.storagePath, + verbosity : o.verbosity ? 3 : 0, + }); + + } + catch( err ) + { + throw _.err( err, `\nFailed to delete storage::${o.storageName} at ${o.storagePath}` ); + } + +} + +storageProfileDel.defaults = +{ + ... storageProfileNameMapFrom.defaults, + verbosity : 0, +} + +// + +function storageTerminalNameFrom( o ) +{ + let self = this; + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageName : arguments[ 0 ] }; + o = _.routine.options_( storageTerminalNameFrom, o ); + + _.assert( _.strIs( o.storageDir ), 'Expects defined {- o.storageDir -}' ); + _.assert( _.strIs( o.profileDir ), 'Expects defined {- o.profileDir -}' ); + _.assert( _.strIs( o.storageTerminalPrefix ), 'Expects defined {- o.storageTerminalPrefix -}' ); + _.assert( _.strIs( o.storageTerminal ), 'Expects defined {- o.storageTerminal -}' ); + _.assert( _.strIs( o.storageTerminalPostfix ), 'Expects defined {- o.storageTerminalPostfix -}' ); + + if( o.storageName === null ) + o.storageName = self.path.join + ( + o.storageDir, + o.profileDir, + o.storageTerminalPrefix + o.storageTerminal + o.storageTerminalPostfix, + ); + + _.assert( _.strDefined( o.storageName ) ); + + return o.storageName; +} + +storageTerminalNameFrom.defaults = +{ + storageDir : null, + profileDir : 'default', + storageTerminalPrefix : '', + storageTerminal : null, + storageTerminalPostfix : '', + storageName : null, + storagePath : null, +} + +// + +function storageTerminalPathFrom( o ) +{ + let self = this; + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageName : arguments[ 0 ] }; + o = _.routine.options_( storageTerminalPathFrom, o ); + + if( o.storagePath === null ) + o.storagePath = self.configUserPath( o.storageName ); + + // return self.storageTerminalNameMapFrom( o ).storagePath; + + return o.storagePath; +} + +storageTerminalPathFrom.defaults = +{ + ... storageTerminalNameFrom.defaults, +} + +// + +function storageTerminalNameMapFrom( o ) +{ + let self = this; + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageName : arguments[ 0 ] }; + o = _.routine.options_( storageTerminalNameMapFrom, o ); + + if( o.storageName === null ) + o.storageName = self.storageTerminalNameFrom( o ); + if( o.storagePath === null ) + o.storagePath = self.storageTerminalPathFrom( o ); + + return o; +} + +storageTerminalNameMapFrom.defaults = +{ + ... storageTerminalNameFrom.defaults, +} + +// + +function storageTerminalRead( o ) +{ + let self = this; + try + { + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageDir : arguments[ 0 ] }; + o = _.routine.options_( storageTerminalRead, o ); + + self.storageTerminalNameMapFrom( o ); + + if( !self.fileExists( o.storagePath ) ) + return null; + + return self.configUserRead + ({ + name : o.storageName, + locking : 0, + }); + + } + catch( err ) + { + throw _.err( err, `\nFailed to read storage::${o.storageName} at ${o.storagePath}` ); + } +} + +storageTerminalRead.defaults = +{ + ... storageTerminalNameMapFrom.defaults, +} + +// + +function storageTerminalOpen( o ) +{ + let self = this; + try + { + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageName : arguments[ 0 ] }; + o = _.routine.options_( storageTerminalOpen, o ); + + let o2 = _.mapOnly_( null, o, self.storageTerminalNameFrom.defaults ); + self.storageTerminalNameMapFrom( o2 ); + _.props.extend( o, o2 ); + + o.storage = self.configUserRead + ({ + name : o.storageName, + locking : o.locking, + }); + + if( !o.storage ) + { + o.storage = o.onStorageConstruct( o ); + _.assert( _.mapIs( o.storage ) ); + self.configUserWrite( o.storageName, o.storage ); + if( o.locking ) + self.configUserLock( o.storageName ); + } + + return o; + } + catch( err ) + { + if( !o.throwing ) + return null; + throw _.err( err, `\nFailed to open storage::${o.storageName}` ); + } +} + +storageTerminalOpen.defaults = +{ + ... storageTerminalNameMapFrom.defaults, + onStorageConstruct : null, + locking : 1, + throwing : 1, +} + +// + +function storageTerminalClose( o ) +{ + let self = this; + // let storageName; + + try + { + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageDir : arguments[ 0 ] }; + o = _.routine.options_( storageTerminalClose, o ); + + _.assert( _.mapIs( o.storage ), 'Expects defined {- o.storage -}' ); + + let o2 = _.mapOnly_( null, o, self.storageTerminalNameFrom.defaults ); + self.storageTerminalNameMapFrom( o2 ); + _.props.extend( o, o2 ); + + o.storage = self.configUserWrite + ({ + name : o.storageName, + structure : o.storage, + unlocking : o.locking, + }); + + return o; + } + catch( err ) + { + if( !o.throwing ) + return null; + throw _.err( err, `\nFailed to close storage::${storageName}` ); + } +} + +storageTerminalClose.defaults = +{ + ... storageTerminalOpen.defaults, + storage : null, +} + +// + +function storageTerminalDel( o ) +{ + let self = this; + // let storageName, storagePath; + + try + { + + if( _.strIs( arguments[ 0 ] ) ) + o = { storageDir : arguments[ 0 ] }; + o = _.routine.options_( storageTerminalDel, o ); + + let o2 = _.mapOnly_( null, o, self.storageTerminalNameMapFrom.defaults ); + self.storageTerminalNameMapFrom( o2 ); + _.props.extend( o, o2 ); + + if( self.fileExists( o.storagePath ) ) + self.filesDelete + ({ + filePath : o.storagePath, + verbosity : o.verbosity ? 3 : 0, + }); + + } + catch( err ) + { + throw _.err( err, `\nFailed to delete storage::${o.storageName} at ${o.storagePath}` ); + } + +} + +storageTerminalDel.defaults = +{ + ... storageTerminalNameMapFrom.defaults, + verbosity : 0, +} + +// -- +// relations +// -- + +let Composes = +{ +} + +let Aggregates = +{ +} + +let Associates = +{ +} + +let Restricts = +{ +} + +// -- +// declare +// -- + +let Supplement = +{ + + // read + + // configRead2, + // _configRead2, + + configFind, + configRead, + + // user config + + configUserPath, /* qqq : cover */ + configUserRead, /* qqq : cover */ + configUserWrite, /* qqq : cover */ + configUserLock, /* qqq : cover */ + configUserUnlock, /* qqq : cover */ + + // storage + + storageNameFrom, + storagePathFrom, + storageNameMapFrom, + storageRead, + storageDel, + + storageProfileNameFrom, + storageProfilePathFrom, + storageProfileNameMapFrom, + storageProfileRead, + storageProfileDel, + + storageTerminalNameFrom, + storageTerminalPathFrom, + storageTerminalNameMapFrom, + storageTerminalRead, + storageTerminalOpen, + storageTerminalClose, + storageTerminalDel, + + // relation + + Composes, + Aggregates, + Associates, + Restricts, + +} + +// + +_.classDeclare +({ + cls : Self, + supplement : Supplement, + withMixin : true, + withClass : true, +}); + +_.FileProvider = _.FileProvider || Object.create( null ); +_.FileProvider[ Self.shortName ] = Self; +Self.mixin( Partial ); + +_.assert( !!_.FileProvider.Partial.prototype.configUserRead ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l7/ConfigMixin.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ConfigMixin_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ConfigMixin_s */ })(); + +/* */ /* begin of file SecondaryMixin_s */ ( function SecondaryMixin_s() { function SecondaryMixin_s_naked() { ( function _SecondaryMixin_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const FileRecord = _.files.FileRecord; +const Abstract = _.FileProvider.Abstract; +const Partial = _.FileProvider.Partial; +const Find = _.FileProvider.FindMixin; +const fileRead = Partial.prototype.fileRead; + +_.assert( _.entity.lengthOf( _.files.ReadEncoders ) > 0 ); +_.assert( _.routineIs( _.files.FileRecord ) ); +_.assert( _.routineIs( Abstract ) ); +_.assert( _.routineIs( Partial ) ); +_.assert( _.routineIs( Find ) ); +_.assert( _.routineIs( fileRead ) ); + +// + +/** + @classdesc Mixin to add operations on group of files with very specific purpose. For example, it has a method to search for text in files. + @class wFileProviderSecondaryMixin + @namespace wTools.FileProvider + @module Tools/mid/Files +*/ + +const Parent = null; +const Self = wFileProviderSecondaryMixin; +function wFileProviderSecondaryMixin( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'SecondaryMixin'; + +// -- +// files read +// -- + +// function filesReadOld( o ) +// { +// let self = this; +// +// /* options */ +// +// if( _.arrayIs( o ) ) +// o = { paths : o }; +// +// if( o.preset ) +// { +// _.assert( _.object.isBasic( filesReadOld.presets[ o.preset ] ), 'unknown preset', o.preset ); +// _.mapSupplementAppending( o, filesReadOld.presets[ o.preset ] ); +// } +// +// _.routine.options_( filesReadOld, o ); +// _.assert( arguments.length === 1, 'Expects single argument' ); +// _.assert( _.arrayIs( o.paths ) || _.object.isBasic( o.paths ) || _.strIs( o.paths ) ); +// +// o.onBegin = o.onBegin ? _.array.as( o.onBegin ) : []; +// o.onEnd = o.onEnd ? _.array.as( o.onEnd ) : []; +// o.onProgress = o.onProgress ? _.array.as( o.onProgress ) : []; +// +// let onBegin = o.onBegin; +// let onEnd = o.onEnd; +// let onProgress = o.onProgress; +// +// delete o.onBegin; +// delete o.onEnd; +// delete o.onProgress; +// +// if( Config.debug ) +// { +// for( let i = 0 ; i < onBegin.length ; i++ ) +// _.assert( onBegin[ i ].length === 1 ); +// for( let i = 0 ; i < onEnd.length ; i++ ) +// _.assert( onEnd[ i ].length === 1 ); +// for( let i = 0 ; i < onProgress.length ; i++ ) +// _.assert( onProgress[ i ].length === 1 ); +// } +// +// /* paths */ +// +// if( _.object.isBasic( o.paths ) ) +// { +// let _paths = []; +// for( let p in o.paths ) +// _paths.push({ filePath : o.paths[ p ], name : p }); +// o.paths = _paths; +// } +// +// o.paths = _.array.as( o.paths ); +// +// /* result */ +// +// let result = Object.create( null ); +// result.options = o; +// +// /* */ +// +// o._filesReadOldEnd = _filesReadOldEnd; +// o._optionsForFileRead = _optionsForFileRead; +// +// /* begin */ +// +// _filesReadOldBegin(); +// +// if( o.sync ) +// { +// return self._filesReadOldSync( o ); +// } +// else +// { +// return self._filesReadOldAsync( o ); +// } +// +// /* - */ +// +// function _optionsForFileRead( src ) +// { +// let readOptions = _.mapOnly_( null, o, self.fileRead.defaults ); +// readOptions.onEnd = o.onEach; +// +// if( _.object.isBasic( src ) ) +// { +// if( _.files.FileRecord && src instanceof _.files.FileRecord ) +// readOptions.filePath = src.absolute; +// else +// _.props.extend( readOptions, _.mapOnly_( null, src, self.fileRead.defaults ) ); +// } +// else +// readOptions.filePath = src; +// +// return readOptions; +// } +// +// /* */ +// +// function _filesReadOldBegin() +// { +// if( !onBegin.length ) +// return; +// debugger; +// _.routinesCall( self, onBegin, [ result ] ); +// } +// +// /* */ +// +// function _filesReadOldEnd( errs, got ) +// { +// let err; +// let errsArray = []; +// +// for( let k in errs ) +// errsArray.push( errs[ k ] ); +// +// if( errsArray.length ) +// { +// errs.total = errsArray.length; +// err = _.err.apply( _, errsArray ); +// } +// +// let read = got; +// if( !o.returningRead ) +// read = _.container.map_( null, got, ( e ) => e.result ); +// +// if( o.map === 'name' ) +// { +// +// let read2 = Object.create( null ); +// let got2 = Object.create( null ); +// +// for( let p = 0 ; p < o.paths.length ; p++ ) +// { +// let path = o.paths[ p ]; +// let name; +// +// if( _.strIs( path ) ) +// { +// name = self.path.name( path ); +// } +// else if( _.object.isBasic( path ) ) +// { +// _.assert( _.strIs( path.name ) ) +// name = path.name; +// } +// else +// _.assert( 0, 'unknown type of path', _.entity.strType( path ) ); +// +// read2[ name ] = read[ p ]; +// got2[ name ] = got[ p ]; +// } +// +// read = read2; +// got = got2; +// +// } +// else if( o.map ) +// _.assert( 0, 'unknown map : ' + o.map ); +// +// result.read = read; +// result.data = read; +// result.got = got; +// result.errs = errs; +// result.err = err; +// +// if( onEnd.length ) +// { +// _.routinesCall( self, onEnd, [ result ] ); +// } +// +// return result; +// } +// +// } +// +// filesReadOld.defaults = +// { +// paths : null, +// onEach : null, +// map : '', +// sync : 1, +// preset : null, +// } +// +// filesReadOld.defaults.__proto__ = fileRead.defaults; +// +// filesReadOld.presets = Object.create( null ); +// +// filesReadOld.presets.js = +// { +// onEnd : function format( o ) +// { +// let prefix = '// ======================================\n( function() {\n'; +// let postfix = '\n})();\n'; +// _.assert( _.arrayIs( o.data ) ); +// if( o.data.length > 1 ) +// o.data = prefix + o.data.join( postfix + prefix ) + postfix; +// else +// o.data = o.data[ 0 ]; +// } +// } + +// + +function _filesReadOldSync( o ) +{ + let self = this; + + _.assert( !o.onProgress, 'not implemented' ); + + let read = []; + let errs = Object.create( null ); + + let _filesReadOldEnd = o._filesReadOldEnd; + delete o._filesReadOldEnd; + + let _optionsForFileRead = o._optionsForFileRead; + delete o._optionsForFileRead; + + let throwing = o.throwing; + o.throwing = 1; + + /* exec */ + + for( let p = 0 ; p < o.paths.length ; p++ ) + { + let readOptions = _optionsForFileRead( o.paths[ p ] ); + + try + { + read[ p ] = self.fileRead( readOptions ); + } + catch( err ) + { + + if( throwing ) + throw err; + + errs[ p ] = err; + read[ p ] = null; + } + } + + /* end */ + + let result = _filesReadOldEnd( errs, read ); + + /* */ + + return result; +} + +// + +function _filesReadOldAsync( o ) +{ + let self = this; + let con = new _.Consequence(); + + _.assert( !o.onProgress, 'not implemented' ); + + let read = []; + let errs = []; + let err = null; + + let _filesReadOldEnd = o._filesReadOldEnd; + delete o._filesReadOldEnd; + + let _optionsForFileRead = o._optionsForFileRead; + delete o._optionsForFileRead; + + /* exec */ + + for( let p = 0 ; p < o.paths.length ; p++ ) ( function( p ) + { + + con.give( 1 ); + + let readOptions = _optionsForFileRead( o.paths[ p ] ); + + _.Consequence.From( self.fileRead( readOptions ) ).give( function filesReadOldFileEnd( _err, arg ) + { + + if( _err || arg === undefined || arg === null ) + { + err = _.errAttend( err ); + err = _.err( 'Cant read : ' + _.entity.exportString( readOptions.filePath ) + '\n', ( _err || 'unknown reason' ) ); + errs[ p ] = err; + } + else + { + read[ p ] = arg; + } + + con.take( null ); + + }); + + })( p ); + + /* end */ + + con.take( null ).give( function filesReadOldEnd() + { + let result = _filesReadOldEnd( errs, read ); + con.take( o.throwing ? err : undefined, result ); + }); + + /* */ + + return con; +} + +// -- +// etc +// -- + +// /** +// * @summary Returns true if file from `dst` is newer than file from `src`. +// * @param {String} src Source path. +// * @param {String} dst Destination path. +// * @returns {Boolean} Returns result of comparison as boolean. +// * @function filesAreUpToDate +// * @class wFileProviderSecondaryMixin +// * @namespace wTools.FileProvider +// * @module Tools/mid/Files +// */ +// +// function filesAreUpToDate( dst, src ) +// { +// let self = this; +// let odst = dst; +// let osrc = src; +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// +// /* */ +// +// dst = from( dst ); +// src = from( src ); +// +// // logger.log( 'dst', dst[ 0 ] ); +// // logger.log( 'src', src[ 0 ] ); +// +// let dstMax = _.entityMax( dst, function( e ){ return e.stat ? e.stat.mtime : Infinity; } ); +// let srcMax = _.entityMax( src, function( e ){ return e.stat ? e.stat.mtime : Infinity; } ); +// +// debugger; +// // logger.log( 'dstMax.element.stat.mtime', dstMax.element.stat.mtime ); +// // logger.log( 'srcMax.element.stat.mtime', srcMax.element.stat.mtime ); +// +// if( !dstMax.element.stat ) +// return false; +// +// if( !srcMax.element.stat ) +// return false; +// +// if( dstMax.element.stat.mtime >= srcMax.element.stat.mtime ) +// return true; +// else +// return false; +// +// /* */ +// +// function _from( file ) +// { +// if( _.fileStatIs( file ) ) +// return { stat : file }; +// else if( _.strIs( file ) ) +// return { stat : self.statResolvedRead( file ) }; +// else if( !_.object.isBasic( file ) ) +// throw _.err( 'unknown descriptor of file' ); +// } +// +// /* */ +// +// function from( file ) +// { +// if( _.arrayIs( file ) ) +// { +// let result = []; +// for( let i = 0 ; i < file.length ; i++ ) +// result[ i ] = _from( file[ i ] ); +// return result; +// } +// return [ _from( file ) ]; +// } +// +// } +// +// var having = filesAreUpToDate.having = Object.create( null ); +// +// having.writing = 0; +// having.reading = 1; +// having.driving = 0; + +// + +/** + * Returns true if any file from o.dst is newer than other any from o.src. + * @example : + * wTools.filesAreUpToDate2 + * ({ + * src : [ 'foo/file1.txt', 'foo/file2.txt' ], + * dst : [ 'bar/file1.txt', 'bar/file2.txt' ], + * }); + * @param {Object} o + * @param {string[]} o.src array of paths + * @param {Object} [o.srcOptions] + * @param {string[]} o.dst array of paths + * @param {Object} [o.dstOptions] + * @param {boolean} [o.verbosity=true] turns on/off logging + * @returns {boolean} + * @throws {Error} If passed object has unexpected parameter. + * @function filesAreUpToDate2 + * @class wFileProviderSecondaryMixin + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +/* +qqq : +- add GOOD coverage for the routine filesAreUpToDate2 +- make head/body for the routine +*/ + +function filesAreUpToDate2_head( routine, args ) +{ + var o = args[ 0 ]; + + _.assert( args.length === 1, 'Expects single argument' ) + _.assert( arguments.length === 2 ); + _.assert( !o.newer || _.dateIs( o.newer ) ); + + _.routine.options_( routine, o ); + + return o; +} + +function filesAreUpToDate2_body( o ) +{ + let self = this; + let factory = self.recordFactory({ allowingMissed : 1 }); + let srcFiles = factory.records( _.array.as( o.src ) ); + + if( !srcFiles.length ) + { + if( o.verbosity ) + logger.log( 'No source' ); + return true; + } + + /* + stat could have no mtime + */ + + let srcNewest = _.entityMax( srcFiles, function( file ) + { + if( !file.stat ) + return +Infinity; + if( !file.stat.mtime ) + return +Infinity; + return file.stat.mtime.getTime(); + }).value; + + /* */ + + let dstFiles = factory.records( _.array.as( o.dst ) ); + if( !dstFiles.length ) + { + if( o.verbosity ) + logger.log( 'No destination' ); + return false; + } + + let dstOldest = _.entityMin( dstFiles, function( file ) + { + if( !file.stat ) + return -Infinity; + if( !file.stat.mtime ) + return -Infinity; + return file.stat.mtime.getTime(); + }).value; + + /* */ + + if( o.youngerThan ) + { + if( o.youngerThan.getTime() >= dstOldest ) + { + if( o.verbosity ) + logger.log( 'Younger' ); + return true; + } + else + { + if( o.verbosity ) + logger.log( 'Older' ); + return false; + } + } + else + { + if( srcNewest <= dstOldest ) + { + if( o.verbosity ) + logger.log( 'Up to date' ); + return true; + } + else + { + if( o.verbosity ) + logger.log( 'Outdated' ); + return false; + } + } + +} + +filesAreUpToDate2_body.defaults = +{ + src : null, + dst : null, + verbosity : 0, + youngerThan : null, +} + +var having = filesAreUpToDate2_body.having = Object.create( null ); + +having.writing = 0; +having.reading = 1; +having.driving = 0; + +var filesAreUpToDate2 = _.routine.uniteCloning_replaceByUnite( filesAreUpToDate2_head, filesAreUpToDate2_body ); + +// + +function filesAreOnSameDevice_head( routine, args ) +{ + var o = args[ 0 ]; + + _.assert( args.length === 1 || args.length === 2 ); + _.assert( arguments.length === 2 ); + + if( args.length === 2 ) + { + o = { src : args[ 0 ], dst : args[ 1 ] } + } + + _.routine.options_( routine, o ); + + _.assert( _.strDefined( o.src ) ); + _.assert( _.strDefined( o.dst ) ); + + return o; +} + +// + +function filesAreOnSameDevice_body( o ) +{ + let self = this; + + let src = + { + filePath : o.src, + resolvingSoftLink : 1, + throwing : 0 + } + self.pathResolveLinkFull( src ); + + let dst = + { + filePath : o.dst, + resolvingSoftLink : 1, + throwing : 0 + } + self.pathResolveLinkFull( dst ); + + if( !src.stat || !dst.stat ) + { + let trace = self.path.traceToRoot( o.src ); + if( !trace.length ) + { + _.assert( o.filePath === '/' ); + trace = [ o.filePath ]; + } + else if( trace.length > 1 ) + trace.shift(); + + let common = self.path.common( o.dst, trace[ 0 ] ); + return common === trace[ 0 ]; + } + + return src.stat.dev === dst.stat.dev; +} + +filesAreOnSameDevice_body.defaults = +{ + src : null, + dst : null +} + +var having = filesAreOnSameDevice_body.having = Object.create( null ); + +having.writing = 0; +having.reading = 1; +having.driving = 0; + +var filesAreOnSameDevice = _.routine.uniteCloning_replaceByUnite( filesAreOnSameDevice_head, filesAreOnSameDevice_body ); + +// + +/** + * @summary Calculates date resolution time in milliseconds for current file system. + * @function systemBitrateTimeGet + * @class wFileProviderSecondaryMixin + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function systemBitrateTimeGet() +{ + let self = this; + + let result = 10; + + if( _.FileProvider.HardDrive && self instanceof _.FileProvider.HardDrive ) + { + let testDir = self.path.tempOpen({ filePath : self.path.join( __dirname, '../../..' ), name : 'SecondaryMixin' }); + let tempFile = self.path.join( testDir, 'systemBitrateTimeGet' ); + self.fileWrite( tempFile, tempFile ); + let ostat = self.statResolvedRead( tempFile ); + let mtime = new Date( ostat.mtime.getTime() ); + let ms = 500; + mtime.setMilliseconds( ms ); + try + { + self.timeWrite( tempFile, ostat.atime, mtime ); + let stat = self.statResolvedRead( tempFile ); + let diff = mtime.getTime() - stat.mtime.getTime(); + if( diff ) + { + debugger + result = ( diff / 1000 ).toFixed() * 1000; + _.assert( !!result ); + } + } + catch( err ) + { + throw _.err( err ); + } + finally + { + self.path.tempClose( testDir ); + } + } + + return result; +} + +systemBitrateTimeGet.defaults = +{ +} + +var having = systemBitrateTimeGet.having = Object.create( null ); + +having.writing = 1; +having.reading = 0; +having.driving = 1; + +// -- +// top +// -- + +function filesSearchText( o ) +{ + let self = this; + let result = []; + + _.routine.options_( filesSearchText, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + o.ins = _.array.as( o.ins ); + o.ins = _.regexpsMaybeFrom + ({ + srcStr : o.ins, + stringWithRegexp : o.stringWithRegexp, + toleratingSpaces : o.toleratingSpaces, + }); + + let o2 = _.mapOnly_( null, o, self.filesFind.defaults ); + + o2.onUp = _.arrayAppendElement( o2.onUp, handleUp ); + + let records = self.filesFind( o2 ); + + return result; + + /* */ + + function handleUp( record ) + { + let read = record.factory.effectiveProvider.fileRead( record.absolute ); + + let o2 = _.mapOnly_( null, o, _.strSearch.defaults ); + o2.src = read; + o2.stringWithRegexp = 0; + o2.toleratingSpaces = 0; + + let matches = _.strSearch( o2 ); + + for( let m = 0 ; m < matches.length ; m++ ) + { + let match = matches[ m ]; + match.file = record; + result.push( match ); + } + + return false; + } + +} + +_.routineExtend( filesSearchText, Find.prototype.filesFind ); + +var defaults = filesSearchText.defaults; + +_.props.supplement( defaults, _.mapBut_( null, _.strSearch.defaults, { src : null } ) ); + +defaults.determiningLineNumber = 1; + +// -- +// read +// -- + +/** + * @summary Read source code from provided file `o.filePath` and wraps it with self enclosed function of name `o.name`. + * @param {Object} o Options map. + * @param {String} o.filePath Source path. + * @param {String} o.encoding='utf8' Encoding used in file reading. + * @param {Boolean} o.wrapping=1 Adds custom `o.prefix` and `o.postfix` to source code. + * @param {Boolean} o.routine=0 Creates routine from result string. + * @param {String} o.name Name for self enclosed function. + * @param {String} o.prefix Inserts this string before source code. + * @param {String} o.postfix Inserts this string after source code. + * @function fileCodeRead + * @class wFileProviderSecondaryMixin + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function fileCodeRead_body( o ) +{ + let self = this; + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( o.sync, 'not implemented' ); + + let o2 = _.mapOnly_( null, o, self.fileRead.defaults ); + let result = self.fileRead( o2 ); + + if( o.name === null ) + o.name = _.strVarNameFor( self.path.fullName( o.filePath ) ); + + if( o.wrapping ) + { + + if( _.TemplateTreeResolver ) + { + let resolver = _.TemplateTreeResolver({ tree : o }); + o.prefix = resolver.resolve( o.prefix ); + o.postfix = resolver.resolve( o.postfix ); + } + + result = o.prefix + result + o.postfix; + + } + + if( o.routine ) + { + result = _.routineMake({ code : result, name : o.name }); + } + + return result; +} + +var defaults = fileCodeRead_body.defaults = _.props.extend( null, fileRead.defaults ); + +defaults.encoding = 'utf8'; +defaults.wrapping = 1; +defaults.routine = 0; +defaults.name = null; +defaults.prefix = '// ======================================\n( function {{name}}() {\n'; +defaults.postfix = '\n})();\n'; + +_.routineExtend( fileCodeRead_body, fileRead.body ); + +var fileCodeRead = _.routine.uniteCloning_replaceByUnite( fileRead.head, fileCodeRead_body ); + +fileCodeRead.having.aspect = 'entry'; + +// -- +// relations +// -- + +let Composes = +{ +} + +let Aggregates = +{ +} + +let Associates = +{ +} + +let Restricts = +{ +} + +// -- +// declare +// -- + +let Supplement = +{ + + // files read + + // filesReadOld, + // _filesReadOldAsync, + // _filesReadOldSync, + + // etc + + // filesAreUpToDate, + filesAreUpToDate2, + filesAreOnSameDevice, + + filesSearchText, + + systemBitrateTimeGet, + + // read + + fileCodeRead, + + // + + Composes, + Aggregates, + Associates, + Restricts, + +} + +// + +_.classDeclare +({ + cls : Self, + supplement : Supplement, + withMixin : true, + withClass : true, +}); + +_.FileProvider = _.FileProvider || Object.create( null ); +_.FileProvider[ Self.shortName ] = Self; +Self.mixin( Partial ); + +_.assert( !!_.FileProvider.Partial.prototype.configUserRead ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l7/SecondaryMixin.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, SecondaryMixin_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file SecondaryMixin_s */ })(); + +/* */ /* begin of file TempMixin_s */ ( function TempMixin_s() { function TempMixin_s_naked() { ( function _TempMixin_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const FileRecord = _.files.FileRecord; +const Abstract = _.FileProvider.Abstract; +const Partial = _.FileProvider.Partial; + +_.assert( _.entity.lengthOf( _.files.ReadEncoders ) > 0 ); +_.assert( _.routineIs( _.files.FileRecord ) ); +_.assert( _.routineIs( Abstract ) ); +_.assert( _.routineIs( Partial ) ); + +// + +/** + @class wFileProviderTempMixin + @class FileProvider + @namespace wTools + @module Tools/mid/Files +*/ + +const Parent = null; +const Self = wFileProviderTempMixin; +function wFileProviderTempMixin( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'TempMixin'; + +// -- +// implementation +// -- + +function tempCollectionMaking( o ) +{ + let self = this; + + let tempCollection = self.TempCollection[ self.id ]; + if( !tempCollection ) + { + tempCollection = self.TempCollection[ self.id ] = Object.create( null ); + tempCollection.associated = Object.create( null ); + tempCollection.wild = new Set; + } + + return tempCollection; +} + +// + +function tempHead( routine, args ) +{ + let self = this; + let path = self.path; + let o = args[ 0 ]; + + if( !_.mapIs( args[ 0 ] ) ) + o = { srcPath : args[ 0 ] } + if( args[ 1 ] !== undefined ) + o.name = args[ 1 ]; + + if( o.srcPath === undefined || o.srcPath === null ) + o.srcPath = null; + else + o.srcPath = path.resolve( o.srcPath ); + + _.routine.options( routine, o ); + _.assert( args.length <= 2 ); + _.assert( o.srcPath === null || path.isAbsolute( o.srcPath ) ); + _.assert( o.srcPath === null || path.isNormalized( o.srcPath ) ); + _.assert( arguments.length === 2 ); + + return o; +} + +// + +function tempAt_body( o ) +{ + let self = this; + let path = self.path; + let err; + let dirTemp = path.dirTemp(); + let tempCollection = self.tempCollectionMaking(); + + _.assert( !o.tempStoragePath ); + + o.providerId = self.id; + + if( o.srcPath === null ) + { + return make( dirTemp ); + } + else + { + let result = tempCollection.associated[ o.srcPath ]; + if( result ) + return result; + } + + let sameDevice = self.filesAreOnSameDevice( o.srcPath, dirTemp ); + if( sameDevice ) + return make( dirTemp ); + + /* */ + + let fileStat = statRead( o.srcPath ); + let trace = path.traceToRoot( o.srcPath ); + if( !trace.length ) + { + _.assert( o.srcPath === '/' ); + trace = [ o.srcPath ]; + } + else if( trace.length > 1 ) + trace.shift(); + + for( let i = 0; i < trace.length; i++ ) + { + try + { + if( trace[ i ] === '/' ) + continue; + + if( self.fileExists( trace[ i ] ) ) + { + let currentStat = statRead( trace[ i ] ); + if( fileStat.dev != currentStat.dev ) + continue; + } + + if( tempCollection.associated[ trace[ i ] ] ) + return tempCollection.associated[ trace[ i ] ]; + else + return make( trace[ i ] ); + } + catch( e ) + { + err = e; + } + } + + return make( dirTemp ); + + /* */ + + function make( dirPath ) + { + _.assert( !o.tempStoragePath ); + o.tempStoragePath = dirPath; + return o; + } + + /* */ + + function statRead( filePath ) + { + return self.statReadAct + ({ + filePath, + throwing : 0, + sync : 1, + resolvingSoftLink : 1, + }); + } + + /* */ + +} + +tempAt_body.defaults = +{ + srcPath : null, +} + +let tempAt = _.routine.unite( tempHead, tempAt_body ); + +// + +function tempMake_body( o ) +{ + let self = this; + let path = self.path; + let err; + let dirTemp = path.dirTemp(); + let tempCollection = self.tempCollectionMaking(); + + if( !o.name ) + o.name = 'tmp'; + if( !o.tempName ) + o.tempName = o.name + '-' + _.idWithDateAndTime() + '.tmp'; + o.providerId = self.id; + + if( !o.tempStoragePath && !o.tempPath ) + o = self.tempAt.body.call( self, o ); + _.assert( !!o.tempStoragePath ); + + if( o.counter ) + return reuse( o ); + return make( o ); + + /* */ + + function reuse( o ) + { + o.counter += 1; + return o; + } + + /* */ + + function make( o ) + { + o.close = close; + o.counter = 1; + + if( !o.tempPath ) + o.tempPath = path.join( o.tempStoragePath, o.tempName ); + if( !self.fileExists( o.tempPath ) ) + self.dirMake( o.tempPath ); + + if( o.resolving ) /* xxx : qqq : cover the option please */ + o.tempPath = self.pathResolveLinkFull + ({ + filePath : o.tempPath, + resolvingSoftLink : 1, + }).absolutePath; + + if( o.srcPath === null ) + tempCollection.wild.add( o ); + else + tempCollection.associated[ o.srcPath ] = o; + + if( o.auto ) + _.process.on( _.event.Chain( 'available', 'exit' ), () => + { + o.close(); + }); + + return o; + } + + /* */ + + function close() + { + this.counter -= 1; + _.assert( this.counter >= 0 ); + if( this.counter > 0 ) + return false; + + _.assert( this.counter === 0 ); + this.counter = -1; + Object.freeze( this ); + + if( o.srcPath === null ) + { + _.assert( tempCollection.wild.has( o ) ); + tempCollection.wild.delete( o ); + } + else + { + _.assert( !!tempCollection.associated[ this.srcPath ] ); + delete tempCollection.associated[ this.srcPath ]; + } + + self.filesDelete + ({ + filePath : this.tempPath, + safe : 0, + throwing : 0, + }); + _.assert + ( + !self.fileExists( o.tempPath ), + () => `Temp dir "${o.tempPath}" was closed, but still exist in file system.` + ); + + return true; + } + +} + +tempMake_body.defaults = +{ + srcPath : null, + tempPath : null, + tempStoragePath : null, + name : null, + tempName : null, + resolving : 1, + auto : 1, +} + +let tempMake = _.routine.unite( tempHead, tempMake_body ); + +// + +function tempOpen_body( o ) +{ + let self = this; + let path = self.path; + + o = self.tempMake.body.call( self, o ); + + return o; +} + +tempOpen_body.defaults = +{ + ... tempMake.defaults, +} + +let tempOpen = _.routine.unite( tempHead, tempOpen_body ); + +// +// + +function tempClose( srcPath ) +{ + let self = this; + let path = self.path; + + _.assert( arguments.length <= 1 ); + _.assert( _.str.is( srcPath ) || srcPath === undefined ); + + let tempCollection = self.TempCollection[ self.id ]; + if( !tempCollection ) + return; + + if( _.str.is( srcPath ) ) + { + _.assert( path.isAbsolute( srcPath ) ); + _.assert( path.isNormalized( srcPath ) ); + let o = tempCollection.associated[ srcPath ]; + if( o.close ) + o.close(); + } + else + { + for( let p in tempCollection.associated ) + tempCollection.associated[ p ].close(); + _.assert( _.props.keys( tempCollection ).length === 0 ); + + for( let e of tempCollection.wild ) + e.close(); + _.assert( tempCollection.wild.size === 0 ); + + delete self.TempCollection[ self.id ]; + } + +} + +// -- +// relations +// -- + +let Composes = +{ +} + +let Aggregates = +{ +} + +let Associates = +{ +} + +let Restricts = +{ +} + +let Statics = +{ + TempCollection : Object.create( null ), +} + +// -- +// declare +// -- + +let Supplement = +{ + + tempCollectionMaking, + tempAt, + tempMake, + tempOpen, + tempClose, + + // + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + +} + +// + +_.classDeclare +({ + cls : Self, + supplement : Supplement, + withMixin : true, + withClass : true, +}); + +_.FileProvider = _.FileProvider || Object.create( null ); +_.FileProvider[ Self.shortName ] = Self; + +Self.mixin( Partial ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l7/TempMixin.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l7' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, TempMixin_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file TempMixin_s */ })(); + +/* */ /* begin of file Extract_s */ ( function Extract_s() { function Extract_s_naked() { ( function _Extract_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Abstract = _.FileProvider.Abstract; +const Partial = _.FileProvider.Partial; +const FileRecord = _.files.FileRecord; +const Find = _.FileProvider.FindMixin; + +_.assert( _.routineIs( _.files.FileRecord ) ); +_.assert( _.routineIs( Abstract ) ); +_.assert( _.routineIs( Partial ) ); +_.assert( !!Find ); +_.assert( !_.FileProvider.Extract ); + +// + +/** + @classdesc Class that allows file manipulations on filesTree - object based on some folders/files tree, + where folders are nested objects with same depth level as in real folder and contains some files that are properties + with corresponding names and file content as a values. + @class wFileProviderExtract + @namespace wTools.FileProvider + @module Tools/mid/Files +*/ + +const Parent = Partial; +const Self = wFileProviderExtract; +function wFileProviderExtract( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'Extract'; + +// -- +// inter +// -- + +function init( o ) +{ + let self = this; + Parent.prototype.init.call( self, o ); + + if( self.filesTree === null ) + self.filesTree = Object.create( null ); + +} + +// -- +// path +// -- + +function pathNativizeAct( filePath ) +{ + let self = this; + let result = filePath; + _.assert( _.strIs( filePath ), 'Expects string' ); + _.assert( _.routineIs( self.path.unescape ) ); + result = self.path.unescape( result ); /* yyy */ + return result; +} + +// + +/** + * @summary Return path to current working directory. + * @description Changes current path to `path` if argument is provided. + * @param {String} [path] New current path. + * @function pathCurrentAct + * @class wFileProviderExtract + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function pathCurrentAct() +{ + let self = this; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( arguments.length === 1 && arguments[ 0 ] ) + { + let path = arguments[ 0 ]; + _.assert( self.path.is( path ) ); + self._currentPath = path; + } + + let result = self._currentPath; + + return result; +} + +// + +/** + * @summary Resolves soft link `o.filePath`. + * @description Accepts single argument - map with options. Expects that map `o` contains all necessary options and don't have redundant fields. + * Returns input path `o.filePath` if source file is not a soft link. + * @param {Object} o Options map. + * @param {String} o.filePath Path to soft link. + * @param {Boolean} o.resolvingMultiple=0 Resolves chain of terminal links. + * @param {Boolean} o.resolvingIntermediateDirectories=0 Resolves intermediate soft links. + * @function pathResolveSoftLinkAct + * @class wFileProviderExtract + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function pathResolveSoftLinkAct( o ) +{ + let self = this; + // let filePath = o.filePath; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( self.path.isAbsolute( o.filePath ) ); + + // /* using self.resolvingSoftLink causes recursion problem in pathResolveLinkFull */ + // debugger; + // if( !self.isSoftLink( o.filePath ) ) + // return o.filePath; + + let result; + + if( o.resolvingIntermediateDirectories ) + return resolveIntermediateDirectories(); + + let filePath = self._pathResolveIntermediateDirs( o.filePath ); + + let descriptor = self._descriptorRead( filePath ); + + if( !self._DescriptorIsSoftLink( descriptor ) ) + return o.filePath; + + result = self._descriptorResolveSoftLinkPath( descriptor ); + + _.assert( _.strIs( result ) ) + + if( o.resolvingMultiple ) + return resolvingMultiple(); + + return result; + + /* */ + + function resolveIntermediateDirectories() + { + let splits = self.path.split( o.filePath ); + let o2 = _.props.extend( null, o ); + + o2.resolvingIntermediateDirectories = 0; + o2.filePath = '/'; + + for( let i = 1 ; i < splits.length ; i++ ) + { + o2.filePath = self.path.join( o2.filePath, splits[ i ] ); + + let descriptor = self._descriptorRead( o2.filePath ); + + if( self._DescriptorIsSoftLink( descriptor ) ) + { + result = self.pathResolveSoftLinkAct( o2 ) + o2.filePath = self.path.join( o2.filePath, result ); + } + } + return o2.filePath; + } + + /**/ + + function resolvingMultiple() + { + result = self.path.join( o.filePath, self.path.normalize( result ) ); + let descriptor = self._descriptorRead( result ); + if( !self._DescriptorIsSoftLink( descriptor ) ) + return result; + let o2 = _.props.extend( null, o ); + o2.filePath = result; + return self.pathResolveSoftLinkAct( o2 ); + } +} + +_.routineExtend( pathResolveSoftLinkAct, Parent.prototype.pathResolveSoftLinkAct ) + +// + +/** + * @summary Resolves text link `o.filePath`. + * @description Accepts single argument - map with options. Expects that map `o` contains all necessary options and don't have redundant fields. + * Returns input path `o.filePath` if source file is not a text link. + * @param {Object} o Options map. + * @param {String} o.filePath Path to text link. + * @param {Boolean} o.resolvingMultiple=0 Resolves chain of text links. + * @param {Boolean} o.resolvingIntermediateDirectories=0 Resolves intermediate text links. + * @function pathResolveTextLinkAct + * @class wFileProviderExtract + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function pathResolveTextLinkAct( o ) +{ + let self = this; + let filePath = o.filePath; + let result; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( self.path.isAbsolute( o.filePath ) ); + + if( o.resolvingIntermediateDirectories ) + return resolveIntermediateDirectories(); + + let file = self._descriptorRead( o.filePath ); + + if( self._DescriptorIsSoftLink( file ) ) + return false; + if( _.numberIs( file ) ) + return false; + + if( _.bufferRawIs( file ) || _.bufferTypedIs( file ) ) + file = _.bufferToStr( file ); + + if( _.arrayIs( file ) ) + file = file[ 0 ].data; + + _.assert( _.strIs( file ) ); + + let regexp = /^link ([^\n]+)\n?$/; + let m = file.match( regexp ); + + if( !m ) + return false; + + result = m[ 1 ]; + + if( o.resolvingMultiple ) + return resolvingMultiple(); + + return result; + + /* */ + + function resolveIntermediateDirectories() + { + let splits = self.path.split( o.filePath ); + let o2 = _.props.extend( null, o ); + + o2.resolvingIntermediateDirectories = 0; + o2.filePath = '/'; + + for( let i = 1 ; i < splits.length ; i++ ) + { + o2.filePath = self.path.join( o2.filePath, splits[ i ] ); + + let descriptor = self._descriptorRead( o2.filePath ); + + if( self._DescriptorIsTextLink( descriptor ) ) + { + result = self.pathResolveTextLinkAct( o2 ) + o2.filePath = self.path.join( o2.filePath, result ); + } + } + return o2.filePath; + } + + /**/ + + function resolvingMultiple() + { + result = self.path.join( o.filePath, self.path.normalize( result ) ); + let descriptor = self._descriptorRead( result ); + if( !self._DescriptorIsTextLink( descriptor ) ) + return result; + let o2 = _.props.extend( null, o ); + o2.filePath = result; + return self.pathResolveTextLinkAct( o2 ); + } +} + +_.routineExtend( pathResolveTextLinkAct, Parent.prototype.pathResolveTextLinkAct ) + +// -- +// read +// -- + +/** + * @summary Reads content of a terminal file. + * @description Accepts single argument - map with options. Expects that map `o` contains all necessary options and don't have redundant fields. + * If `o.sync` is false, return instance of wConsequence, that gives a message with concent of a file when reading is finished. + * @param {Object} o Options map. + * @param {String} o.filePath Path to terminal file. + * @param {String} o.encoding Desired encoding of a file concent. + * @param {*} o.advanced + * @param {Boolean} o.resolvingSoftLink Enable resolving of soft links. + * @param {String} o.sync Determines how to read a file, synchronously or asynchronously. + * @function fileReadAct + * @class wFileProviderExtract + * @namespace wTools.FileProvider + * @module Tools/mid/Files +*/ + +function fileReadAct( o ) +{ + let self = this; + let con = new _.Consequence(); + let result = null; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.map.assertHasAll( o, fileReadAct.defaults ); + _.assert( _.strIs( o.encoding ) ); + + let encoderName = o.encoder; + o.fileProvider = self; + o.encoder = fileReadAct.encoders[ o.encoding ]; + // _.assert( o.encoding === null || o.encoding === undefined || _.object.is( o.encoder ), `encoder::${o.encoding} is not registered` ); + if( o.encoder && o.encoder.onSelect) + o.encoder.onSelect.call( self, o ); + + if( o.encoding ) + if( !o.encoder ) + return handleError( _.err( 'Encoding: ' + o.encoding + ' is not supported!' ) ) + + /* exec */ + + handleBegin(); + + o.filePath = self.pathResolveLinkFull + ({ + filePath : o.filePath, + resolvingSoftLink : o.resolvingSoftLink, + // resolvingTextLink : o.resolvingTextLink, + }).absolutePath; + + if( self.system && _.path.isGlobal( o.filePath ) ) + { + _.assert( self.system !== self ); + return self.system.fileReadAct( o ); + } + + result = self._descriptorRead( o.filePath ); + + if( self._DescriptorIsHardLink( result ) ) + { + result = result[ 0 ].data; + _.assert( result !== undefined ); + } + + if( result === undefined || result === null ) + { + debugger; + result = self._descriptorRead( o.filePath ); + return handleError( _.err( 'File at', _.strQuote( o.filePath ), 'doesn`t exist!' ) ); + } + + if( self._DescriptorIsDir( result ) ) + return handleError( _.err( 'Can`t read from dir : ' + _.strQuote( o.filePath ) + ' method expects terminal file' ) ); + else if( self._DescriptorIsLink( result ) ) + return handleError( _.err( 'Can`t read from link : ' + _.strQuote( o.filePath ) + ', without link resolving enabled' ) ); + else if( !self._DescriptorIsTerminal( result ) ) + return handleError( _.err( 'Can`t read file : ' + _.strQuote( o.filePath ), result ) ); + + if( self.usingExtraStat ) + self._timeWriteAct({ filePath : o.filePath, atime : _.time.now() }); + + return handleEnd( result ); + + /* begin */ + + function handleBegin() + { + + if( o.encoder && o.encoder.onBegin ) + _.sure( o.encoder.onBegin.call( self, { operation : o, encoder : o.encoder }) === undefined ); + + } + + /* end */ + + function handleEnd( data ) + { + + let context = { data, operation : o, encoder : o.encoder }; + if( o.encoder && o.encoder.onEnd ) + _.sure( o.encoder.onEnd.call( self, context ) === undefined ); + data = context.data; + + if( o.sync ) + { + return data; + } + else + { + return con.take( data ); + } + + } + + /* error */ + + function handleError( err ) + { + + debugger; + err = _._err + ({ + // args : [ stack, '\nfileReadAct( ', o.filePath, ' )\n', err ], + args : [ err, '\nfileRead( ', o.filePath, ' )\n' ], + usingSourceCode : 0, + level : 0, + }); + + if( o.encoder && o.encoder.onError ) + try + { + err = o.encoder.onError.call( self, { error : err, operation : o, encoder : o.encoder }) + } + catch( err2 ) + { + console.error( err2 ); + console.error( err.toString() + '\n' + err.stack ); + } + + if( o.sync ) + { + throw err; + } + else + { + return con.error( err ); + } + + } + +} + +_.routineExtend( fileReadAct, Parent.prototype.fileReadAct ); + +// + +function dirReadAct( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( dirReadAct, o ); + + let result; + + if( o.sync ) + { + readDir(); + return result; + } + else + { + return _.time.out( 0, function() + { + readDir(); + return result; + }); + } + + /* */ + + function readDir() + { + o.filePath = self.pathResolveLinkFull({ filePath : o.filePath, resolvingSoftLink : 1 }).absolutePath; + + let file = self._descriptorRead( o.filePath ); + + if( file !== undefined ) + { + if( _.object.isBasic( file ) ) + { + result = Object.keys( file ); + } + else + { + result = self.path.name({ path : o.filePath, full : 1 }); + } + } + else + { + result = null; + throw _.err( 'File ', _.strQuote( o.filePath ), 'doesn`t exist!' );; + } + } + +} + +_.routineExtend( dirReadAct, Parent.prototype.dirReadAct ); + +// -- +// read stat +// - + +function statReadAct( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( statReadAct, o ); + + /* */ + + if( o.sync ) + { + return _statReadAct( o.filePath ); + } + else + { + return _.time.out( 0, function() + { + return _statReadAct( o.filePath ); + }) + } + + /* */ + + function _statReadAct( filePath ) + { + let result = null; + + if( o.resolvingSoftLink ) + { + + let o2 = + { + filePath, + resolvingSoftLink : o.resolvingSoftLink, + resolvingTextLink : 0, + }; + + filePath = self.pathResolveLinkFull( o2 ).absolutePath; + _.assert( o2.stat !== undefined ); + + if( !o2.stat && o.throwing ) + throw _.err( 'File', _.strQuote( filePath ), 'doesn`t exist!' ); + + return o2.stat; + } + else + { + filePath = self._pathResolveIntermediateDirs( filePath ); + } + + let d = self._descriptorRead( filePath ); + + if( !_.definedIs( d ) ) + { + if( o.throwing ) + throw _.err( 'File', _.strQuote( filePath ), 'doesn`t exist!' ); + return result; + } + + result = new _.files.FileStat(); + + if( self.extraStats && self.extraStats[ filePath ] ) + { + let extraStat = self.extraStats[ filePath ]; + result.atime = new Date( extraStat.atime ); + result.mtime = new Date( extraStat.mtime ); + result.ctime = new Date( extraStat.ctime ); + result.birthtime = new Date( extraStat.birthtime ); + result.ino = extraStat.ino || null; + result.dev = extraStat.dev || null; + } + + result.filePath = filePath; + result.isTerminal = returnFalse; + result.isDir = returnFalse; + result.isTextLink = returnFalse; /* qqq : implement and add coverage, please */ + result.isSoftLink = returnFalse; + result.isHardLink = returnFalse; /* qqq : implement and add coverage, please */ + result.isFile = returnFalse; + result.isDirectory = returnFalse; + result.isSymbolicLink = returnFalse; + result.nlink = 1; + + if( result.ino === null ) + result.ino = d; + + if( self._DescriptorIsDir( d ) ) + { + result.isDirectory = returnTrue; + result.isDir = returnTrue; + } + else if( self._DescriptorIsTerminal( d ) || self._DescriptorIsHardLink( d ) ) + { + if( self._DescriptorIsHardLink( d ) ) + { + if( _.arrayIs( d[ 0 ].hardLinks ) ) + result.nlink = d[ 0 ].hardLinks.length; + + d = d[ 0 ].data; + result.isHardLink = returnTrue; + } + + result.isTerminal = returnTrue; + result.isFile = returnTrue; + + if( _.numberIs( d ) ) + result.size = String( d ).length; + else if( _.strIs( d ) ) + result.size = d.length; + else + result.size = d.byteLength; + + _.assert( result.size >= 0 ); + + result.isTextLink = function isTextLink() + { + if( !self.usingTextLink ) + return false; + return self._DescriptorIsTextLink( d ); + } + } + else if( self._DescriptorIsSoftLink( d ) ) + { + result.isSymbolicLink = returnTrue; + result.isSoftLink = returnTrue; + } + // else if( self._DescriptorIsHardLink( d ) ) /* Dmytro : strange duplicate */ + // { + // _.assert( 0 ); + // // result.isHardLink = returnTrue; + // } + else if( self._DescriptorIsScript( d ) ) + { + result.isTerminal = returnTrue; + result.isFile = returnTrue; + } + + return result; + } + + /* */ + + function returnFalse() + { + return false; + } + + /* */ + + function returnTrue() + { + return true; + } + +} + +_.routineExtend( statReadAct, Parent.prototype.statReadAct ); + +// + +function fileExistsAct( o ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + _.assert( self.path.isNormalized( o.filePath ) ); + + let filePath = o.filePath; + + filePath = self._pathResolveIntermediateDirs( filePath ); + + let file = self._descriptorRead( filePath ); + return !!file; +} + +_.routineExtend( fileExistsAct, Parent.prototype.fileExistsAct ); + +// -- +// write +// -- + +function fileWriteAct( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( fileWriteAct, o ); + _.assert( self.path.isNormalized( o.filePath ) ); + _.assert( self.WriteMode.indexOf( o.writeMode ) !== -1 ); + + o.fileProvider = self; + o.encoder = fileWriteAct.encoders[ o.encoding ]; + // _.assert( o.encoding === null || o.encoding === undefined || _.object.is( o.encoder ), `encoder::${o.encoding} is not registered` ); + if( o.encoder && o.encoder.onSelect) + o.encoder.onSelect.call( self, o ); + + _.assert( self._DescriptorIsTerminal( o.data ), `Expects string or BufferNode, but got ${_.entity.strType( o.data )}` ); + + /* */ + + if( o.sync ) + { + write(); + } + else + { + return _.time.out( 0, () => write() ); + } + + /* */ + + function handleError( err ) + { + err = _.err( err ); + if( o.sync ) + throw err; + return new _.Consequence().error( err ); + } + + /* begin */ + + function handleBegin( read ) + { + if( !o.encoder ) + return o.data; + + _.assert( _.routineIs( o.encoder.onBegin ) ) + let context = { data : o.data, read, operation : o, encoder : o.encoder }; + _.sure( o.encoder.onBegin.call( self, context ) === undefined ); + + return context.data; + } + + /* */ + + function write() + { + + let filePath = o.filePath; + let descriptor = self._descriptorRead( filePath ); + let read; + + if( self._DescriptorIsLink( descriptor ) ) + { + let resolvedPath = self.pathResolveLinkFull + ({ + filePath, + allowingMissed : 1, + allowingCycled : 0, + resolvingSoftLink : 1, + resolvingTextLink : 0, + preservingRelative : 0, + throwing : 1 + }).absolutePath; + descriptor = self._descriptorRead( resolvedPath ); + filePath = resolvedPath; + + // descriptor should be missing/text/hard/terminal + _.assert + ( + descriptor === undefined + || self._DescriptorIsTerminal( descriptor ) + || self._DescriptorIsHardLink( descriptor ) + ); + + } + + let dstDir = self._descriptorRead( self.path.dir( filePath ) ); + if( !dstDir ) + throw _.err( 'Directory for', filePath, 'does not exist' ); + else if( !self._DescriptorIsDir( dstDir ) ) + throw _.err( 'Parent of', filePath, 'is not a directory' ); + + if( self._DescriptorIsDir( descriptor ) ) + throw _.err( 'Incorrect path to file!\nCan`t rewrite dir :', filePath ); + + let writeMode = o.writeMode; + + _.assert( _.longHas( self.WriteMode, writeMode ), 'Unknown write mode:' + writeMode ); + + if( descriptor === undefined || self._DescriptorIsLink( descriptor ) ) + { + if( self._DescriptorIsHardLink( descriptor ) ) + { + read = descriptor[ 0 ].data; + } + else + { + read = ''; + writeMode = 'rewrite'; + } + } + else + { + read = descriptor; + } + + let data = handleBegin( read ); + + _.assert( self._DescriptorIsTerminal( read ) ); + + /* qqq : xxx : rewrite using extending module::Tools */ + if( writeMode === 'append' || writeMode === 'prepend' ) + { + if( !o.encoder ) + { + //converts data from file to the type of o.data + if( _.strIs( data ) ) + { + if( !_.strIs( read ) ) + read = _.bufferToStr( read ); + } + else + { + _.assert( 0, 'not tested' ); + + if( _.bufferBytesIs( data ) ) + read = _.bufferBytesFrom( read ) + else if( _.bufferRawIs( data ) ) + read = _.bufferRawFrom( read ) + else + _.assert( 0, 'not implemented for:', _.entity.strType( data ) ); + } + } + + if( _.strIs( read ) ) + { + if( writeMode === 'append' ) + data = read + data; + else + data = data + read; + } + else + { + if( writeMode === 'append' ) + data = _.bufferJoin( read, data ); + else + data = _.bufferJoin( data, read ); + } + + } + else + { + _.assert( writeMode === 'rewrite', 'Not implemented write mode:', writeMode ); + } + + self._descriptorWrite( filePath, data ); + + /* what for is that needed ??? */ + /*self._descriptorRead({ selector : dstDir, set : structure });*/ + + return true; + } + +} + +_.routineExtend( fileWriteAct, Parent.prototype.fileWriteAct ); + +// + +function timeWriteAct( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.map.assertHasOnly( o, timeWriteAct.defaults ); + + let file = self._descriptorRead( o.filePath ); + if( !file ) + throw _.err( 'File:', o.filePath, 'doesn\'t exist. Can\'t set time stats.' ); + + self._timeWriteAct( o ); + +} + +_.routineExtend( timeWriteAct, Parent.prototype.timeWriteAct ); + +// + +function _timeWriteAct( o ) +{ + let self = this; + + if( !self.usingExtraStat ) + return; + + if( _.strIs( arguments[ 0 ] ) ) + o = { filePath : arguments[ 0 ] }; + + _.assert( self.path.isAbsolute( o.filePath ), o.filePath ); + _.assert( o.atime === undefined || o.atime === null || _.numberIs( o.atime ) ); + _.assert( o.mtime === undefined || o.mtime === null || _.numberIs( o.mtime ) ); + _.assert( o.ctime === undefined || o.ctime === null || _.numberIs( o.ctime ) ); + _.assert( o.birthtime === undefined || o.birthtime === null || _.numberIs( o.birthtime ) ); + + let extra = self.extraStats[ o.filePath ]; + + if( !extra ) + { + extra = self.extraStats[ o.filePath ] = Object.create( null ); + extra.atime = null; + extra.mtime = null; + extra.ctime = null; + extra.birthtime = null; + extra.ino = ++Self.InoCounter; + Object.preventExtensions( extra ); + } + + if( o.atime ) + extra.atime = o.atime; + + if( o.mtime ) + extra.mtime = o.mtime; + + if( o.ctime ) + extra.ctime = o.ctime; + + if( o.birthtime ) + extra.birthtime = o.birthtime; + + if( o.updatingDir ) + { + let dirPath = self.path.dir( o.filePath ); + if( dirPath === '/' ) + return; + + extra.birthtime = null; + + _.assert( !!o.atime && !!o.mtime && !!o.ctime ); + _.assert( o.atime === o.mtime && o.mtime === o.ctime ); + + o.filePath = dirPath; + + self._timeWriteAct( o ); + } + + return extra; +} + +_timeWriteAct.defaults = +{ + filePath : null, + atime : null, + mtime : null, + ctime : null, + birthtime : null, + updatingDir : false +} + +// + +function fileDeleteAct( o ) +{ + let self = this; + + _.routine.assertOptions( fileDeleteAct, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( self.path.isNormalized( o.filePath ) ); + + if( o.sync ) + { + act(); + } + else + { + return _.time.out( 0, () => act() ); + } + + /* - */ + + function act() + { + let filePath = o.filePath; + + let stat = self.statReadAct + ({ + filePath, + resolvingSoftLink : 0, + sync : 1, + throwing : 0, + }); + + if( !stat ) + { + debugger; + throw _.err( 'Path', _.strQuote( o.filePath ), 'doesn`t exist!' ); + } + + /* Vova: intermediate dirs should be resolved, stat.filePath stores that resolved path */ + + filePath = stat.filePath; + + let file = self._descriptorRead( filePath ); + if( self._DescriptorIsDir( file ) && Object.keys( file ).length ) + { + debugger; + throw _.err( 'Directory is not empty : ' + _.strQuote( o.filePath ) ); + } + + let dirPath = self.path.dir( filePath ); + let dir = self._descriptorRead( dirPath ); + + _.sure( !!dir, () => `Cant delete root directory ${ o.filePath }` ); + + let fileName = self.path.nativize( self.path.name({ path : filePath, full : 1 }) ); + delete dir[ fileName ]; + + delete self.extraStats[ o.filePath ]; + self._descriptorTimeUpdate( dirPath, 0 ); + + return true; + } + +} + +_.routineExtend( fileDeleteAct, Parent.prototype.fileDeleteAct ); + +// + +function dirMakeAct( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( dirMakeAct, o ); + + /* */ + + if( o.sync ) + { + __make(); + } + else + { + return _.time.out( 0, () => __make() ); + } + + /* - */ + + function __make( ) + { + if( self._descriptorRead( o.filePath ) ) + { + debugger; + throw _.err( 'File', _.strQuote( o.filePath ), 'already exists!' ); + } + + // _.assert( !!self._descriptorRead( self.path.dir( o.filePath ) ), 'Directory ', _.strQuote( o.filePath ), ' doesn\'t exist!' ); + + let dstDir = self._descriptorRead( self.path.dir( o.filePath ) ); + if( !dstDir ) + throw _.err( 'Directory for', o.filePath, 'does not exist' ); + else if( !self._DescriptorIsDir( dstDir ) ) + throw _.err( 'Parent of', o.filePath, 'is not a directory' ); + + self._descriptorWrite( o.filePath, Object.create( null ) ); + + return true; + } + +} + +_.routineExtend( dirMakeAct, Parent.prototype.dirMakeAct ); + +// + +function fileLockAct( o ) +{ + let self = this; + + _.assert( !o.locking, 'not implemented' ); + _.assert( !o.sharing || o.sharing === 'process', 'not implemented' ); + _.assert( self.path.isNormalized( o.filePath ) ); + _.assert( !o.waiting || o.timeOut >= 1000 ); + _.routine.assertOptions( fileLockAct, arguments ); + + let con = _.Consequence.Try( () => + { + if( !self._descriptorRead( o.filePath ) ) + throw _.err( 'File:', o.filePath, 'doesn\'t exist.' ); + + let lockFilePath = o.filePath + '.lock'; + + if( self.lockMap ) + if( self.lockMap[ o.filePath ] ) + if( self._descriptorRead( lockFilePath ) ) + { + if( !o.sharing ) + throw _.err( 'File', o.filePath, 'is already locked by current process' ); + + if( !o.waiting ) + { + return true; + } + else if( o.sync ) + { + throw _.err + ( + 'File', o.filePath, 'is already locked by current process.', + 'With option {-o.waiting-} enabled, lock will be waiting for itself.', + 'Please use existing lock or execute method with {-o.sync-} set to 0.' + ) + } + } + + let tries, con; + + if( !o.waiting ) + { + return lock(); + } + else + { + tries = o.timeOut / 1000; + con = new _.Consequence(); + + lockTry(); + + return con; + } + + /* */ + + function lock() + { + let lockFileDescriptor = self._descriptorRead( lockFilePath ); + + if( lockFileDescriptor ) + throw _.err( 'File:', o.filePath, 'is locked, but lock file is not associated with current extract instance.' ); + + self._descriptorWrite( lockFilePath, o.filePath ); + return true; + } + + function lockTry() + { + tries -= 1; + try + { + let result = lock(); + con.take( result ); + } + catch( err ) + { + if( tries < 0 ) + return con.error( err ); + + _.time.out( 1000, () => + { + lockTry(); + return null; + }) + } + } + }) + + con.then( ( got ) => + { + if( self.lockMap === null ) + self.lockMap = Object.create( null ); + + if( self.lockMap[ o.filePath ] === undefined ) + self.lockMap[ o.filePath ] = 0; + + self.lockMap[ o.filePath ] += 1; + + return true; + }) + + if( o.sync ) + return con.sync(); + + return con; +} + +_.routineExtend( fileLockAct, Parent.prototype.fileLockAct ); + +// + +function fileUnlockAct( o ) +{ + let self = this; + + _.assert( self.path.isNormalized( o.filePath ) ); + _.routine.assertOptions( fileUnlockAct, arguments ); + + let con = _.Consequence.Try( () => + { + if( !self._descriptorRead( o.filePath ) ) + throw _.err( 'File:', o.filePath, 'doesn\'t exist.' ); + + let lockFilePath = o.filePath + '.lock'; + let lockFileDescriptor = self._descriptorRead( lockFilePath ); + + if( self.lockMap ) + if( self.lockMap[ o.filePath ] !== undefined ) + { + _.assert( self.lockMap[ o.filePath ] > 0 ); + + self.lockMap[ o.filePath ] -= 1; + + if( self.lockMap[ o.filePath ] > 0 ) + return true; + + if( !lockFileDescriptor ) + return true; + + let con = self.fileDeleteAct({ filePath : lockFilePath, sync : o.sync }); + + if( o.sync ) + return true; + + return con; + } + + if( lockFileDescriptor ) + throw _.err( 'File:', o.filePath, 'is locked, but lock file is not associated with current extract instance.' ); + else + throw _.err( 'File:', o.filePath, 'is not locked.' ); + }) + + con.then( ( got ) => + { + if( self.lockMap[ o.filePath ] === 0 ) + { + delete self.lockMap[ o.filePath ]; + } + + return true; + }) + + if( o.sync ) + return con.sync(); + + return con; +} + +_.routineExtend( fileUnlockAct, Parent.prototype.fileUnlockAct ); + +// + +function fileIsLockedAct( o ) +{ + let self = this; + + _.routine.assertOptions( fileIsLockedAct, arguments ); + _.assert( self.path.isNormalized( o.filePath ) ); + + let con = _.Consequence.Try( () => + { + if( !self._descriptorRead( o.filePath ) ) + throw _.err( 'File:', o.filePath, 'doesn\'t exist.' ); + + let lockFilePath = o.filePath + '.lock'; + let lockFileDescriptor = self._descriptorRead( lockFilePath ); + return !!lockFileDescriptor; + }) + + if( o.sync ) + return con.sync(); + + return con; +} + +_.routineExtend( fileIsLockedAct, Parent.prototype.fileIsLockedAct ); + + +// -- +// linkingAction +// -- + +function fileRenameAct( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( fileRenameAct, arguments ); + _.assert( self.path.isNormalized( o.srcPath ) ); + _.assert( self.path.isNormalized( o.dstPath ) ); + + if( o.sync ) + { + return rename(); + } + else + { + return _.time.out( 0, () => rename() ); + } + + /* - */ + + /* rename */ + + function rename( ) + { + let dstName = self.path.nativize( self.path.name({ path : o.dstPath, full : 1 }) ); + let srcName = self.path.nativize( self.path.name({ path : o.srcPath, full : 1 }) ); + let srcDirPath = self.path.dir( o.srcPath ); + let dstDirPath = self.path.dir( o.dstPath ); + + let srcDir = self._descriptorReadResolved( srcDirPath ); + if( !srcDir || !srcDir[ srcName ] ) + throw _.err( 'Source path', _.strQuote( o.srcPath ), 'doesn`t exist!' ); + + /* */ + + let dstDir = self._descriptorReadResolved( dstDirPath ); + if( !dstDir ) + throw _.err( 'Directory for', o.dstPath, 'does not exist' ); + else if( !self._DescriptorIsDir( dstDir ) ) + throw _.err( 'Parent of', o.dstPath, 'is not a directory' ); + if( dstDir[ dstName ] ) + throw _.err( 'Destination path', _.strQuote( o.dstPath ), 'already exists!' ); + + dstDir[ dstName ] = srcDir[ srcName ]; + delete srcDir[ srcName ]; + + self.extraStats[ o.dstPath ] = self.extraStats[ o.srcPath ]; + delete self.extraStats[ o.srcPath ]; + + if( dstDir !== srcDir ) + { + self._descriptorTimeUpdate( srcDirPath, 0 ); + self._descriptorTimeUpdate( dstDirPath, 0 ); + } + + return true; + } + +} + +_.routineExtend( fileRenameAct, Parent.prototype.fileRenameAct ); + +// + +function fileCopyAct( o ) +{ + let self = this; + let srcFile; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.assertOptions( fileCopyAct, arguments ); + _.assert( self.path.isNormalized( o.srcPath ) ); + _.assert( self.path.isNormalized( o.dstPath ) ); + + if( o.sync ) // qqq : synchronize async version aaa : done + { + _copyPre(); + + let dstStat = self.statReadAct + ({ + filePath : o.dstPath, + resolvingSoftLink : 0, + sync : 1, + throwing : 0, + }); + + // let srcStat = self.statReadAct + // ({ + // filePath : o.srcPath, + // resolvingSoftLink : 0, + // sync : 1, + // throwing : 0, + // }); + + _.assert( self.isTerminal( o.srcPath ), () => _.strQuote( o.srcPath ), 'is not terminal' ); + + /* qqq : ? aaa : redundant, just copy the descriptor instead of this */ + // if( self.isSoftLink( o.srcPath ) ) + // { + // if( self.fileExistsAct({ filePath : o.dstPath }) ) + // self.fileDeleteAct({ filePath : o.dstPath, sync : 1 }) + // return self.softLinkAct + // ({ + // originalDstPath : o.originalDstPath, + // originalSrcPath : o.originalSrcPath, + // srcPath : self.pathResolveSoftLink( o.srcPath ), + // dstPath : o.dstPath, + // sync : o.sync, + // type : null + // }) + // } + // self.fileWriteAct({ filePath : o.dstPath, data : srcFile, sync : 1 }); + + let data = self.fileRead({ filePath : o.srcPath, encoding : 'meta.original', sync : 1, resolvingTextLink : 0 }); + _.assert( data !== null && data !== undefined ); + + if( dstStat ) + if( dstStat.isSoftLink() ) + { + o.dstPath = self.pathResolveLinkFull + ({ + filePath : o.dstPath, + allowingMissed : 1, + allowingCycled : 0, + resolvingSoftLink : 1, + resolvingTextLink : 0, + preservingRelative : 0, + throwing : 1 + }).absolutePath; + } + + self._descriptorWrite( o.dstPath, data ); + + } + else + { + let con = new _.Consequence().take( null ); + let dstStat, data; + + con.then( () => + { + _copyPre(); + return self.statReadAct + ({ + filePath : o.dstPath, + resolvingSoftLink : 0, + sync : 0, + throwing : 0, + }) + }) + .then( ( got ) => + { + dstStat = got; + return null; + }) + .then( () => + { + return self.fileRead + ({ + filePath : o.srcPath, + encoding : 'meta.original', + sync : 0, + resolvingTextLink : 0 + }) + }) + .then( ( got ) => + { + data = got; + + _.assert( data !== null && data !== undefined ); + + if( dstStat ) + if( dstStat.isSoftLink() ) + return self.pathResolveLinkFull + ({ + filePath : o.dstPath, + allowingMissed : 1, + allowingCycled : 0, + resolvingSoftLink : 1, + resolvingTextLink : 0, + preservingRelative : 0, + sync : 0, + throwing : 1 + }) + .then( ( resolved ) => + { + o.dstPath = resolved.absolutePath; + return true; + }) + + return true; + }) + .then( () => + { + self._descriptorWrite( o.dstPath, data ); + return true; + }) + + return con; + } + + /* - */ + + function _copyPre( ) + { + + let srcIsTerminal = self.isTerminal( o.srcPath ); + if( !srcIsTerminal ) + { + debugger; + throw _.err( 'File', _.strQuote( o.srcPath ), 'doesn`t exist or isn`t terminal!' ); + } + + let dstDirIsDir = self.isDir( self.path.dir( o.dstPath ) ); + if( !dstDirIsDir ) + { + debugger; + throw _.err( 'File', _.strQuote( self.path.dir( o.dstPath ) ), 'doesn`t exist or isn`t directory!' ); + } + + // srcFile = self._descriptorRead( o.srcPath ); + // + // if( !srcFile ) + // { + // debugger; + // throw _.err( 'File', _.strQuote( o.srcPath ), 'doesn`t exist!' ); + // } + // + // if( self._DescriptorIsDir( srcFile ) ) + // { + // debugger; + // throw _.err( o.srcPath, ' is not a terminal file!' ); + // } + + // let dstDir = self._descriptorRead( self.path.dir( o.dstPath ) ); + // if( !dstDir ) + // throw _.err( 'Directory for', o.dstPath, 'does not exist' ); + + // let dstDir = self._descriptorRead( self.path.dir( o.dstPath ) ); + // if( !dstDir ) + // throw _.err( 'Directory for', o.dstPath, 'does not exist' ); + // else if( !self._DescriptorIsDir( dstDir ) ) + // throw _.err( 'Parent of', o.dstPath, 'is not a directory' ); + + let dstIsDir = self.isDir( o.dstPath ); + // let dstPath = self._descriptorRead( o.dstPath ); + // if( self._DescriptorIsDir( dstPath ) ) + if( dstIsDir ) + throw _.err( 'Can`t rewrite directory by terminal file : ' + o.dstPath ); + + return true; + } + +} + +_.routineExtend( fileCopyAct, Parent.prototype.fileCopyAct ); + +// + +function softLinkAct( o ) +{ + let self = this; + + // debugger + _.routine.assertOptions( softLinkAct, arguments ); + + _.assert( self.path.is( o.srcPath ) ); + _.assert( self.path.isAbsolute( o.dstPath ) ); + _.assert( self.path.isNormalized( o.srcPath ) ); + _.assert( self.path.isNormalized( o.dstPath ) ); + + // if( !self.path.isAbsolute( o.originalSrcPath ) ) + // debugger; + // if( !self.path.isAbsolute( o.originalSrcPath ) ) + // o.srcPath = o.originalSrcPath; + + if( o.sync ) + { + // if( o.dstPath === o.srcPath ) + // return true; + + if( self.statRead( o.dstPath ) ) + throw _.err( 'softLinkAct', o.dstPath, 'already exists' ); + + dstDirCheck(); + + /* + qqq : add tests for linkingAction act routines + qqq : don't forget throwing cases + */ + + self._descriptorWrite( o.dstPath, self._DescriptorSoftLinkMake( o.relativeSrcPath ) ); + + return true; + } + else + { + // if( o.dstPath === o.srcPath ) + // return new _.Consequence().take( true ); + + return self.statRead({ filePath : o.dstPath, sync : 0 }) + .finally( ( err, stat ) => + { + if( err ) + throw _.err( err ); + + if( stat ) + throw _.err( 'softLinkAct', o.dstPath, 'already exists' ); + + + dstDirCheck(); + + self._descriptorWrite( o.dstPath, self._DescriptorSoftLinkMake( o.relativeSrcPath ) ); + + return true; + }) + } + + /* */ + + function dstDirCheck() + { + let dstDir = self._descriptorReadResolved( self.path.dir( o.dstPath ) ); + if( !dstDir ) + throw _.err( 'Directory for', o.dstPath, 'does not exist' ); + else if( !self._DescriptorIsDir( dstDir ) ) + throw _.err( 'Parent of', o.dstPath, 'is not a directory' ); + } +} + +_.routineExtend( softLinkAct, Parent.prototype.softLinkAct ); + +// + +function hardLinkAct( o ) +{ + let self = this; + + _.routine.assertOptions( hardLinkAct, arguments ); + _.assert( self.path.isNormalized( o.srcPath ) ); + _.assert( self.path.isNormalized( o.dstPath ) ); + + let con = _.Consequence().take( true ); + + if( o.dstPath === o.srcPath ) + return o.sync ? true : con; + + let dstPath = o.dstPath; + let srcPath = o.srcPath; + + con.then( checkPaths ) + + if( o.context ) + { + con.then( () => o.context.tempRenameMaybe() ) + con.then( handleHardlinkBreaking ); + } + + con.then( link ); + + if( o.context ) + { + con.then( tempDelete ); + con.finally( tempRenameRevert ); + } + + if( o.sync ) + return con.sync(); + + return con; + + /* */ + + function checkPaths() + { + var con = _.Consequence.Try( () => + { + return self.statReadAct + ({ + filePath : o.srcPath, + throwing : 0, + sync : o.sync, + resolvingSoftLink : 0, + }); + }) + + con.then( function( stat ) + { + if( !stat ) + throw _.err( '{o.srcPath} does not exist on hard drive:', o.srcPath ); + if( !stat.isTerminal() ) + throw _.err( '{o.srcPath} is not a terminal file:', o.srcPath ); + return true; + }); + + if( o.sync ) + return con.sync(); + + return con; + } + + /* */ + + function handleHardlinkBreaking() + { + let c = o.context; + + if( c.options.breakingSrcHardLink ) + if( !self.fileExists( o.dstPath ) ) + { + if( c.srcStat.isHardLink() ) + return self.hardLinkBreak({ filePath : o.srcPath, sync : o.sync }); + } + else + { + if( !c.options.breakingDstHardLink ) + if( c.dstStat.isHardLink() ) + { + let con = _.Consequence.Try( () => + { + return self.fileReadAct + ({ + filePath : o.srcPath, + encoding : self.encoding, + advanced : null, + resolvingSoftLink : self.resolvingSoftLink, + sync : o.sync + }) + }) + .then( ( srcData ) => + { + let r = self.fileWriteAct + ({ + filePath : o.dstPath, + data : srcData, + encoding : 'meta.original', + writeMode : 'rewrite', + sync : o.sync, + advanced : null, + }) + return o.sync ? true : r; + }) + .then( () => + { + let r = self.fileDeleteAct + ({ + filePath : o.srcPath, + sync : o.sync + }) + return o.sync ? true : r; + }) + .then( () => + { + let dstPathTemp = dstPath; + dstPath = srcPath + srcPath = dstPathTemp; + return null; + }) + + if( o.sync ) + return con.sync(); + + return con; + } + } + return null; + } + + /* */ + + function link() + { + if( self.fileExists( dstPath ) ) + throw _.err( dstPath, 'already exists' ); + + let dstDir = self._descriptorRead( self.path.dir( dstPath ) ); + if( !dstDir ) + throw _.err( 'Directory for', dstPath, 'does not exist' ); + else if( !self._DescriptorIsDir( dstDir ) ) + throw _.err( 'Parent of', dstPath, 'is not a directory' ); + + let srcDescriptor = self._descriptorRead( srcPath ); + let descriptor = self._DescriptorHardLinkMake( [ dstPath, srcPath ], srcDescriptor ); + if( srcDescriptor !== descriptor ) + self._descriptorWrite( srcPath, descriptor ); + self._descriptorWrite( dstPath, descriptor ); + + if( self.usingExtraStat ) + self.extraStats[ o.dstPath ] = self.extraStats[ o.srcPath ]; /* Vova : check which stats hardlinked files should have in common */ + + return true; + } + + /* */ + + function tempDelete( got ) + { + let r = _.Consequence.Try( () => + { + let result = o.context.tempDelete(); + return o.sync ? true : result; + }) + r.then( () => got ); + + if( o.sync ) + return r.sync(); + + return r; + } + + /* */ + + function tempRenameRevert( err, got ) + { + if( !err ) + return got; + + _.errAttend( err ); + + let r = _.Consequence.Try( () => + { + let result = o.context.tempRenameRevert() + return o.sync ? true : result; + }) + .finally( () => + { + throw _.err( err ); + }) + + if( o.sync ) + return r.sync(); + + return r; + } + +} + +_.routineExtend( hardLinkAct, Parent.prototype.hardLinkAct ); + +// -- +// link +// -- + +function hardLinkBreakAct( o ) +{ + let self = this; + let descriptor = self._descriptorRead( o.filePath ); + + _.assert( self._DescriptorIsHardLink( descriptor ) ); + + // let read = self._descriptorResolve({ descriptor : descriptor }); + // _.assert( self._DescriptorIsTerminal( read ) ); + + let con = _.Consequence.Try( () => + { + _.arrayRemoveOnce( descriptor[ 0 ].hardLinks, o.filePath ); + + self._descriptorWrite + ({ + filePath : o.filePath, + data : descriptor[ 0 ].data, + breakingHardLink : true + }); + + return true; + }) + + if( o.sync ) + return con.sync(); + + return con; +} + +_.routineExtend( hardLinkBreakAct, Parent.prototype.hardLinkBreakAct ); + +// + +function areHardLinkedAct( o ) +{ + let self = this; + + _.routine.assertOptions( areHardLinkedAct, arguments ); + _.assert( o.filePath.length === 2, 'Expects exactly two arguments' ); + + if( o.filePath[ 0 ] === o.filePath[ 1 ] ) + return true; + + let filePath1 = self._pathResolveIntermediateDirs( o.filePath[ 0 ] ); + let filePath2 = self._pathResolveIntermediateDirs( o.filePath[ 1 ] ); + + if( filePath1 === filePath2 ) + return true; + + let descriptor1 = self._descriptorRead( filePath1 ); + let descriptor2 = self._descriptorRead( filePath2 ); + + if( !self._DescriptorIsHardLink( descriptor1 ) ) + return false; + if( !self._DescriptorIsHardLink( descriptor2 ) ) + return false; + + if( descriptor1 === descriptor2 ) + return true; + + _.assert + ( + !_.longHas( descriptor1[ 0 ].hardLinks, o.filePath[ 1 ] ), + 'Hardlinked files are desynchronized, two hardlinked files should share the same descriptor, but those do not :', + '\n', o.filePath[ 0 ], + '\n', o.filePath[ 1 ] + ); + + return false; +} + +_.routineExtend( areHardLinkedAct, Parent.prototype.areHardLinkedAct ); + +// -- +// etc +// -- + +function isInoAct( o ) +{ + let self = this; + _.routine.assertOptions( isInoAct, arguments ); + + if( self.usingExtraStat ) + { + if( _.numberIs( o.ino ) || _.bigIntIs( o.ino ) ) + return true; + } + else + { + return self._DescriptorIs( o.ino ); + } + + return false; +} + +isInoAct.defaults = +{ + ... Parent.prototype.isInoAct.defaults, +} + +// + +function filesTreeSet( src ) +{ + let self = this; + + if( self[ filesTreeSymbol ] === src ) + return src; + + _.mapDelete( self.extraStats ); + + self[ filesTreeSymbol ] = src; + + if( src && _.props.keys( src ).length && self.usingExtraStat ) + self.statsAdopt(); + + return src; +} + +// + +function statsAdopt() +{ + let self = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + self.filesFindNominal( '/', ( r ) => + { + self._timeWriteAct({ filePath : r.absolute, atime : r.stat.atime || _.time.now() }); + return r; + }); + + return self; +} + +// + +// function linksRebase( o ) +// { +// let self = this; +// +// _.routine.options_( linksRebase, o ); +// _.assert( arguments.length === 1, 'Expects single argument' ); +// _.assert( 0, 'not tested' ); +// +// self.filesFind +// ({ +// filePath : o.filePath, +// recursive : 2, +// onUp : onUp, +// }); +// +// function onUp( file ) +// { +// let descriptor = self._descriptorRead( file.absolute ); +// +// if( self._DescriptorIsHardLink( descriptor ) ) +// { +// debugger; +// descriptor = descriptor[ 0 ]; +// let was = descriptor.hardLink; +// let url = _.uri.parseAtomic( descriptor.hardLink ); +// url.longPath = self.path.rebase( url.longPath, o.oldPath, o.newPath ); +// descriptor.hardLink = _.uri.str( url ); +// logger.log( '* linksRebase :', descriptor.hardLink, '<-', was ); +// debugger; +// } +// +// return file; +// } +// +// } +// +// linksRebase.defaults = +// { +// filePath : '/', +// oldPath : '', +// newPath : '', +// } + +// -- +// +// -- + +function _pathResolveIntermediateDirs( filePath ) +{ + let self = this; + + // resolves intermediate dir(s) except terminal + + _.assert( self.path.isAbsolute( filePath ) ); + _.assert( self.path.isNormalized( filePath ) ); + + if( _.strCount( filePath, self.path.upToken ) > 1 ) + { + let fileName = self.path.name({ path : filePath, full : 1 }); + filePath = self.pathResolveSoftLinkAct + ({ + filePath : self.path.dir( filePath ), + resolvingIntermediateDirectories : 1, + resolvingMultiple : 1 + }); + filePath = self.path.join( filePath, fileName ); + } + + return filePath; + +} + +// -- +// descriptor read +// -- + +function _descriptorRead( o ) +{ + let self = this; + let path = self.path; + + if( _.strIs( arguments[ 0 ] ) ) + o = { filePath : arguments[ 0 ] }; + + _.routine.options_( _descriptorRead, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( !path.isGlobal( o.filePath ), 'Expects local path, but got', o.filePath ); + + if( o.upToken === null ) + o.upToken = [ './', '/' ]; + if( o.filePath === '.' ) + o.filePath = ''; + if( !o.filesTree ) + o.filesTree = self.filesTree; + + let o2 = Object.create( null ); + + // o2.setting = 0; + o2.action = _.Selector.Action.no; + o2.selector = o.filePath; + o2.src = o.filesTree; + o2.upToken = o.upToken; + // o2.usingIndexedAccessToMap = 0; + o2.globing = 0; + + // if( _.strEnds( o2.selector, '"?a8"' ) ) + // debugger; + + let result = _.select( o2 ); + + return result; +} + +_descriptorRead.defaults = +{ + filePath : null, + filesTree : null, + upToken : null, +} + +// + +function _descriptorReadResolved( o ) +{ + let self = this; + + if( _.strIs( arguments[ 0 ] ) ) + o = { filePath : arguments[ 0 ] }; + + let filePath = self._pathResolveIntermediateDirs( o.filePath ); + + let result = self._descriptorRead( filePath ); + + if( self._DescriptorIsLink( result ) ) + { + let filePathResolved = self.pathResolveLinkFull + ({ + filePath, + allowingMissed : 1, + allowingCycled : 0, + resolvingSoftLink : 1, + resolvingTextLink : 0, + preservingRelative : 0, + throwing : 1 + }); + result = self._descriptorRead( filePathResolved.absolutePath ); + // result = self._descriptorResolve({ descriptor : result }); + } + + return result; +} + +_.routineExtend( _descriptorReadResolved, _descriptorRead ); + +// + +function _descriptorResolve( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( o.descriptor ); + _.routine.options_( _descriptorResolve, o ); + self._providerDefaultsApply( o ); + _.assert( !o.resolvingTextLink ); + + if( self._DescriptorIsHardLink( o.descriptor ) /* && self.resolvingHardLink */ ) + { + return self._descriptorResolveHardLink( o.descriptor ); + // o.descriptor = self._descriptorResolveHardLink( o.descriptor ); + // return self._descriptorResolve + // ({ + // descriptor : o.descriptor, + // // resolvingHardLink : o.resolvingHardLink, + // resolvingSoftLink : o.resolvingSoftLink, + // resolvingTextLink : o.resolvingTextLink, + // }); + } + + if( self._DescriptorIsSoftLink( o.descriptor ) && self.resolvingSoftLink ) + { + o.descriptor = self._descriptorResolveSoftLink( o.descriptor ); + return self._descriptorResolve + ({ + descriptor : o.descriptor, + // resolvingHardLink : o.resolvingHardLink, + resolvingSoftLink : o.resolvingSoftLink, + resolvingTextLink : o.resolvingTextLink, + }); + } + + return o.descriptor; +} + +_descriptorResolve.defaults = +{ + descriptor : null, + // resolvingHardLink : null, + resolvingSoftLink : null, + resolvingTextLink : null, +} + +// function _descriptorResolvePath( o ) +// { +// let self = this; + +// _.assert( arguments.length === 1, 'Expects single argument' ); +// _.assert( o.descriptor ); +// _.routine.options_( _descriptorResolve, o ); +// self._providerDefaultsApply( o ); +// _.assert( !o.resolvingTextLink ); + +// let descriptor = self._descriptorRead( o.descriptor ); + +// if( self._DescriptorIsHardLink( descriptor ) && self.resolvingHardLink ) +// { +// o.descriptor = self._descriptorResolveHardLinkPath( descriptor ); +// return self._descriptorResolvePath +// ({ +// descriptor : o.descriptor, +// resolvingHardLink : o.resolvingHardLink, +// resolvingSoftLink : o.resolvingSoftLink, +// resolvingTextLink : o.resolvingTextLink, +// }); +// } + +// if( self._DescriptorIsSoftLink( descriptor ) && self.resolvingSoftLink ) +// { +// o.descriptor = self._descriptorResolveSoftLinkPath( descriptor ); +// return self._descriptorResolvePath +// ({ +// descriptor : o.descriptor, +// resolvingHardLink : o.resolvingHardLink, +// resolvingSoftLink : o.resolvingSoftLink, +// resolvingTextLink : o.resolvingTextLink, +// }); +// } + +// return o.descriptor; +// } + +// _descriptorResolvePath.defaults = +// { +// descriptor : null, +// resolvingHardLink : null, +// resolvingSoftLink : null, +// resolvingTextLink : null, +// } + +// + +// function _descriptorResolveHardLinkPath( descriptor ) +// { +// let self = this; +// descriptor = descriptor[ 0 ]; +// +// _.assert( descriptor.data !== undefined ); +// return descriptor.data; +// +// // _.assert( !!descriptor.hardLink ); +// // return descriptor.hardLink; +// } + +// + +function _descriptorResolveHardLink( descriptor ) +{ + let self = this; + let result; + + _.assert( descriptor.data !== undefined ); + return descriptor.data; + + // let filePath = self._descriptorResolveHardLinkPath( descriptor ); + // let url = _.uri.parse( filePath ); + // + // _.assert( arguments.length === 1 ) + // + // if( url.protocol ) + // { + // debugger; + // throw _.err( 'not implemented' ); + // // _.assert( url.protocol === 'file', 'can handle only "file" protocol, but got', url.protocol ); + // // result = _.fileProvider.fileRead( url.localPath ); + // // _.assert( _.strIs( result ) ); + // } + // else + // { + // debugger; + // result = self._descriptorRead( url.localPath ); + // } + + return result; +} + +// + +function _descriptorResolveSoftLinkPath( descriptor, withPath ) +{ + let self = this; + descriptor = descriptor[ 0 ]; + _.assert( !!descriptor.softLink ); + return descriptor.softLink; +} + +// + +function _descriptorResolveSoftLink( descriptor ) +{ + let self = this; + let result; + let filePath = self._descriptorResolveSoftLinkPath( descriptor ); + let url = _.uri.parse( filePath ); + + _.assert( arguments.length === 1 ) + + if( url.protocol ) + { + debugger; + throw _.err( 'not implemented' ); + // _.assert( url.protocol === 'file', 'can handle only "file" protocol, but got', url.protocol ); + // result = _.fileProvider.fileRead( url.localPath ); + // _.assert( _.strIs( result ) ); + } + else + { + debugger; + result = self._descriptorRead( url.resourcePath ); + } + + return result; +} + +// + +function _DescriptorIs( file ) +{ + if( file === undefined ) + return false; + return true; +} + +// + +function _DescriptorIsDir( file ) +{ + return _.object.isBasic( file ); +} + +// + +function _DescriptorIsTerminal( file ) +{ + if( _.strIs( file ) ) + return true; + if( _.numberIs( file ) ) + return true; + if( _.bufferRawIs( file ) ) + return true; + if( _.bufferTypedIs( file ) ) + return true; + if( _.bufferNodeIs( file ) ) + return true; + return false; +} + +// + +function _DescriptorIsLink( file ) +{ + if( !_.arrayIs( file ) ) + return false; + + // if( _.arrayIs( file ) ) + // { + _.assert( file.length === 1 ); + file = file[ 0 ]; + // } + _.assert( !!file ); + return !!( file.hardLinks || file.softLink ); +} + +// + +function _DescriptorIsSoftLink( file ) +{ + if( !_.arrayIs( file ) ) + return false; + + // if( _.arrayIs( file ) ) + // { + _.assert( file.length === 1 ); + file = file[ 0 ]; + // } + _.assert( !!file ); + return !!file.softLink; +} + +// + +function _DescriptorIsHardLink( file ) +{ + if( !_.arrayIs( file ) ) + return false; + + // if( _.arrayIs( file ) ) + // { + _.assert( file.length === 1 ); + file = file[ 0 ]; + // } + + _.assert( !!file ); + _.assert( !file.hardLink ); + + return !!file.hardLinks; +} + +// + +function _DescriptorIsTextLink( file ) +{ + if( !_.definedIs( file ) ) + return false; + if( _.arrayIs( file ) ) + return false; + if( _.object.isBasic( file ) ) + return false; + + let regexp = /^link ([^\n]+)\n?$/; + if( _.bufferRawIs( file ) || _.bufferTypedIs( file ) ) + file = _.bufferToStr( file ) + _.assert( _.strIs( file ) ); + return regexp.test( file ); +} + +// + +function _DescriptorIsScript( file ) +{ + if( !_.arrayIs( file ) ) + return false; + + // if( _.arrayIs( file ) ) + // { + _.assert( file.length === 1 ); + file = file[ 0 ]; + // } + + _.assert( !!file ); + return !!file.code; +} + +// -- +// descriptor write +// -- + +function _descriptorWrite( o ) +{ + let self = this; + + if( _.strIs( arguments[ 0 ] ) ) + o = { filePath : arguments[ 0 ], data : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + + _.routine.options_( _descriptorWrite, o ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + if( o.upToken === null ) + o.upToken = [ './', '/' ]; + if( o.filePath === '.' ) + o.filePath = ''; + + if( !o.filesTree ) + { + _.assert( _.objectLike( self.filesTree ) ); + o.filesTree = self.filesTree; + } + + o.filePath = self._pathResolveIntermediateDirs( o.filePath ) + + let file = self._descriptorRead( o.filePath ); + let willBeCreated = file === undefined; + let time = _.time.now(); + + let result; + + if( !o.breakingHardLink && self._DescriptorIsHardLink( file ) ) + { + result = file[ 0 ].data = o.data; + } + else + { + let o2 = Object.create( null ); + + // o2.setting = 1; + o2.action = _.Selector.Action.set; + o2.set = o.data; + o2.selector = o.filePath; + o2.src = o.filesTree; + o2.upToken = o.upToken; + // o2.usingIndexedAccessToMap = 0; + o2.globing = 0; + + result = _.select( o2 ); + } + + o.filePath = self.path.join( '/', o.filePath ); + + let timeOptions = + { + filePath : o.filePath, + ctime : time, + mtime : time + } + + if( willBeCreated ) + { + timeOptions.atime = time; + timeOptions.birthtime = time; + timeOptions.updatingDir = 1; + } + + if( self.usingExtraStat ) + self._timeWriteAct( timeOptions ); + + return result; +} + +_descriptorWrite.defaults = +{ + filePath : null, + filesTree : null, + data : null, + upToken : null, + breakingHardLink : false +} + +// + +function _descriptorTimeUpdate( filePath, created ) +{ + let self = this; + let time = _.time.now(); + + _.assert( arguments.length === 2 ); + + if( !self.usingExtraStat ) + return; + + let o2 = + { + filePath, + ctime : time, + mtime : time + } + + if( created ) + { + o2.atime = time; + o2.birthtime = time; + o2.updatingDir = 1; + } + + self._timeWriteAct( o2 ); +} + +// // +// +// function _DescriptorScriptMake( filePath, data ) +// { +// +// if( _.strIs( data ) ) +// try +// { +// data = _.routineMake({ code : data, prependingReturn : 0 }); +// } +// catch( err ) +// { +// debugger; +// throw _.err( 'Cant make routine for file :\n' + filePath + '\n', err ); +// } +// +// _.assert( _.routineIs( data ) ); +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// +// let d = Object.create( null ); +// d.filePath = filePath; +// d.code = data; +// // d.ino = ++Self.InoCounter; +// return [ d ]; +// } + +// + +function _DescriptorSoftLinkMake( filePath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + let d = Object.create( null ); + d.softLink = filePath; + // d.ino = ++Self.InoCounter; + return [ d ]; +} + +// + +function _DescriptorHardLinkMake( filePath, data ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.arrayIs( filePath ) ); + + if( this._DescriptorIsHardLink( data ) ) + { + _.arrayAppendArrayOnce( data[ 0 ].hardLinks, filePath ); + return data; + } + + let d = Object.create( null ); + d.hardLinks = filePath; + d.data = data; + // d.ino = ++Self.InoCounter; + + return [ d ]; +} + +// -- +// encoders +// -- + +let readEncoders = Object.create( null ); +let writeEncoders = Object.create( null ); + +fileReadAct.encoders = readEncoders; +fileWriteAct.encoders = writeEncoders; + +// + +readEncoders[ 'utf8' ] = +{ + + onBegin : function( e ) + { + _.assert( e.operation.encoding === 'utf8' ); + }, + + onEnd : function( e ) + { + if( !_.strIs( e.data ) ) + e.data = _.bufferToStr( e.data ); + _.assert( _.strIs( e.data ) );; + }, + +} + +// + +readEncoders[ 'ascii' ] = +{ + + onBegin : function( e ) + { + _.assert( e.operation.encoding === 'ascii' ); + }, + + onEnd : function( e ) + { + if( !_.strIs( e.data ) ) + e.data = _.bufferToStr( e.data ); + _.assert( _.strIs( e.data ) );; + }, + +} + +// + +readEncoders[ 'latin1' ] = +{ + + onBegin : function( e ) + { + _.assert( e.operation.encoding === 'latin1' ); + }, + + onEnd : function( e ) + { + if( !_.strIs( e.data ) ) + e.data = _.bufferToStr( e.data ); + _.assert( _.strIs( e.data ) );; + }, + +} + +// + +readEncoders[ 'buffer.raw' ] = +{ + + onBegin : function( e ) + { + _.assert( e.operation.encoding === 'buffer.raw' ); + }, + + onEnd : function( e ) + { + + e.data = _.bufferRawFrom( e.data ); + + _.assert( !_.bufferNodeIs( e.data ) ); + _.assert( _.bufferRawIs( e.data ) ); + + }, + +} + +// + +readEncoders[ 'buffer.bytes' ] = +{ + + onBegin : function( e ) + { + _.assert( e.operation.encoding === 'buffer.bytes' ); + }, + + onEnd : function( e ) + { + e.data = _.bufferBytesFrom( e.data ); + }, + +} + +// + +readEncoders[ 'meta.original' ] = +{ + + onBegin : function( e ) + { + _.assert( e.operation.encoding === 'meta.original' ); + }, + + onEnd : function( e ) + { + _.assert( _DescriptorIsTerminal( e.data ) ); + }, + +} + +// + +if( Config.interpreter === 'njs' ) +readEncoders[ 'buffer.node' ] = +{ + + onBegin : function( e ) + { + _.assert( e.operation.encoding === 'buffer.node' ); + }, + + onEnd : function( e ) + { + e.data = _.bufferNodeFrom( e.data ); + // let result = BufferNode.from( e.data ); + // _.assert( _.strIs( e.data ) ); + _.assert( _.bufferNodeIs( e.data ) ); + _.assert( !_.bufferRawIs( e.data ) ); + // return result; + }, + +} + +// + +writeEncoders[ 'meta.original' ] = +{ + onBegin : function( e ) + { + _.assert( e.operation.encoding === 'meta.original' ); + + if( e.read === undefined || e.operation.writeMode === 'rewrite' ) + return; + + if( _.strIs( e.read ) ) + { + if( !_.strIs( e.data ) ) + e.data = _.bufferToStr( e.data ); + } + else + { + + if( _.bufferBytesIs( e.read ) ) + e.data = _.bufferBytesFrom( e.data ) + else if( _.bufferRawIs( e.read ) ) + e.data = _.bufferRawFrom( e.data ) + else + { + _.assert( 0, 'not implemented for:', _.entity.strType( e.read ) ); + // _.bufferCoerceFrom({ src : data, bufferConstructor : read.constructor }); + } + } + } +} + +// -- +// relations +// -- + +/** + * @typedef {Object} Fields + * @property {Boolean} usingExtraStat + * @property {Array} protocols + * @property {Boolean} safe + * @property {Object} filesTree + * @namespace wTools.FileProvider + @module Tools/mid/Files + */ + +let Composes = +{ + usingExtraStat : null, /* add test suite for this provider and usingExtraStat : 1 */ + protocols : _.define.own( [] ), + _currentPath : '/', + safe : 0, +} + +let Aggregates = +{ + filesTree : null, +} + +let Associates = +{ +} + +let Restricts = +{ + extraStats : _.define.own( {} ), + lockMap : null +} + +let Accessors = +{ + filesTree : { set : filesTreeSet }, +} + +let Statics = +{ + + _DescriptorIs, + _DescriptorIsDir, + _DescriptorIsTerminal, + _DescriptorIsLink, + _DescriptorIsSoftLink, + _DescriptorIsHardLink, + _DescriptorIsTextLink, + + // _DescriptorScriptMake, /* zzz : deprecate */ + _DescriptorSoftLinkMake, + _DescriptorHardLinkMake, + + Path : _.uri.CloneExtending({ fileProvider : Self }), + InoCounter : 0, + + SupportsIno : 1, + +} + +let filesTreeSymbol = Symbol.for( 'filesTree' ); + +// -- +// declare +// -- + +let Extension = +{ + + init, + + // path + + pathNativizeAct, + pathCurrentAct, + pathResolveSoftLinkAct, + pathResolveTextLinkAct, + + // read + + fileReadAct, + dirReadAct, + streamReadAct : null, + statReadAct, + fileExistsAct, + + // write + + fileWriteAct, + timeWriteAct, + _timeWriteAct, + fileDeleteAct, + dirMakeAct, + streamWriteAct : null, + + // locking + + fileLockAct, + fileUnlockAct, + fileIsLockedAct, + + // linkingAction + + fileRenameAct, + fileCopyAct, + softLinkAct, + hardLinkAct, + + // link + + hardLinkBreakAct, + areHardLinkedAct, + + // etc + + isInoAct, + + filesTreeSet, + statsAdopt, + // linksRebase, + + // + + _pathResolveIntermediateDirs, + + // descriptor read + + _descriptorRead, + _descriptorReadResolved, + + _descriptorResolve, + // _descriptorResolvePath, + + // _descriptorResolveHardLinkPath, + _descriptorResolveHardLink, + _descriptorResolveSoftLinkPath, + _descriptorResolveSoftLink, + + _DescriptorIs, + _DescriptorIsDir, + _DescriptorIsTerminal, + _DescriptorIsLink, + _DescriptorIsSoftLink, + _DescriptorIsHardLink, + _DescriptorIsScript, + + // descriptor write + + _descriptorWrite, + + _descriptorTimeUpdate, + + // _DescriptorScriptMake, + _DescriptorSoftLinkMake, + _DescriptorHardLinkMake, + + // + + Composes, + Aggregates, + Associates, + Restricts, + Accessors, + Statics, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Extension, +}); + +// -- +// export +// -- + +_.FileProvider[ Self.shortName ] = Self; +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l7_provider/Extract.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l7_provider' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Extract_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Extract_s */ })(); + +/* */ /* begin of file HardDrive_ss */ ( function HardDrive_ss() { function HardDrive_ss_naked() { ( function _HardDrive_ss_() +{ + +'use strict'; + +let File, StandardFile, Os, LockFile; + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + + File = require( 'fs' ); + StandardFile = require( 'fs' ); /* xxx : remove */ + Os = require( 'os' ); + LockFile = require( 'proper-lockfile' ) + +} + +// + +/** + @classdesc Class to perform file operations on local drive. + @class wFileProviderHardDrive + @namespace wTools.FileProvider + @module Tools/mid/Files +*/ + +const _global = _global_; +const _ = _global_.wTools; +const FileRecord = _.files.FileRecord; +const Parent = _.FileProvider.Partial; +const Self = wFileProviderHardDrive; +function wFileProviderHardDrive( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'HardDrive'; + +// -- +// inter +// -- + +function init( o ) +{ + let self = this; + Parent.prototype.init.call( self, o ); +} + +// -- +// path +// -- + +let pathNativizeAct = process.platform === 'win32' ? ( src ) => _.path._nativizeWindows( src ) : ( src ) => _.path._nativizePosix( src ); + +_.assert( _.routineIs( pathNativizeAct ) ); + +// + +function pathCurrentAct() +{ + let self = this; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( arguments.length === 1 && arguments[ 0 ] ) + { + let path = self.path.nativize( arguments[ 0 ] ); + process.chdir( path ); + } + + let result = process.cwd(); + + return result; +} + +// + +function _pathHasDriveLetter( filePath ) +{ + _.assert( _.strIs( filePath ), 'Expects nativized path.' ); + + if( process.platform === 'win32' ) + return /^[a-zA-Z]:\\/.test( filePath ); + return true; +} + +// + +function _isTextLink( filePath ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( !self.usingTextLink ) + return false; + + // let result = self._pathResolveTextLink({ filePath : filePath, allowingMissed : true }); + + let stat = self.statReadAct + ({ + filePath, + throwing : 0, + sync : 1, + resolvingSoftLink : 0, + }); + + if( stat && stat.isTerminal() ) + { + let read = self.fileReadAct + ({ + filePath, + sync : 1, + encoding : 'utf8', + advanced : null, + resolvingSoftLink : 0 + }) + let regexp = /^link ([^\n]+)\n?$/; + return regexp.test( read ); + } + + // return !!result.resolved; + return false; +} + +var having = _isTextLink.having = Object.create( null ); + +having.writing = 0; +having.reading = 1; +having.driving = 0; + +var operates = _isTextLink.operates = Object.create( null ); + +operates.filePath = { pathToRead : 1 } + +// + +let buffer; +// function pathResolveTextLinkAct( filePath, visited, hasLink, allowingMissed ) +// function pathResolveTextLinkAct( o ) +// { +// let self = this; + +// _.routine.assertOptions( pathResolveTextLinkAct, arguments ); +// _.assert( arguments.length === 1 ); +// _.assert( _.arrayIs( o.visited ) ); + +// if( !buffer ) +// buffer = BufferNode.alloc( 512 ); + +// if( o.visited.indexOf( o.filePath ) !== -1 ) +// throw _.err( 'Cyclic text link :', o.filePath ); +// o.visited.push( o.filePath ); + +// o.filePath = self.path.normalize( o.filePath ); +// let exists = _.fileProvider.fileExists({ filePath : o.filePath /*, resolvingTextLink : 0*/ }); + +// let prefix, parts; +// if( o.filePath[ 0 ] === '/' ) +// { +// prefix = '/'; +// parts = o.filePath.substr( 1 ).split( '/' ); +// } +// else +// { +// prefix = ''; +// parts = o.filePath.split( '/' ); +// } + +// for( var p = exists ? p = parts.length-1 : 0 ; p < parts.length ; p++ ) +// { + +// let cpath = _.fileProvider.path.nativize( prefix + parts.slice( 0, p+1 ).join( '/' ) ); + +// let stat = _.fileProvider.statResolvedRead({ filePath : cpath, resolvingTextLink : 0, resolvingSoftLink : 0 }); +// if( !stat ) +// { +// if( o.allowingMissed ) +// return o.filePath; +// else +// return false; +// } + +// if( stat.isTerminal() ) +// { + +// let regexp = /^link ([^\n]+)\n?$/; +// let size = Number( stat.size ); +// let readSize = _.bigIntIs( size ) ? BigInt( 256 ) : 256; +// let f = File.openSync( cpath, 'r' ); +// let m; +// do +// { + +// readSize *= _.bigIntIs( size ) ? BigInt( 2 ) : 2; +// readSize = readSize < size ? readSize : size; +// if( buffer.length < readSize ) +// buffer = BufferNode.alloc( readSize ); +// File.readSync( f, buffer, 0, readSize, 0 ); +// let read = buffer.toString( 'utf8', 0, readSize ); +// m = read.match( regexp ); + +// } +// while( m && readSize < size ); +// File.closeSync( f ); + +// if( m ) +// o.hasLink = true; + +// if( !m ) +// if( p !== parts.length-1 ) +// return false; +// else +// return o.hasLink ? o.filePath : false; + +// /* */ + +// let o2 = _.props.extend( null, o ); +// o2.filePath = self.path.join( m[ 1 ], parts.slice( p+1 ).join( '/' ) ); + +// if( o2.filePath[ 0 ] === '.' ) +// o2.filePath = self.path.reroot( cpath , '..' , o2.filePath ); + +// let result = self.pathResolveTextLinkAct( o2 ); +// if( o2.hasLink ) +// { +// if( !result ) +// { +// throw _.err +// ( +// 'Cant resolve : ' + o.visited[ 0 ] + +// '\nnot found : ' + ( m ? m[ 1 ] : o.filePath ) + +// '\nlooked at :\n' + ( o.visited.join( '\n' ) ) +// ); +// } +// else +// return result; +// } +// else +// { +// throw _.err( 'not expected' ); +// return result; +// } +// } + +// } + +// return o.hasLink ? o.filePath : false; +// } + +// pathResolveTextLinkAct.defaults = +// { +// filePath : null, +// visited : null, +// hasLink : null, +// allowingMissed : true, +// } + +function pathResolveTextLinkAct( o ) +{ + let self = this; + + _.routine.assertOptions( pathResolveTextLinkAct, arguments ); + _.assert( arguments.length === 1 ); + + let result; + + if( !buffer ) + buffer = BufferNode.alloc( 512 ); + + if( o.resolvingIntermediateDirectories ) + return resolveIntermediateDirectories(); + + let stat = self.statReadAct + ({ + filePath : o.filePath, + throwing : 0, + sync : 1, + resolvingSoftLink : 0, + }); + + if( !stat ) + return false; + + if( !stat.isTerminal() ) + return false; + + let filePath = self.path.nativize( o.filePath ); + let regexp = /^link ([^\n]+)\n?$/; + let size = Number( stat.size ); + let readSize = _.bigIntIs( size ) ? BigInt( 256 ) : 256; + let f = File.openSync( filePath, 'r' ); + readSize *= _.bigIntIs( size ) ? BigInt( 2 ) : 2; + readSize = readSize < size ? readSize : size; + if( buffer.length < readSize ) + buffer = BufferNode.alloc( readSize ); + File.readSync( f, buffer, 0, readSize, 0 ); + File.closeSync( f ); + let read = buffer.toString( 'utf8', 0, readSize ); + let m = read.match( regexp ); + + if( !m ) + return false; + + result = m[ 1 ]; + + if( o.resolvingMultiple ) + return multipleResolve(); + + return result; + + /**/ + + function resolveIntermediateDirectories() + { + let splits = self.path.split( o.filePath ); + let o2 = _.props.extend( null, o ); + + o2.resolvingIntermediateDirectories = 0; + o2.filePath = '/'; + + for( let i = 1 ; i < splits.length ; i++ ) + { + o2.filePath = self.path.join( o2.filePath, splits[ i ] ); + + if( self.isTextLink( o2.filePath ) ) + { + result = self.pathResolveTextLinkAct( o2 ) + o2.filePath = self.path.join( o2.filePath, result ); + } + } + return o2.filePath; + } + + /**/ + + function multipleResolve() + { + result = self.path.join( o.filePath, self.path.normalize( result ) ); + if( !self.isTextLink( result ) ) + return result; + let o2 = _.props.extend( null, o ); + o2.filePath = result; + return self.pathResolveTextLinkAct( o2 ); + } +} + +_.routineExtend( pathResolveTextLinkAct, Parent.prototype.pathResolveTextLinkAct ) + + +// + +function pathResolveSoftLinkAct( o ) +{ + let self = this; + let path = self.system ? self.system.path : self.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( path.isAbsolute( o.filePath ) ); + + let result; + + try + { + if( o.resolvingIntermediateDirectories ) + return resolveIntermediateDirectories(); + + if( !self.isSoftLink( o.filePath ) ) + return o.filePath; + + /* qqq : optimize for resolvingMultiple:1 case */ + + result = File.readlinkSync( self.path.nativize( o.filePath ) ); + + /* qqq : why? add experiment please? */ + /* aaa : makes path relative to link instead of directory where link is located */ + if( !path.isAbsolute( path.normalize( result ) ) ) + { + if( _.strBegins( result, '.\\' ) ) + result = _.strIsolateLeftOrNone( result, '.\\' )[ 2 ]; + result = '..\\' + result; + } + + if( o.resolvingMultiple ) + return multipleResolve(); + + return result; + } + catch( err ) + { + throw _.err( 'Error resolving softLink', o.filePath, '\n', err ); + } + + /**/ + + function resolveIntermediateDirectories() + { + if( o.resolvingMultiple ) + return File.realpathSync( self.path.nativize( o.filePath ) ); + + let splits = path.split( o.filePath ); + let o2 = _.props.extend( null, o ); + + o2.resolvingIntermediateDirectories = 0; + o2.filePath = '/'; + + for( let i = 1 ; i < splits.length ; i++ ) + { + o2.filePath = path.join( o2.filePath, splits[ i ] ); + + if( self.isSoftLink( o2.filePath ) ) + { + result = self.pathResolveSoftLinkAct( o2 ) + o2.filePath = path.join( o2.filePath, result ); + } + } + return o2.filePath; + } + + /**/ + + function multipleResolve() + { + result = path.join( o.filePath, path.normalize( result ) ); + if( !self.isSoftLink( result ) ) + return result; + let o2 = _.props.extend( null, o ); + o2.filePath = result; + return self.pathResolveSoftLinkAct( o2 ); + } + +} + +_.routineExtend( pathResolveSoftLinkAct, Parent.prototype.pathResolveSoftLinkAct ); + +// + +function pathDirTempAct() +{ + let self = this; + let path = self.path; + return path.normalize( Os.tmpdir() ); +} + +// + +/** + * Returns `home` directory. On depend from OS it's will be value of 'HOME' for posix systems or 'USERPROFILE' + * for windows environment variables. + * @returns {string} + * @function pathDirUserHomeAct + * @class wFileProviderHardDrive + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function pathDirUserHomeAct() +{ + _.assert( arguments.length === 0, 'Expects single argument' ); + let result = process.env[ ( process.platform === 'win32' ) ? 'USERPROFILE' : 'HOME' ] || __dirname; + _.assert( _.strIs( result ) ); + result = _.path.normalize( result ); + return result; +} + +// + +function pathAllowedAct( filePath ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + _.assert( self.path.isNormalized( filePath ), 'Expects normalized path.' ); + _.assert( self.path.isAbsolute( filePath ), 'Expects absolute path.' ); + + filePath = self.path.unescape( filePath ); + + if( process.platform === 'win32' ) + return !_.strHasAny( filePath, [ '<', '>', ':', '"', '\\', '|', '?', '*' ] ); + + if( process.platform === 'darwin' ) + return !_.strHasAny( filePath, [ ':' ] ); + + return true; +} + + +// -- +// read +// -- + +function fileReadAct( o ) +{ + let self = this; + let con; + let stack = null; + let result = null; + + _.map.assertHasAll( o, fileReadAct.defaults ); + _.assert( self.path.isNormalized( o.filePath ) ); + + let filePath = self.path.nativize( o.filePath ); + + o.fileProvider = self; + o.encoder = fileReadAct.encoders[ o.encoding ]; + // _.assert( o.encoding === null || o.encoding === undefined || _.object.is( o.encoder ), `encoder::${o.encoding} is not registered` ); + if( o.encoder && o.encoder.onSelect ) + o.encoder.onSelect.call( self, o ); + + /* exec */ + + handleBegin(); + + if( !o.resolvingSoftLink && self.isSoftLink( o.filePath ) ) + { + let err = _.err( 'fileReadAct: Reading from soft link is not allowed when "resolvingSoftLink" is disabled' ); + return handleError( err ); + } + + if( o.sync ) + { + try + { + result = File.readFileSync( filePath, { encoding : self._encodingFor( o.encoding ) } ); + } + catch( err ) + { + return handleError( err ); + } + + return handleEnd( result ); + } + else + { + con = new _.Consequence(); + + File.readFile( filePath, { encoding : self._encodingFor( o.encoding ) }, function( err, data ) + { + if( err ) + return handleError( err ); + else + return handleEnd( data ); + }); + + return con; + } + + /* begin */ + + function handleBegin() + { + + if( o.encoder && o.encoder.onBegin ) + o.encoder.onBegin.call( self, { operation : o, encoder : o.encoder }) + + } + + /* end */ + + function handleEnd( data ) + { + + if( o.encoder && o.encoder.onEnd ) + data = o.encoder.onEnd.call( self, { data, operation : o, encoder : o.encoder }) + + if( o.sync ) + return data; + else + return con.take( data ); + + } + + /* error */ + + function handleError( err ) + { + + err = _._err + ({ + args : [ '\nfileReadAct( ', o.filePath, ' )\n', err ], + usingSourceCode : 0, + level : 0, + // stack : stack, + }); + + if( o.encoder && o.encoder.onError ) + try + { + err = o.encoder.onError.call( self, { error : err, operation : o, encoder : o.encoder }) + } + catch( err2 ) + { + console.error( err2.message ); + console.error( err2.stack ); + console.error( err.message ); + console.error( err.stack ); + } + + if( o.sync ) + throw err; + else + return con.error( err ); + + } + +} + +_.routineExtend( fileReadAct, Parent.prototype.fileReadAct ); + +// + +function streamReadAct( o ) +{ + let self = this; + let result; + + _.routine.assertOptions( streamReadAct, arguments ); + + o.fileProvider = self; + o.encoder = fileReadAct.encoders[ o.encoding ]; + // _.assert( o.encoding === null || o.encoding === undefined || _.object.is( o.encoder ), `encoder::${o.encoding} is not registered` ); + if( o.encoder && o.encoder.onSelect ) + o.encoder.onSelect.call( self, o ); + + let filePath = self.path.nativize( o.filePath ); + + handleBegin(); + + try + { + result = File.createReadStream( filePath, { encoding : self._encodingFor( o.encoding ) } ); + } + catch( err ) + { + throw _.err( err ); + } + + result.on( 'error', ( err ) => handleError( err ) ); + result.on( 'end', () => handleEnd() ); + + return result; + + /* begin */ + + function handleBegin() + { + + if( o.encoder && o.encoder.onBegin ) + o.encoder.onBegin.call( self, { operation : o, encoder : o.encoder }); + + } + + /* end */ + + function handleEnd() + { + + if( o.encoder && o.encoder.onEnd ) + o.encoder.onEnd.call( self, { stream : result, operation : o, encoder : o.encoder }) + + } + + /* error */ + + function handleError( err ) + { + + err = _._err + ({ + args : [ '\nfileReadAct( ', o.filePath, ' )\n', err ], + usingSourceCode : 0, + level : 0, + // stack : stack, + }); + + if( o.encoder && o.encoder.onError ) + try + { + err = o.encoder.onError.call( self, { error : err, operation : o, encoder : o.encoder }); + } + catch( err2 ) + { + console.error( err2.message ); + console.error( err2.stack ); + console.error( err.message ); + console.error( err.stack ); + } + + } + +} + +_.routineExtend( streamReadAct, Parent.prototype.streamReadAct ); + +// + +function dirReadAct( o ) +{ + let self = this; + let result = null; + + _.routine.assertOptions( dirReadAct, arguments ); + + let nativizedFilePath = self.path.nativize( o.filePath ); + + /* read dir */ + + if( o.sync ) + { + try + { + let stat = self.statReadAct + ({ + filePath : o.filePath, + throwing : 1, + sync : 1, + resolvingSoftLink : 1, + }); + if( stat.isDir() ) + { + result = File.readdirSync( nativizedFilePath ); + return result + } + else + { + result = self.path.name({ path : o.filePath, full : 1 }); + } + } + catch( err ) + { + throw _.err( err ); + result = null; + } + + return result; + } + else + { + let con = new _.Consequence(); + + self.statReadAct + ({ + filePath : o.filePath, + sync : 0, + resolvingSoftLink : 1, + throwing : 1, + }) + .give( function( err, stat ) + { + if( err ) + { + con.error( _.err( err ) ); + } + else if( stat.isDir() ) + { + File.readdir( nativizedFilePath, function( err, files ) + { + if( err ) + { + con.error( _.err( err ) ); + } + else + { + con.take( files || null ); + } + }); + } + else + { + result = self.path.name({ path : o.filePath, full : 1 }); + con.take( result ); + } + }); + + return con; + } + +} + +_.routineExtend( dirReadAct, Parent.prototype.dirReadAct ); + +// -- +// read stat +// -- + +/* +xxx : return maybe undefined if error, but exists? +*/ + +function statReadAct( o ) +{ + let self = this; + let result = null; + + _.assert( self.path.isAbsolute( o.filePath ), 'Expects absolute {-o.FilePath-}, but got', o.filePath ); + _.assert( self.path.isNormalized( o.filePath ), 'Expects normalized {-o.FilePath-}, but got', o.filePath ); + _.routine.assertOptions( statReadAct, arguments ); + + let nativizedFilePath = self.path.nativize( o.filePath ); + let args = [ nativizedFilePath ]; + + if( self.UsingBigIntForStat ) + args.push( { bigint : true } ); + + /* */ + + if( o.sync ) + { + + try + { + if( o.resolvingSoftLink ) + result = StandardFile.statSync.apply( StandardFile, args ); + else + result = StandardFile.lstatSync.apply( StandardFile, args ); + } + catch( err ) + { + if( o.throwing ) + throw _.err( 'Error getting stat of', o.filePath, '\n', err ); + } + + if( result ) + handleEnd( result ); + + return result; + } + + /* */ + + let con = new _.Consequence(); + + args.push( handleAsyncEnd ); + + if( o.resolvingSoftLink ) + StandardFile.stat.apply( StandardFile, args ); + else + StandardFile.lstat.apply( StandardFile, args ); + + return con; + + /* */ + + function handleAsyncEnd( err, stat ) + { + if( err ) + { + if( o.throwing ) + con.error( _.err( err ) ); + else + con.take( null ); + } + else + { + handleEnd( stat ); + con.take( stat ); + } + } + + /* */ + + function isTerminal() + { + return this.isFile(); + } + + /* */ + + function isDir() + { + return this.isDirectory(); + } + + /* */ + + let _isTextLink; + function isTextLink() + { + if( this._isTextLink !== undefined ) + return this._isTextLink; + this._isTextLink = self._isTextLink( o.filePath ); + return this._isTextLink; + } + + /* */ + + function isSoftLink() + { + return this.isSymbolicLink(); + } + + /* */ + + function isHardLink() + { + if( !this.isFile() ) + return false; + return this.nlink >= 2; + } + + /* */ + + function handleEnd( stat ) + { + let extend = + { + filePath : o.filePath, + isTerminal, + isDir, + isTextLink, + isSoftLink, + isHardLink, + isLink : _.files.FileStat.prototype.isLink, + } + _.props.extend( stat, extend ); + return stat; + } + +} + +_.assert( _.routineIs( _.files.FileStat.prototype.isLink ) ); +_.routineExtend( statReadAct, Parent.prototype.statReadAct ); + +// + +function fileExistsAct( o ) +{ + let self = this; + let nativizedFilePath = self.path.nativize( o.filePath ); + try + { + File.accessSync( nativizedFilePath, File.constants.F_OK ); + } + catch( err ) + { + if( err.code === 'ENOENT' ) + { /* + Used to check if symlink is present on Unix when referenced file doesn't exist. + qqq : Check if same behavior can be obtained by using combination of File.constants in accessSync + aaa : possible solution is to use faccessat, it accepts flag that disables resolving of the soft links. + But we need to implement own c++ addon for faccessat. https://linux.die.net/man/2/faccessat. + */ + if( process.platform !== 'win32' ) + return !!self.statReadAct({ filePath : o.filePath, sync : 1, throwing : 0, resolvingSoftLink : 0 }); + return false; + } + if( err.code === 'ENOTDIR' ) + return false; + } + _.assert( arguments.length === 1 ); + return true; +} + +_.routineExtend( fileExistsAct, Parent.prototype.fileExistsAct ); + +// -- +// write +// -- + +/** + * Writes data to a file. `data` can be a string or a buffer. Creating the file if it does not exist yet. + * Returns wConsequence instance. + * By default method writes data synchronously, with replacing file if exists, and if parent dir hierarchy doesn't + exist, it's created. Method can accept two parameters : string `filePath` and string\buffer `data`, or single + argument : options map, with required 'filePath' and 'data' parameters. + * @example + * + let data = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + options = + { + filePath : 'tmp/sample.txt', + data : data, + sync : false, + }; + let con = wTools.fileWrite( options ); + con.give( function() + { + console.log('write finished'); + }); + * @param {Object} options write options + * @param {string} options.filePath path to file is written. + * @param {string|BufferNode} [options.data=''] data to write + * @param {boolean} [options.append=false] if this options sets to true, method appends passed data to existing data + in a file + * @param {boolean} [options.sync=true] if this parameter sets to false, method writes file asynchronously. + * @param {boolean} [options.force=true] if it's set to false, method throws exception if parents dir in `filePath` + path is not exists + * @param {boolean} [options.silentError=false] if it's set to true, method will catch error, that occurs during + file writes. + * @param {boolean} [options.verbosity=false] if sets to true, method logs write process. + * @param {boolean} [options.clean=false] if sets to true, method removes file if exists before writing + * @returns {wConsequence} + * @throws {Error} If arguments are missed + * @throws {Error} If passed more then 2 arguments. + * @throws {Error} If `filePath` argument or options.PathFile is not string. + * @throws {Error} If `data` argument or options.data is not string or BufferNode, + * @throws {Error} If options has unexpected property. + * @function fileWriteAct + * @class wFileProviderHardDrive + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function fileWriteAct( o ) +{ + let self = this; + + _.routine.assertOptions( fileWriteAct, arguments ); + _.assert( self.path.isNormalized( o.filePath ) ); + _.assert( self.WriteMode.indexOf( o.writeMode ) !== -1 ); + + o.fileProvider = self; + o.encoder = fileWriteAct.encoders[ o.encoding ]; + // _.assert( o.encoding === null || o.encoding === undefined || _.object.is( o.encoder ), `encoder::${o.encoding} is not registered` ); + if( o.encoder && o.encoder.onSelect ) + o.encoder.onSelect.call( self, o ); + + if( o.encoder && o.encoder.onBegin ) + _.sure( o.encoder.onBegin.call( self, { operation : o, encoder : o.encoder, data : o.data } ) === undefined ); + + /* data conversion */ + + if( _.bufferTypedIs( o.data ) && !_.bufferBytesIs( o.data ) || _.bufferRawIs( o.data ) ) + o.data = _.bufferNodeFrom( o.data ); + + _.assert + ( + _.strIs( o.data ) || _.bufferNodeIs( o.data ) || _.bufferBytesIs( o.data ), + 'Expects string or node buffer, but got', _.entity.strType( o.data ) + ); + + let nativizedFilePath = self.path.nativize( o.filePath ); + + _.assert + ( + self._pathHasDriveLetter( nativizedFilePath ), + `Expects path that begins with drive letter, but got:"${o.filePath}"` + ); + + /* write */ + + if( o.sync ) + { + + if( o.writeMode === 'rewrite' ) + { + File.writeFileSync( nativizedFilePath, o.data, { encoding : self._encodingFor( o.encoding ) } ); + } + else if( o.writeMode === 'append' ) + { + File.appendFileSync( nativizedFilePath, o.data, { encoding : self._encodingFor( o.encoding ) } ); + } + else if( o.writeMode === 'prepend' ) + { + if( self.fileExistsAct({ filePath : o.filePath, sync : 1 }) ) + { + let data = File.readFileSync( nativizedFilePath, { encoding : undefined } ); + o.data = _.bufferJoin( _.bufferNodeFrom( o.data ), data ); + } + File.writeFileSync( nativizedFilePath, o.data, { encoding : self._encodingFor( o.encoding ) } ); + } + else + { + throw _.err( 'Not implemented write mode', o.writeMode ); + } + return; + + } + + /* */ + + let con = _.Consequence(); + + if( o.writeMode === 'rewrite' ) + { + File.writeFile( nativizedFilePath, o.data, { encoding : self._encodingFor( o.encoding ) }, handleEnd ); + } + else if( o.writeMode === 'append' ) + { + File.appendFile( nativizedFilePath, o.data, { encoding : self._encodingFor( o.encoding ) }, handleEnd ); + } + else if( o.writeMode === 'prepend' ) + { + if( self.fileExistsAct({ filePath : o.filePath, sync : 1 }) ) + File.readFile( nativizedFilePath, { encoding : undefined }, function( err, data ) + { + if( err ) + return handleEnd( err ); + o.data = _.bufferJoin( _.bufferNodeFrom( o.data ), data ); + File.writeFile( nativizedFilePath, o.data, { encoding : self._encodingFor( o.encoding ) }, handleEnd ); + }); + else + { + File.writeFile( nativizedFilePath, o.data, { encoding : self._encodingFor( o.encoding ) }, handleEnd ); + } + } + else + { + handleEnd( _.err( 'Not implemented write mode', o.writeMode ) ); + } + + return con; + + /* */ + + function handleEnd( err ) + { + if( err ) + return con.error( _.err( err ) ); + return con.take( o ); + } + +} + +_.routineExtend( fileWriteAct, Parent.prototype.fileWriteAct ); + +// + +function streamWriteAct( o ) +{ + let self = this; + + _.routine.assertOptions( streamWriteAct, arguments ); + + let filePath = self.path.nativize( o.filePath ); + + _.assert( self._pathHasDriveLetter( filePath ), `Expects path that begins with drive letter, but got:"${o.filePath}"` ); + + try + { + return File.createWriteStream( filePath ); + } + catch( err ) + { + throw _.err( err ); + } +} + +_.routineExtend( streamWriteAct, Parent.prototype.streamWriteAct ); + +// + +function timeWriteAct( o ) +{ + let self = this; + + _.routine.assertOptions( timeWriteAct, arguments ); + + // File.utimesSync( o.filePath, o.atime, o.mtime ); + + /* + futimesSync atime/mtime precision: + win32 up to seconds, throws error milliseconds + unix up to nanoseconds, but stat.mtime works properly up to milliseconds otherwise returns "Invalid Date" + */ + + let nativizedFilePath = self.path.nativize( o.filePath ); + + _.assert + ( + self._pathHasDriveLetter( nativizedFilePath ), + `Expects path that begins with drive letter, but got:"${o.filePath}"` + ); + + let flags = process.platform === 'win32' ? 'r+' : 'r'; + let descriptor = File.openSync( nativizedFilePath, flags ); + try + { + File.futimesSync( descriptor, o.atime, o.mtime ); + File.closeSync( descriptor ); + } + catch( err ) + { + File.closeSync( descriptor ); + throw _.err( err ); + } +} + +_.routineExtend( timeWriteAct, Parent.prototype.timeWriteAct ); + +// + +function rightsWriteAct( o ) +{ + let self = this; + let nativizedFilePath = self.path.nativize( o.filePath ); + + /* + https://nodejs.org/api/fs.html#fs_file_modes + Node caveats: on Windows only the write permission can be changed, and the distinction among the permissions of group, owner or others is not implemented. + */ + + _.routine.assertOptions( rightsWriteAct, o ); + + if( o.addRights !== null || o.delRights !== null ) + { + + if( o.setRights === null ) + o.setRights = self.rightsRead({ filePath : o.filePath, sync : 1 }); + if( o.addRights !== null ) + o.setRights = Number( o.setRights ) | Number( o.addRights ); + if( o.delRights !== null ) + o.setRights = Number( o.setRights ) & Number( ~o.delRights ); + + } + + if( o.setRights !== null ) + { + let d = File.openSync( nativizedFilePath, 'r' ); + File.fchmodSync( d, Number( o.setRights ) ); + File.closeSync( d ); + return true; + } + + return false; +} + +_.routineExtend( rightsWriteAct, Parent.prototype.rightsWriteAct ); + +// + +/** + * Delete file of directory. Accepts path string or options map. Returns wConsequence instance. + * @example + * let StandardFile = require( 'fs' ); + + const fileProvider = _.FileProvider.Default(); + + let path = 'tmp/fileSize/data', + textData = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + delOptions = + { + filePath : path, + sync : 0 + }; + + fileProvider.fileWrite( { filePath : path, data : textData } ); // create test file + + console.log( StandardFile.existsSync( path ) ); // true (file exists) + let con = fileProvider.fileDelete( delOptions ); + + con.give( function(err) + { + console.log( StandardFile.existsSync( path ) ); // false (file does not exist) + } ); + + * @param {string|Object} o - options map. + * @param {string} o.filePath path to file/directory for deleting. + * @param {boolean} [o.force=false] if sets to true, method remove file, or directory, even if directory has + content. Else when directory to remove is not empty, wConsequence returned by method, will rejected with error. + * @param {boolean} [o.sync=true] If set to false, method will remove file/directory asynchronously. + * @returns {wConsequence} + * @throws {Error} If missed argument, or pass more than 1. + * @throws {Error} If filePath is not string. + * @throws {Error} If options map has unexpected property. + * @function fileDeleteAct + * @class wFileProviderHardDrive + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function fileDeleteAct( o ) +{ + let self = this; + + _.routine.assertOptions( fileDeleteAct, arguments ); + _.assert( self.path.isAbsolute( o.filePath ) ); + _.assert( self.path.isNormalized( o.filePath ) ); + + // console.log( 'fileDeleteAct', o.filePath ); + + let filePath = self.path.nativize( o.filePath ); + + _.assert( self._pathHasDriveLetter( filePath ), `Expects path that begins with drive letter, but got:"${o.filePath}"` ); + + if( o.sync ) + { + let stat = self.statReadAct + ({ + filePath : o.filePath, + resolvingSoftLink : 0, + sync : 1, + throwing : 0, + }); + + if( stat && stat.isDir() ) + File.rmdirSync( filePath ); + else if( stat && process.platform === 'win32' ) + { + /* + The problem is that on windows, when you unlink a file that is opened, it doesn't really get deleted. + It is just marked for deletion, but the directory entry is still there until the file is closed + + rename + unlink combination fixes the problem: + + rename moves file to temp directory, unlink marks file fo delete, it is not longer located in the original directory + and will be deleted when original file is closed. + + Limitation : rename fails if temp directory is located on other device + */ + let tempPath = tempPathGet(); + try + { + File.renameSync( filePath, tempPath ); + } + catch( err ) + { + _.errLogOnce( err ); + return File.unlinkSync( filePath ); + } + + // File.unlink( tempPath, ( err ) => /* Dmytro : we should use sync methods in sync branch */ + File.unlinkSync( tempPath, ( err ) => + { + if( err ) + throw err; + }); + + } + else + File.unlinkSync( filePath ); + + return; + } + + /* */ + + let con = self.statReadAct + ({ + filePath : o.filePath, + resolvingSoftLink : 0, + sync : 0, + throwing : 0, + }); + con.give( ( err, stat ) => + { + if( err ) + return con.error( err ); + + if( stat && stat.isDir() ) + File.rmdir( filePath, handleResult ); + else if( process.platform === 'win32' ) + { + let tempPath = tempPathGet(); + File.rename( filePath, tempPath, ( err ) => + { + if( err ) + _.errLogOnce( err ); + else + filePath = tempPath; + + File.unlink( filePath, handleResult ); + }); + } + else + File.unlink( filePath, handleResult ); + }) + + return con; + + /* */ + + function tempPathGet() + { + let tempPath = _.strRemoveEnd( self.path.normalize( o.filePath ), '/' ); /* Dmytro : maybe, normalizing is overhead */ + tempPath = self.path.nativize( o.filePath ); + let fileName = self.path.name({ path : tempPath, full : 1 }); + let tempName = fileName + '-' + _.idWithGuid() + '.tmp'; + return tempPath + tempName; + // let fileName = self.path.name({ path : o.filePath, full : 1 }); + // let tempName = fileName + '-' + _.idWithGuid() + '.tmp'; + // // let tempDirPath = self.path.tempOpen( o.filePath ); /* Dmytro : opening and closing ( missed ) of temp path is overhead for simple renaming, we can modify path to get unique name */ + // // let tempPath = self.path.join( tempDirPath, tempName ); + // let tempPath = _.strRemoveEnd( self.path.normalize( o.filePath ), '/' ); /* Dmytro : maybe, normalizing is overhead */ + // tempPath = self.path.nativize( tempPath+tempName ); + // return tempPath; + } + + /* */ + + function handleResult( err ) + { + if( err ) + con.error( err ); + else + con.take( true ); + } + +} + +_.routineExtend( fileDeleteAct, Parent.prototype.fileDeleteAct ); + +// + +function dirMakeAct( o ) +{ + let self = this; + let nativizedFilePath = self.path.nativize( o.filePath ); + + _.routine.assertOptions( dirMakeAct, arguments ); + _.assert + ( + self._pathHasDriveLetter( nativizedFilePath ), + `Expects path that begins with drive letter, but got:"${o.filePath}"` + ); + + + if( o.sync ) + { + + try + { + File.mkdirSync( nativizedFilePath ); + } + catch( err ) + { + throw _.err( err ); + } + + } + else + { + let con = new _.Consequence(); + + File.mkdir( nativizedFilePath, function( err ) + { + if( err ) + con.error( err ); + else + con.take( true ); + }); + + return con; + } + +} + +_.routineExtend( dirMakeAct, Parent.prototype.dirMakeAct ); + +// + +let lockFileCounterMap = Object.create( null ); + +function fileLockAct( o ) +{ + let self = this; + let nativizedFilePath = self.path.nativize( o.filePath ); + + _.assert( !o.locking, 'not implemented' ); + _.assert( !o.sharing || o.sharing === 'process', 'not implemented' ); + _.assert( self.path.isNormalized( o.filePath ) ); + _.assert( !o.waiting || o.timeOut >= 1000 ); + _.routine.assertOptions( fileLockAct, arguments ); + _.assert + ( + self._pathHasDriveLetter( nativizedFilePath ), + `Expects path that begins with drive letter, but got:"${o.filePath}"` + ); + + let con = _.Consequence.Try( () => + { + if( !self.fileExistsAct({ filePath : o.filePath }) ) + throw _.err( 'File:', o.filePath, 'doesn\'t exist.' ); + + if( lockFileCounterMap[ o.filePath ] ) + if( self.fileExistsAct({ filePath : o.filePath + '.lock' } ) ) + { + if( !o.sharing ) + throw _.err( 'File', nativizedFilePath, 'is already locked by current process' ); + + if( !o.waiting ) + { + return true; + } + else if( o.sync ) + { + throw _.err + ( + 'File', nativizedFilePath, 'is already locked by current process.', + 'With option {-o.waiting-} enabled, lock will be waiting for itself.', + 'Please use existing lock or execute method with {-o.sync-} set to 0.' + ) + } + } + + let lockOptions = Object.create( null ); + + if( o.sync ) + { + LockFile.lockSync( nativizedFilePath, lockOptions ); + return true; + } + else + { + if( o.waiting ) + lockOptions.retries = + { + retries : o.timeOut / 1000, + minTimeout : 1000, + maxRetryTime : o.timeOut + } + return _.Consequence.From( LockFile.lock( nativizedFilePath, lockOptions ) ); + } + }) + + con.then( ( got ) => + { + if( lockFileCounterMap[ o.filePath ] === undefined ) + lockFileCounterMap[ o.filePath ] = 0; + + lockFileCounterMap[ o.filePath ] += 1; + + return true; + }) + + if( o.sync ) + return con.sync(); + + return con; +} + +_.routineExtend( fileLockAct, Parent.prototype.fileLockAct ); + +// + +function fileUnlockAct( o ) +{ + let self = this; + let nativizedFilePath = self.path.nativize( o.filePath ); + + _.assert( self.path.isNormalized( o.filePath ) ); + _.routine.assertOptions( fileUnlockAct, arguments ); + _.assert + ( + self._pathHasDriveLetter( nativizedFilePath ), + `Expects path that begins with drive letter, but got:"${o.filePath}"` + ); + + let con = _.Consequence.Try( () => + { + if( !self.fileExistsAct({ filePath : o.filePath }) ) + throw _.err( 'File:', o.filePath, 'doesn\'t exist.' ); + + if( lockFileCounterMap[ o.filePath ] !== undefined ) + { + _.assert( lockFileCounterMap[ o.filePath ] > 0 ); + + lockFileCounterMap[ o.filePath ] -= 1; + + if( lockFileCounterMap[ o.filePath ] > 0 ) + return true; + } + + if( o.sync ) + { + LockFile.unlockSync( nativizedFilePath ); + return true; + } + else + { + return _.Consequence.From( LockFile.unlock( nativizedFilePath ) ); + } + + }) + + con.then( ( got ) => + { + if( lockFileCounterMap[ o.filePath ] === 0 ) + { + delete lockFileCounterMap[ o.filePath ]; + } + + return true; + }) + + if( o.sync ) + return con.sync(); + + return con; +} + +_.routineExtend( fileUnlockAct, Parent.prototype.fileUnlockAct ); + +// + +function fileIsLockedAct( o ) +{ + let self = this; + let nativizedFilePath = self.path.nativize( o.filePath ); + + _.routine.assertOptions( fileIsLockedAct, arguments ); + _.assert( self.path.isNormalized( o.filePath ) ); + + let con = _.Consequence.Try( () => + { + if( o.sync ) + { + return LockFile.checkSync( nativizedFilePath ); + } + else + { + return _.Consequence.From( LockFile.check( nativizedFilePath ) ); + } + }) + + if( o.sync ) + return con.sync(); + + return con; +} + +_.routineExtend( fileIsLockedAct, Parent.prototype.fileIsLockedAct ); + + +// + +function fileRenameAct( o ) +{ + let self = this; + + _.routine.assertOptions( fileRenameAct, arguments ); + _.assert( self.path.isNormalized( o.srcPath ) ); + _.assert( self.path.isNormalized( o.dstPath ) ); + + let dstPath = self.path.nativize( o.dstPath ); + let srcPath = self.path.nativize( o.srcPath ); + + _.assert( self._pathHasDriveLetter( srcPath ), `Expects src path that begins with drive letter, but got:"${o.srcPath}"` ); + _.assert( self._pathHasDriveLetter( dstPath ), `Expects dst path that begins with drive letter, but got:"${o.dstPath}"` ); + + _.assert( !!dstPath ); + _.assert( !!srcPath ); + + if( o.sync ) + { + File.renameSync( srcPath, dstPath ); + } + else + { + let con = new _.Consequence(); + File.rename( srcPath, dstPath, function( err ) + { + if( err ) + con.error( err ); + else + con.take( true ); + }); + return con; + } + +} + +_.routineExtend( fileRenameAct, Parent.prototype.fileRenameAct ); +_.assert( fileRenameAct.defaults.originalDstPath === undefined ); +_.assert( fileRenameAct.defaults.relativeDstPath !== undefined ); + +// + +function fileCopyAct( o ) +{ + let self = this; + + _.routine.assertOptions( fileCopyAct, arguments ); + _.assert( self.path.isNormalized( o.srcPath ) ); + _.assert( self.path.isNormalized( o.dstPath ) ); + + if( self.isDir( o.srcPath ) ) + { + let err = _.err( o.srcPath, ' is not a terminal file of link!' ); + if( o.sync ) + throw err; + return new _.Consequence().error( err ); + } + + if( self.isSoftLink( o.srcPath ) ) /* qqq2 : should not be here. move to partial aaa: should be here becase Extract has more optiomal implementation of this case */ + { + if( self.fileExistsAct({ filePath : o.dstPath }) ) + self.fileDeleteAct({ filePath : o.dstPath, sync : 1 }) + return self.softLinkAct + ({ + srcPath : o.srcPath, + dstPath : o.dstPath, + + relativeSrcPath : o.relativeSrcPath, + relativeDstPath : o.relativeDstPath, + + sync : o.sync, + type : null + }) + } + + + let dstPath = self.path.nativize( o.dstPath ); + let srcPath = self.path.nativize( o.srcPath ); + + _.assert( self._pathHasDriveLetter( srcPath ), `Expects src path that begins with drive letter, but got:"${o.srcPath}"` ); + _.assert( self._pathHasDriveLetter( dstPath ), `Expects dst path that begins with drive letter, but got:"${o.dstPath}"` ); + + _.assert( !!dstPath ); + _.assert( !!srcPath ); + + /* */ + + if( o.sync ) + { + // File.copySync( o.srcPath, o.dstPath ); + File.copyFileSync( srcPath, dstPath ); + } + else + { + let con = new _.Consequence().take( null ); + let readCon = new _.Consequence(); + let writeCon = new _.Consequence(); + + con.andKeep( [ readCon, writeCon ] ); + + con.ifNoErrorThen( ( got ) => + { + let errs = got.filter( ( result ) => _.errIs( result ) ); + + if( errs.length ) + throw _.err.apply( _, errs ); + + return got; + }) + + let readStream = self.streamReadAct + ({ + filePath : srcPath, + encoding : self.encoding, + onStreamBegin : null + }); + + readStream.on( 'error', ( err ) => + { + readCon.take( _.err( err ) ); + }) + + readStream.on( 'end', () => + { + readCon.take( null ); + }) + + let writeStream = self.streamWriteAct({ filePath : dstPath }); + + writeStream.on( 'error', ( err ) => + { + writeCon.take( _.err( err ) ); + }) + + writeStream.on( 'finish', () => + { + writeCon.take( null ); + }) + + readStream.pipe( writeStream ); + + return con; + } + +} + +_.routineExtend( fileCopyAct, Parent.prototype.fileCopyAct ); + +// + +// function softLinkAct( o ) +// { +// let self = this; +// let srcIsAbsolute = self.path.isAbsolute( o.relativeSrcPath ); +// let srcPath = o.srcPath; +// +// _.routine.assertOptions( softLinkAct, arguments ); +// _.assert( self.path.isAbsolute( o.dstPath ) ); +// _.assert( self.path.isNormalized( o.srcPath ) ); +// _.assert( self.path.isNormalized( o.dstPath ) ); +// _.assert( o.type === null || o.type === 'dir' || o.type === 'file' ); +// +// if( !srcIsAbsolute ) +// { +// srcPath = o.relativeSrcPath; +// if( _.strBegins( srcPath, './' ) ) +// srcPath = _.strIsolateLeftOrNone( srcPath, './' )[ 2 ]; +// if( _.strBegins( srcPath, '..' ) ) +// srcPath = '.' + _.strIsolateLeftOrNone( srcPath, '..' )[ 2 ]; +// } +// +// if( process.platform === 'win32' ) +// { +// +// if( o.type === null ) +// { +// let srcPathResolved = srcPath; +// +// /* not dir */ +// if( !srcIsAbsolute ) +// srcPathResolved = self.path.resolve( self.path.dir( o.dstPath ), srcPath ); +// +// let srcStat = self.statReadAct +// ({ +// filePath : srcPathResolved, +// resolvingSoftLink : 1, +// sync : 1, +// throwing : 0, +// }); +// +// if( srcStat ) +// o.type = srcStat.isDirectory() ? 'dir' : 'file'; +// +// } +// +// } +// +// let dstNativePath = self.path.nativize( o.dstPath ); +// let srcNativePath = self.path.nativize( srcPath ); +// +// _.assert +// ( +// !srcIsAbsolute || self._pathHasDriveLetter( srcNativePath ), +// `Expects src path that begins with drive letter, but got:"${srcPath}"` +// ); +// _.assert +// ( +// self._pathHasDriveLetter( dstNativePath ), +// `Expects dst path that begins with drive letter, but got:"${o.dstPath}"` +// ); +// +// /* */ +// +// if( o.sync ) +// { +// +// if( process.platform === 'win32' ) +// File.symlinkSync( srcNativePath, dstNativePath, o.type ); +// else +// File.symlinkSync( srcNativePath, dstNativePath ); +// +// return; +// } +// +// let con = new _.Consequence(); +// +// if( process.platform === 'win32' ) +// File.symlink( srcNativePath, dstNativePath, o.type, onSymlink ); +// else +// File.symlink( srcNativePath, dstNativePath, onSymlink ); +// +// return con; +// +// /* */ +// +// function onSymlink( err ) +// { +// if( err ) +// con.error( err ); +// else +// con.take( true ); +// } +// +// } + +function softLinkAct_functor() +{ + let con; + const isWindows = process.platform === 'win32' ? 1 : 0; + const nodejsSoftLinkingChanged = _.files.nodeJsIsSameOrNewer([ 15, 0, 0 ]) ? 1 : 0; + + const softLinkSyncRoutines = + [ + softLinkSync, + softLinkSyncWindows, + softLinkSyncWindowsWithTry, + ]; + + const softLinkSyncRoutine = softLinkSyncRoutines[ isWindows + nodejsSoftLinkingChanged ]; + const softLinkAsyncRoutine = isWindows ? softLinkAsyncWindows : softLinkAsync; + + return softLinkAct; + + /* */ + + function softLinkSync( srcNativePath, dstNativePath, type ) + { + File.symlinkSync( srcNativePath, dstNativePath ); + } + + /* */ + + function softLinkSyncWindows( srcNativePath, dstNativePath, type ) + { + File.symlinkSync( srcNativePath, dstNativePath, type ); + } + + /* */ + + function softLinkSyncWindowsWithTry( srcNativePath, dstNativePath, type ) + { + /* + Dmytro : try-catch imitate njs file system API of njs versions earlier than 15. + The behavior of routine is similar to posix-like OS + */ + try + { + File.symlinkSync( srcNativePath, dstNativePath, type ); + } + catch( err ) + { + if( err.code === 'ELOOP' ) + if( type === null ) /* Dmytro : can be changed only not defined type */ + { + File.symlinkSync( srcNativePath, dstNativePath, 'dir' ); + return; + } + + throw _.err( err ); + } + } + + /* */ + + function softLinkAsync( srcNativePath, dstNativePath, type ) + { + con = new _.Consequence(); + File.symlink( srcNativePath, dstNativePath, onSymlink ); + return con; + } + + /* */ + + function softLinkAsyncWindows( srcNativePath, dstNativePath, type ) + { + con = new _.Consequence(); + File.symlink( srcNativePath, dstNativePath, type, onSymlink ); + return con; + } + + /* */ + + function onSymlink( err ) + { + if( err ) + con.error( err ); + else + con.take( true ); + } + + /* */ + + function softLinkAct( o ) + { + let self = this; + let srcIsAbsolute = self.path.isAbsolute( o.relativeSrcPath ); + let srcPath = o.srcPath; + + _.routine.assertOptions( softLinkAct, arguments ); + _.assert( self.path.isAbsolute( o.dstPath ) ); + _.assert( self.path.isNormalized( o.srcPath ) ); + _.assert( self.path.isNormalized( o.dstPath ) ); + _.assert( o.type === null || o.type === 'dir' || o.type === 'file' ); + + if( !srcIsAbsolute ) + { + srcPath = o.relativeSrcPath; + if( _.strBegins( srcPath, './' ) ) + srcPath = _.strIsolateLeftOrNone( srcPath, './' )[ 2 ]; + if( _.strBegins( srcPath, '..' ) ) + srcPath = '.' + _.strIsolateLeftOrNone( srcPath, '..' )[ 2 ]; + } + + if( isWindows ) + { + if( o.type === null ) + { + let srcPathResolved = srcPath; + + /* not dir */ + if( !srcIsAbsolute ) + srcPathResolved = self.path.resolve( self.path.dir( o.dstPath ), srcPath ); + + let srcStat = self.statReadAct + ({ + filePath : srcPathResolved, + resolvingSoftLink : 1, + sync : 1, + throwing : 0, + }); + + if( srcStat ) + o.type = srcStat.isDirectory() ? 'dir' : 'file'; + } + } + + let dstNativePath = self.path.nativize( o.dstPath ); + let srcNativePath = self.path.nativize( srcPath ); + + _.assert + ( + !srcIsAbsolute || self._pathHasDriveLetter( srcNativePath ), + `Expects src path that begins with drive letter, but got:"${srcPath}"` + ); + _.assert + ( + self._pathHasDriveLetter( dstNativePath ), + `Expects dst path that begins with drive letter, but got:"${o.dstPath}"` + ); + + /* */ + + if( o.sync ) + return softLinkSyncRoutine( srcNativePath, dstNativePath, o.type ); + else + return softLinkAsyncRoutine( srcNativePath, dstNativePath, o.type ); + } +} + +const softLinkAct = softLinkAct_functor(); +_.routineExtend( softLinkAct, Parent.prototype.softLinkAct ); + +// + +/** + * Creates new name (hard link) for existing file. If srcPath is not file or not exists method returns false. + This method also can be invoked in next form : wTools.hardLinkAct( dstPath, srcPath ). If `o.dstPath` is already + exists and creating link finish successfully, method rewrite it, otherwise the file is kept intact. + In success method returns true, otherwise - false. + * @example + + * const fileProvider = _.FileProvider.Default(); + * let path = 'tmp/hardLinkAct/data.txt', + link = 'tmp/hardLinkAct/h_link_for_data.txt', + textData = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + textData1 = ' Aenean non feugiat mauris'; + + fileProvider.fileWrite( { filePath : path, data : textData } ); + fileProvider.hardLinkAct( link, path ); + + let content = fileProvider.fileReadSync(link); // Lorem ipsum dolor sit amet, consectetur adipiscing elit. + console.log(content); + fileProvider.fileWrite( { filePath : path, data : textData1, append : 1 } ); + + fileProvider.fileDelete( path ); // delete original name + + content = fileProvider.fileReadSync( link ); + console.log( content ); + // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean non feugiat mauris + // but file is still exists) + * @param {Object} o options parameter + * @param {string} o.dstPath link path + * @param {string} o.srcPath file path + * @param {boolean} [o.verbosity=false] enable logging. + * @returns {boolean} + * @throws {Error} if missed one of arguments or pass more then 2 arguments. + * @throws {Error} if one of arguments is not string. + * @throws {Error} if file `o.dstPath` is not exist. + * @function hardLinkAct + * @class wFileProviderHardDrive + * @namespace wTools.FileProvider + * @module Tools/mid/Files + */ + +function hardLinkAct( o ) +{ + let self = this; + + _.routine.assertOptions( hardLinkAct, arguments ); + + let dstPath = self.path.nativize( o.dstPath ); + let srcPath = self.path.nativize( o.srcPath ); + + _.assert( self._pathHasDriveLetter( srcPath ), `Expects src path that begins with drive letter, but got:"${o.srcPath}"` ); + _.assert( self._pathHasDriveLetter( dstPath ), `Expects dst path that begins with drive letter, but got:"${o.dstPath}"` ); + + _.assert( !!o.dstPath ); + _.assert( !!o.srcPath ); + + /* */ + + let con = _.Consequence().take( true ); + + if( o.dstPath === o.srcPath ) + return o.sync ? true : con; + + con.then( checkSrc ) + + if( o.context ) + { + con.then( () => o.context.tempRenameMaybe() ) + con.then( handleHardlinkBreaking ); + } + + con.then( link ); + + if( o.context ) + { + con.then( tempDelete ); + con.finally( tempRenameRevert ); + } + + if( o.sync ) + return con.sync(); + + return con; + + /* */ + + function checkSrc() + { + var con = _.Consequence.Try( () => + { + return self.statReadAct + ({ + filePath : o.srcPath, + throwing : 0, + sync : o.sync, + resolvingSoftLink : 0, + }); + }) + + con.then( function( stat ) + { + if( !stat ) + throw _.err( '{o.srcPath} does not exist on hard drive:', o.srcPath ); + if( !stat.isTerminal() ) + throw _.err( '{o.srcPath} is not a terminal file:', o.srcPath ); + return null; + }); + + if( o.sync ) + return con.sync(); + + return con; + } + + /* */ + + function handleHardlinkBreaking() + { + let c = o.context; + + if( c.options.breakingSrcHardLink ) + if( !self.fileExists( o.dstPath ) ) + { + if( c.srcStat.isHardLink() ) + return self.hardLinkBreak({ filePath : o.srcPath, sync : o.sync }); + } + else + { + if( !c.options.breakingDstHardLink ) + if( c.dstStat.isHardLink() ) + { + let con = _.Consequence.Try( () => + { + return self.fileReadAct + ({ + filePath : o.srcPath, + encoding : self.encoding, + advanced : null, + resolvingSoftLink : self.resolvingSoftLink, + sync : o.sync + }) + }) + .then( ( srcData ) => + { + let r = self.fileWriteAct + ({ + filePath : o.dstPath, + data : srcData, + encoding : 'meta.original', + writeMode : 'rewrite', + sync : o.sync, + advanced : null, + }) + return o.sync ? true : r; + }) + .then( () => + { + let r = self.fileDeleteAct + ({ + filePath : o.srcPath, + sync : o.sync + }) + return o.sync ? true : r; + }) + .then( () => + { + let dstPathTemp = dstPath; + dstPath = srcPath + srcPath = dstPathTemp; + return null; + }) + + if( o.sync ) + return con.sync(); + + return con; + } + } + return null; + } + + /* */ + + function link() + { + if( o.sync ) + { + File.linkSync( srcPath, dstPath ); + return true; + } + + let linkReady = new _.Consequence(); + File.link( srcPath, dstPath, function( err ) + { + if( err ) + return linkReady.error( err ) + linkReady.take( true ) + }); + return linkReady; + } + + /* */ + + function tempDelete( got ) + { + let r = _.Consequence.Try( () => + { + let result = o.context.tempDelete(); + return o.sync ? true : result; + }) + r.then( () => got ); + + if( o.sync ) + return r.sync(); + + return r; + } + + /* */ + + function tempRenameRevert( err, got ) + { + if( !err ) + return got; + + _.errAttend( err ); + + let r = _.Consequence.Try( () => + { + let result = o.context.tempRenameRevert() + return o.sync ? true : result; + }) + .finally( () => + { + throw _.err( err ); + }) + + if( o.sync ) + return r.sync(); + + return r; + } + +} + +_.routineExtend( hardLinkAct, Parent.prototype.hardLinkAct ); + +// + +function areHardLinkedAct( o ) +{ + let self = this; + + _.routine.assertOptions( areHardLinkedAct, arguments ); + _.assert( o.filePath.length === 2, 'Expects exactly two arguments' ); + + if( o.filePath[ 0 ] === o.filePath[ 1 ] ) + { + if( self.UsingBigIntForStat ) + return true; + return _.maybe; + } + + let statFirst = self.statRead( o.filePath[ 0 ] ); + if( !statFirst ) + return false; + + let statSecond = self.statRead( o.filePath[ 1 ] ); + if( !statSecond ) + return false; + + /* + should return _.maybe, not true if result is not precise + */ + + return _.files.stat.areHardLinked( statFirst, statSecond ); +} + +_.routineExtend( areHardLinkedAct, Parent.prototype.areHardLinkedAct ); + +// -- +// etc +// -- + +function _encodingFor( encoding ) +{ + let self = this; + let result; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( encoding ) ); + + if( encoding === 'buffer.node' || encoding === 'buffer.bytes' || encoding === 'buffer.raw' ) + result = undefined; + else + result = encoding; + + _.assert( self.KnownNativeEncodings.has( result ), () => `Unknown encoding: ${result}` ); + + return result; +} + +// -- +// encoders +// -- + +var encoders = {}; + +encoders[ 'buffer.raw' ] = +{ + + onBegin : function( e ) + { + _.assert( e.operation.encoding === 'buffer.raw' ); + e.operation.encoding = 'buffer.node'; + }, + + onEnd : function( e ) + { + if( e.stream ) + return; + _.assert( _.bufferNodeIs( e.data ) || _.bufferTypedIs( e.data ) || _.bufferRawIs( e.data ) ); + let result = _.bufferRawFrom( e.data ); + _.assert( !_.bufferNodeIs( result ) ); + _.assert( _.bufferRawIs( result ) ); + return result; + }, + +} + +// + +// yyy +// encoders[ 'js.node' ] = +// { +// +// exts : [ 'js', 's', 'ss' ], +// +// onBegin : function( e ) +// { +// e.operation.encoding = 'utf8'; +// }, +// +// onEnd : function( e ) +// { +// return require( _.fileProvider.path.nativize( e.operation.filePath ) ); +// }, +// } + +encoders[ 'buffer.bytes' ] = +{ + + onBegin : function( e ) + { + _.assert( e.operation.encoding === 'buffer.bytes' ); + }, + + onEnd : function( e ) + { + if( !e.stream ) + return _.bufferBytesFrom( e.data ); + }, + +} + +// + +encoders[ 'meta.original' ] = +{ + + onBegin : function( e ) + { + _.assert( 0 ); + }, + + onEnd : function( e ) + { + _.assert( 0 ); + }, + + onSelect : function( operation ) + { + // let system = this.system || this; + let system = this; + _.assert( operation.encoding === 'meta.original' ); + if( this.fileReadAct.encoders[ system.encoding ] && system.encoding !== 'meta.original' ) + operation.encoding = system.encoding; + else if( this.ExtraNativeEncodings.has( system.encoding ) ) + operation.encoding = system.encoding; + else + operation.encoding = 'buffer.bytes'; + operation.encoder = this.fileReadAct.encoders[ operation.encoding ]; + }, + +} + +fileReadAct.encoders = encoders; + +// + +var encoders = Object.create( null ); + +encoders[ 'meta.original' ] = +{ + + onBegin : function( e ) + { + _.assert( e.operation.encoding === 'meta.original' ); + + if( _.strIs( e.data ) ) + e.operation.encoding = 'utf8'; + else if( _.bufferBytesIs( e.data ) ) + e.operation.encoding = 'buffer.bytes'; + else if( _.bufferRawIs( e.data ) ) + e.operation.encoding = 'buffer.raw'; + else + e.operation.encoding = 'buffer.node'; + + } + +} + +fileWriteAct.encoders = encoders; + +// -- +// relations +// -- + +let KnownNativeEncodings = new Set([ undefined, 'ascii', 'base64', 'binary', 'hex', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'utf8', 'latin1' ]); +let ExtraNativeEncodings = new Set([ ... KnownNativeEncodings, 'buffer.node', 'buffer.bytes' ]); +let UsingBigIntForStat = _.files.nodeJsIsSameOrNewer( [ 10, 5, 0 ] ); /* xxx : remove */ + +let Composes = +{ + protocols : _.define.own([ 'hd', 'file' ]), +} + +let Aggregates = +{ +} + +let Associates = +{ +} + +let Restricts = +{ +} + +let Statics = +{ + + pathNativizeAct, + KnownNativeEncodings, + ExtraNativeEncodings, + UsingBigIntForStat, + Path : _.path.CloneExtending({ fileProvider : Self }), + + SupportsIno : 1, + SupportsRights : 1, + +} + +// -- +// declare +// -- + +let Extension = +{ + + // inter + + init, + + // path + + pathNativizeAct, + pathCurrentAct, + _pathHasDriveLetter, + + _isTextLink, + pathResolveTextLinkAct, + pathResolveSoftLinkAct, + + pathDirTempAct, + pathDirUserHomeAct, + pathAllowedAct, + + // read + + fileReadAct, + streamReadAct, + dirReadAct, + statReadAct, + fileExistsAct, + + // write + + fileWriteAct, + streamWriteAct, + timeWriteAct, + rightsWriteAct, + fileDeleteAct, + dirMakeAct, + + // locking + + fileLockAct, + fileUnlockAct, + fileIsLockedAct, + + // linkingAction + + fileRenameAct, + fileCopyAct, + softLinkAct, + hardLinkAct, + + // link + + areHardLinkedAct, + + // etc + + _encodingFor, + + // + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Extension, +}); + +_.assert( _.routineIs( Self.prototype.pathCurrentAct ) ); +_.assert( _.routineIs( Self.Path.current ) ); + +if( Config.interpreter === 'njs' ) +if( !_.FileProvider.Default ) +{ + _.FileProvider.Default = Self; + if( !_.fileProvider ) + _.FileProvider.Default.MakeDefault(); +} + +_.FileProvider[ Self.shortName ] = Self; + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l7_provider/HardDrive.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wfilesbasic/proto/wtools/amid/l4_files/l7_provider' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, HardDrive_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file HardDrive_ss */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wgdf */ ( function wgdf() { function wgdf_naked() { +module.exports = require( '../wtools/amid/l1/gdf/entry/Gdf.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wGdf', 'wgdf' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/node_modules/wgdf' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wgdf_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wgdf */ })(); + +/* */ /* begin of file Gdf_s */ ( function Gdf_s() { function Gdf_s_naked() { ( function _Gdf_s_( ) +{ + +'use strict'; + +/** + * Standardized abstract interface and collection of strategies to convert complex data structures from one generic data format ( GDF ) to another generic data format. You may use the module to serialize complex data structure to string or deserialize string back to the original data structure. Generic data format ( GDF ) is a format of data structure designed with taking into account none unique feature of data so that it is applicable to any kind of data. + @module Tools/mid/Gdf +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../include/Mid.s' ); + module[ 'exports' ] = _global_.wTools; +} + +/* +qqq : make it working +qqq : use algorithms from wgraphbasic to find shortest path +qqq : introduce field cost +let encoder = _.gdf.selectContext +({ + inFormat : 'buffer.raw', + outFormat : 'structure', + ext : 'yml', +})[ 0 ]; +let structure = encoder.encode( bufferRaw ); +*/ + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/entry/Gdf.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/entry' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Gdf_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Gdf_s */ })(); + +/* */ /* begin of file Basic_s */ ( function Basic_s() { function Basic_s_naked() { ( function _Basic_s_( ) +{ + +'use strict'; + +/* gdf */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../../node_modules/Tools' ); + _.include( 'wCopyable' ); + // _.include( 'wIntrospectorBasic' ); + // _.include( 'wStringsExtra' ); + // _.include( 'wStringer' ); + module[ 'exports' ] = _global_.wTools; +} + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/include/Basic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Basic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Basic_s */ })(); + +/* */ /* begin of file Mid_s */ ( function Mid_s() { function Mid_s_naked() { ( function _Mid_s_() +{ + +'use strict'; + +/* gdf */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( './Basic.s' ); + + require( '../l1/Namespace.s' ); + require( '../l2/Encoder.s' ); + require( '../l3/Context.s' ); + + require( '../l5_strategy/Base64.s' ); + require( '../l5_strategy/Bson.s' ); + require( '../l5_strategy/Cbor.s' ); + require( '../l5_strategy/Coffee.s' ); + require( '../l5_strategy/Json.s' ); + require( '../l5_strategy/JsStructure.s' ); + require( '../l5_strategy/MsgpackLite.s' ); + require( '../l5_strategy/Yml.s' ); + + module[ 'exports' ] = _global_.wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/include/Mid.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Mid_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Mid_s */ })(); + +/* */ /* begin of file Namespace_s */ ( function Namespace_s() { function Namespace_s_naked() { ( function _Namespace_s_( ) +{ + +'use strict'; + +const _ = _global_.wTools; +_.gdf = _.gdf || Object.create( null ); + +// -- +// event +// -- + +function on( o ) +{ + o = _.event.onHead( on, arguments ); + return _.event.on( this._edispatcher, o ); +} + +on.defaults = +{ + callbackMap : null, +}; + +// + +function once( o ) +{ + o = _.event.once.head( once, arguments ); + return _.event.once( this._edispatcher, o ); +} + +once.defaults = +{ + callbackMap : null, +}; + +// + +function off( o ) +{ + o = _.event.offHead( off, arguments ); + return _.event.off( this._edispatcher, o ); +} + +off.defaults = +{ + callbackMap : null, +}; + +// + +function eventHasHandler( o ) +{ + o = _.event.eventHasHandlerHead( eventHasHandler, arguments ); + return _.event.eventHasHandler( this._edispatcher, o ); +} + +eventHasHandler.defaults = +{ + eventName : null, + eventHandler : null, +} + +// + +function eventGive() +{ + let o = _.event.eventGiveHead( this._edispatcher, eventGive, arguments ); + return _.event.eventGive( this._edispatcher, o ); + // return _.event.eventGive( this._edispatcher, ... arguments ); +} + +eventGive.defaults = +{ + ... _.event.eventGive.defaults, + gdf : null, +} + +// -- +// +// -- + +/** + * Searches for converters. + * Finds converters that match the specified selector. + * Converter is selected if all fields of selector are equal with appropriate properties of the converter. + * + * @param {Object} selector a map with one or several rules that should be met by the converter + * + * Possible selector properties are : + * @param {String} [selector.inFormat] Input format of the converter + * @param {String} [selector.outFormat] Output format of the converter + * @param {String} [selector.ext] File extension of the converter + * @param {Boolean|Number} [selector.default] Selects default converter for provided inFormat, outFormat and ext + * + * @example + * //returns converters that accept string as input + * let converters = _.gdf.select({ inFormat : 'string.utf8' }); + * console.log( converters ) + * + * @example + * //returns converters that accept string and return structure( object ) + * let converters = _.gdf.select({ inFormat : 'string.utf8', outFormat : 'structure' }); + * console.log( converters ) + * + * * @example + * //returns default json converter that encodes structure to string + * let converters = _.gdf.select({ inFormat : 'structure', outFormat : 'string.utf8', ext : 'json', default : 1 }); + * console.log( converters[ 0 ] ) + * + * @returns {Array} Returns array with selected converters or empty array if nothing found. + * @throws {Error} If more than one argument is provided + * @throws {Error} If selector is not an Object + * @throws {Error} If selector has unknown field + * @method select + * @class wGenericDataFormatConverter + * @namespace Tools.gdf + * @module Tools/mid/Gdf + * @static + */ + +function select( o ) +{ + let names = [ 'inFormat', 'outFormat', 'ext' ]; + let result; + + o = _.routine.options_( select, o ); + _.assert( arguments.length === 1 ); + + if( o.inFormat === null && o.outFormat === null && o.ext === null ) + { + if( o.filePath ) + o.ext = _.path.ext( o.filePath ); + } + + if( o.inFormat || o.outFormat || o.ext ) + { + let name, val; + if( o.inFormat ) + { + _.assert( _.strDefined( o.inFormat ) ); + if( _.gdf.inMap[ o.inFormat ] ) + result = _.gdf.inMap[ o.inFormat ].slice(); + else + result = []; + } + else if( o.outFormat ) + { + _.assert( _.strDefined( o.outFormat ) ); + if( _.gdf.outMap[ o.outFormat ] ) + result = _.gdf.outMap[ o.outFormat ].slice(); + else + result = []; + } + else if( o.ext ) + { + _.assert( _.strDefined( o.ext ) ); + if( _.gdf.extMap[ o.ext ] ) + result = _.gdf.extMap[ o.ext ].slice(); + else + result = []; + } + } + else + { + result = _.gdf.encodersArray.slice(); + } + + result = result.filter( ( encoder ) => + { + let o2 = _.props.extend( null, o ); + delete o2.single; + delete o2.encoderName; + return encoder.supports( o2 ); + }); + + if( o.encoderName !== null && o.encoderName !== undefined ) + { + result = result.filter( ( e ) => e.shortName === o.encoderName || e.name === o.encoderName ); + } + + if( result.length > 1 ) + if( o.single ) + { + result = result.filter( ( e ) => e.feature ? e.feature.default : false ); + } + + return result; +} + +select.defaults = +{ + data : null, + inFormat : null, + outFormat : null, + encoderName : null, + filePath : null, + ext : null, + single : 1, + feature : null, +} + +// + +function selectContext( o ) +{ + let result = this.select( o ); + result = result.map( ( e ) => _.props.extend( null, o, { encoder : e } ) ); + result = _.gdf.Context( result ); + return result; +} + +selectContext.defaults = +{ + ... select.defaults, +} + +// + +function selectSingleContext( o ) +{ + let result = this.selectContext( o ); + _.assert( result.length <= 1, () => `Found several ( ${result.length} ) encoders` ); + _.assert( result.length > 0, () => `Found no encoder` ); + return result[ 0 ]; +} + +selectSingleContext.defaults = +{ + ... select.defaults, +} + +// + +function formatNameSplit( name ) +{ + return name.split( '.' ); +} + +// -- +// declare +// -- + +/** + * @summary Contains descriptors of registered converters. + * @property {Object} encodersArray + * @static + * @class wGenericDataFormatConverter + * @namespace Tools.gdf + * @module Tools/mid/Gdf + */ + +/** + * @summary Contains descriptors of registered converters mapped by inptut format. + * @property {Object} inMap + * @static + * @class wGenericDataFormatConverter + * @namespace Tools.gdf + * @module Tools/mid/Gdf + */ + +/** + * @summary Contains descriptors of registered converters mapped by out format. + * @property {Object} outMap + * @static + * @class wGenericDataFormatConverter + * @namespace Tools.gdf + * @module Tools/mid/Gdf + */ + +/** + * @summary Contains descriptors of registered converters mapped by extension. + * @property {Object} extMap + * @static + * @class wGenericDataFormatConverter + * @namespace Tools.gdf + * @module Tools/mid/Gdf + */ + +/** + * @summary Contains descriptors of registered converters mapped by in/out format. + * @property {Object} inOutMap + * @static + * @class wGenericDataFormatConverter + * @namespace Tools.gdf + * @module Tools/mid/Gdf + */ + +let encodersArray = []; +let inMap = Object.create( null ); +let outMap = Object.create( null ); +let extMap = Object.create( null ); +let inOutMap = Object.create( null ); + +let events = +{ + 'gdf.form' : [], + 'gdf.unform' : [], +} + +let _edispatcher = +{ + events, +} + +let Extension = +{ + + // event + + on, + once, + off, + eventHasHandler, + eventGive, + + // routine + + select, + selectContext, + selectSingleContext, + formatNameSplit, + + // field + + _edispatcher, + encodersArray, + inMap, + outMap, + extMap, + inOutMap, + +} + +/* _.props.extend */Object.assign( _.gdf, Extension ); + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l1/Namespace.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Namespace_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Namespace_s */ })(); + +/* */ /* begin of file Encoder_s */ ( function Encoder_s() { function Encoder_s_naked() { (function _Encoder_s_() +{ + +'use strict'; + +/** + * @classdesc Class to operate the GDF encoder. + * @class wGenericDataFormatEncoder + * @namespace Tools + * @module Tools/mid/Gdf + */ + +const _global = _global_; +const _ = _global_.wTools; +const Parent = null; +const Self = wGenericDataFormatEncoder; +function wGenericDataFormatEncoder( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'Gdf'; + +// -- +// routine +// -- + +function finit() +{ + let encoder = this; + encoder.unform(); + return _.Copyable.prototype.finit.apply( encoder, arguments ); +} + +// + +function init( o ) +{ + let encoder = this; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + _.workpiece.initFields( encoder ); + Object.preventExtensions( encoder ); + + if( o ) + encoder.copy( o ); + + encoder.form(); + return encoder; +} + +// + +function unform() +{ + let encoder = this; + + _.gdf.eventGive({ event : 'gdf.unform', gdf : encoder }); + + encoder.formed = 0; + + _.arrayRemoveOnceStrictly( _.gdf.encodersArray, encoder ); + + encoder.inFormat.forEach( ( e, k ) => + { + _.arrayRemoveOnceStrictly( _.gdf.inMap[ e ], encoder ); + let splits = _.gdf.formatNameSplit( e ); + if( splits.length > 1 ) + splits.forEach( ( split ) => _.arrayRemoveOnce( _.gdf.inMap[ split ], encoder ) ); + }); + + encoder.outFormat.forEach( ( e, k ) => + { + _.arrayRemoveOnceStrictly( _.gdf.outMap[ e ], encoder ); + let splits = _.gdf.formatNameSplit( e ); + if( splits.length > 1 ) + splits.forEach( ( split ) => _.arrayRemoveOnce( _.gdf.outMap[ split ], encoder ) ); + }); + + encoder.ext.forEach( ( e, k ) => + { + _.arrayRemoveOnceStrictly( _.gdf.extMap[ e ], encoder ); + }); + + encoder.inOut.forEach( ( e, k ) => + { + _.arrayRemoveOnceStrictly( _.gdf.inOutMap[ e ], encoder ); + }); + + return encoder; +} + +// + +/** + * @summary Registers current encoder. + * @description + * Checks descriptor of current encoder and it into maps: InMap, OutMap, ExtMap, InOutMap. + * Generates name for encoder if its not specified explicitly. + * @method form + * @class wGenericDataFormatEncoder + * @namespace Tools + * @module Tools/mid/Gdf + */ + +function form() +{ + let encoder = this; + + _.assert( encoder.inOut === null ); + _.assert( _.mapIs( encoder.feature ), `Expects map {- feature -}` ); + _.assert( encoder.name === null ); + _.assert( encoder.formed === 0 ); + + encoder.formed = 1; + + if( encoder.feature.config === undefined ) + encoder.feature.config = true; + if( encoder.feature.default !== undefined ) + encoder.feature.default = !!encoder.feature.default; + + encoder.inFormat = _.array.as( encoder.inFormat ); + encoder.outFormat = _.array.as( encoder.outFormat ); + encoder.ext = _.array.as( encoder.ext ); + + if( encoder.shortName === null && encoder.ext[ 0 ] ) + encoder.shortName = encoder.ext[ 0 ]; + if( encoder.name === null ) + encoder.name = encoder.shortName + ':' + encoder.inFormat[ 0 ] + '->' + encoder.outFormat[ 0 ]; + + if( Config.debug ) + { + encoder.inFormat.forEach( ( format ) => + { + _.assert( _.strIs( format ), () => `Expects string as name of in-format` ); + _.assert( !_.strHas( format, '-' ), () => `Expects no "-" in name of in-format, but got ${format}` ); + _.assert( _.strHas( format, '.' ) || format === 'structure', () => `Expects "." in name of in-format, but got ${format}` ); + }); + encoder.outFormat.forEach( ( format ) => + { + _.assert( _.strIs( format ), () => `Expects string as name of in-format` ); + _.assert( !_.strHas( format, '-' ), () => `Expects no "-" in name of in-format, but got ${format}` ); + _.assert( _.strHas( format, '.' ) || format === 'structure', () => `Expects "." in name of in-format, but got ${format}` ); + }); + _.assert( _.strsAreAll( encoder.inFormat ) ); + _.assert( _.strsAreAll( encoder.outFormat ) ); + _.assert( _.strsAreAll( encoder.ext ) ); + _.assert( _.strDefined( encoder.shortName ), () => 'Expects defined shortName' ); + } + + /* - */ + + _.arrayAppendOnceStrictly( _.gdf.encodersArray, encoder ); + + encoder.inFormat.forEach( ( e, k ) => + { + _.gdf.inMap[ e ] = _.arrayAppendOnceStrictly( _.gdf.inMap[ e ] || null, encoder ); + let splits = _.gdf.formatNameSplit( e ); + if( splits.length > 1 ) + splits.forEach( ( split ) => _.gdf.inMap[ split ] = _.arrayAppendOnce( _.gdf.inMap[ split ] || null, encoder ) ); + }); + + encoder.outFormat.forEach( ( e, k ) => + { + _.gdf.outMap[ e ] = _.arrayAppendOnceStrictly( _.gdf.outMap[ e ] || null, encoder ); + let splits = _.gdf.formatNameSplit( e ); + if( splits.length > 1 ) + splits.forEach( ( split ) => _.gdf.outMap[ split ] = _.arrayAppendOnce( _.gdf.outMap[ split ] || null, encoder ) ); + }); + + encoder.ext.forEach( ( e, k ) => + { + _.gdf.extMap[ e ] = _.arrayAppendOnceStrictly( _.gdf.extMap[ e ] || null, encoder ); + }); + + let inOut = _.permutation.eachSample([ encoder.inFormat, encoder.outFormat ]); + encoder.inOut = []; + inOut.forEach( ( inOut ) => + { + let key = inOut.join( '->' ); + encoder.inOut.push( key ); + _.gdf.inOutMap[ key ] = _.arrayAppendOnceStrictly( _.gdf.inOutMap[ key ] || null, encoder ); + }); + + /* - */ + + _.assert( _.strIs( encoder.name ) ); + _.assert( _.strsAreAll( encoder.inFormat ) ); + _.assert( _.strsAreAll( encoder.outFormat ) ); + _.assert( _.strsAreAll( encoder.ext ) ); + _.assert( encoder.inFormat.length >= 1 ); + _.assert( encoder.outFormat.length >= 1 ); + _.assert( encoder.ext.length >= 0 ); + _.assert( _.routineIs( encoder.onEncode ) ); + + // if( _.longHas( encoder.ext, 'yaml' ) ) + // debugger; + _.gdf.eventGive({ event : 'gdf.form', gdf : encoder }); + + return encoder; +} + +// + +/** + * @summary Encodes source data from one specific format to another. + * @description + * Possible in/out formats are determined by encoder. + * Use {@link module:Tools/mid/Gdf.gdf.select select} routine to find encoder for your needs. + * @param {Object} o Options map + * + * @param {*} o.data Source data. + * @param {String} o.format Format of source `o.data`. + * @param {Object} o.params Map with enviroment variables that will be used by encoder. + * + * @example + * //returns encoders that accept string as input + * let encoders = _.gdf.selectContext({ inFormat : 'string.utf8', outFormat : 'structure', ext : 'cson' }); + * let src = 'val : 13'; + * let dst = encoders[ 0 ]._encode({ data : src, format : 'string.utf8' }); + * console.log( dst.data ); //{ val : 13 } + * + * @returns {Object} Returns map with properties: `data` - result of encoding and `format` : format of the result. + * @method _encode + * @class wGenericDataFormatEncoder + * @namespace Tools + * @module Tools/mid/Gdf + */ + +function encode_head( routine, args ) +{ + let encoder = this; + let o = args[ 0 ]; + + _.assert( arguments.length === 2 ); + _.routine.options_( routine, o ); + + return o; +} + +// + +function _encode( op ) +{ + let encoder = this; + + _.assert( arguments.length === 1 ); + _.routine.assertOptions( _encode, arguments ); + + return encoder.onEncode( op ); +} + +_encode.defaults = +{ + in : null, + out : null, + sync : null, + params : null, + err : null, +} + +// + +function encode_body( o ) +{ + let encoder = this; + let result; + + _.assert( arguments.length === 1 ); + _.routine.options_( encode_body, arguments ); + + if( !o.filePath ) + if( o.params && _.strIs( o.params.filePath ) ) + o.filePath = o.params.filePath; + + if( !o.ext ) + if( o.filePath ) + o.filePath = _.path.ext( o.filePath ); + if( o.ext ) + o.ext = o.ext.toLowerCase() + + /* */ + + let op = Object.create( null ); + + op.in = Object.create( null ); + op.in.data = o.data; + op.in.filePath = o.filePath; + op.in.ext = o.ext; + op.in.format = o.format || encoder.inFormat; + if( _.arrayIs( op.in.format ) ) + op.in.format = op.in.format.length === 1 ? op.in.format[ 0 ] : null; + + op.out = Object.create( null ); + op.out.data = undefined; + op.out.format = null; + + op.params = o.params || Object.create( null ); + op.sync = o.sync; + // if( o.params.sync !== undefined ) + // op.sync = o.params.sync; + op.err = null; + + if( op.sync === null ) + op.sync = true; + + /* */ + + try + { + + _.assert( _.object.isBasic( op.params ) ); + _.assert( op.in.format === null || _.strIs( op.in.format ), 'Not clear which input format is' ); + _.assert( op.in.format === null || encoder.inFormatSupports( op.in.format ), () => `Unknown format ${op.in.format}` ); + + // if( op.in.format === 'structure' ) + // debugger; + + result = encoder._encode( op ); + // logger.log( `${op.in.format} -> ${op.out.format} , filePath : ${op.in.filePath}` ); + + // structure + // string.utf8 + + if( result === undefined ) + result = op; + + op.out.format = op.out.format || encoder.outFormat; + if( _.arrayIs( op.out.format ) ) + op.out.format = op.out.format.length === 1 ? op.out.format[ 0 ] : undefined; + + _.assert( _.strIs( op.out.format ), 'Output should have format' ); + _.assert( _.longHas( encoder.outFormat, op.out.format ), () => 'Strange output format ' + o.out.format ); + _.routine.assertOptions( encoder._encode, op ); + _.assert( result === op || _.consequenceIs( result ) ); + // _.assert( op.params.sync === undefined ); + + } + catch( err ) + { + let outFormat = op.out.format || encoder.outFormat; + throw _.err + ( + err + , `\nFailed to convert from "${op.in.format}" to "${outFormat}" by encoder ${encoder.name}` + ); + } + + /* */ + + return result; +} + +encode_body.defaults = +{ + data : null, + format : null, + filePath : null, + ext : null, + sync : null, + params : null, +} + +let encode = _.routine.uniteCloning_replaceByUnite( encode_head, encode_body ); + +// + +function supports( o ) +{ + let encoder = this; + let counter = 0; + + o = _.routine.options_( supports, arguments ); + + if( !o.ext ) + if( o.filePath ) + o.filePath = _.path.ext( o.filePath ); + if( o.ext ) + o.ext = o.ext.toLowerCase(); + + _.assert( o.ext === null || _.strIs( o.ext ) ); + + if( o.inFormat ) + if( encoder.inFormatSupports( o.inFormat ) ) + o.counter += 1; + else + return false; + + if( o.outFormat ) + if( encoder.outFormatSupports( o.outFormat ) ) + o.counter += 1; + else + return false; + + if( o.ext ) + if( _.longHas( encoder.ext, o.ext ) ) + o.counter += 1; + else + return false; + + if( o.feature ) + { + for( let f in o.feature ) + if( o.feature[ f ] === encoder.feature[ f ] ) + o.counter += 1; + else + return false; + } + + return encoder._supports( o ); +} + +supports.defaults = +{ + counter : 0, + inFormat : null, + outFormat : null, + ext : null, + filePath : null, + data : null, + feature : null, +} + +// + +function _supports( o ) +{ + let encoder = this; + return true; +} + +_supports.defaults = +{ + ... supports.defaults, +} + +// + +function inFormatSupports( inFormat ) +{ + let encoder = this; + _.assert( _.strDefined( inFormat ) ); + return !!_.any( encoder.inFormat, ( encoderInFormat ) => + { + return _.longHasAll( _.gdf.formatNameSplit( encoderInFormat ), _.gdf.formatNameSplit( inFormat ) ); + }); +} + +// + +function outFormatSupports( outFormat ) +{ + let encoder = this; + _.assert( _.strDefined( outFormat ) ); + return !!_.any( encoder.outFormat, ( encoderOutFormat ) => + { + return _.longHasAll( _.gdf.formatNameSplit( encoderOutFormat ), _.gdf.formatNameSplit( outFormat ) ); + }); +} + +// + +/** + * @summary Fields of wGenericDataFormatEncoder class. + * @typedef {Object} Composes + * @property {String} name=null Name of the encoder + * @property {String} shortName=null Short name of the encoder + * @property {Array} ext=null Supported extensions + * @property {Array} in=null Input format + * @property {Array} out=null Output format + * @property {Array} inOut=null All combinations of in-out formats + * @property {Object} feature=null Map with feature types of data + * + * @class wGenericDataFormatEncoder + * @namespace Tools + * @module Tools/mid/Gdf + */ + +// -- +// relations +// -- + +let Composes = +{ + + name : null, + shortName : null, + + ext : null, + inFormat : null, + outFormat : null, + inOut : null, + + feature : null, + onEncode : null, + +} + +let Aggregates = +{ +} + +let Restricts = +{ + formed : 0, +} + +let Statics = +{ +} + +let Forbids = +{ + + Select : 'Select', + Elements : 'Elements', + InMap : 'InMap', + OutMap : 'OutMap', + ExtMap : 'ExtMap', + InOutMap : 'InOutMap', + forConfig : 'forConfig', + default : 'default', + supporting : 'supporting', + in : 'in', + out : 'out', + +} + +// -- +// declare +// -- + +let Proto = +{ + + finit, + init, + unform, + form, + _encode, + encode, + + supports, + _supports, + + inFormatSupports, + outFormatSupports, + + // relations + + Composes, + Aggregates, + Restricts, + Statics, + Forbids, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); + +_.Copyable.mixin( Self ); + +// -- +// export +// -- + +_.Gdf = Self; +_.gdf.Encoder = Self; +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l2/Encoder.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l2' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Encoder_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Encoder_s */ })(); + +/* */ /* begin of file Context_s */ ( function Context_s() { function Context_s_naked() { (function _Context_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Parent = null; +const Self = wGenericDataFormatContext; +function wGenericDataFormatContext( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'Context'; + +// -- +// implementation +// -- + +function init( o ) +{ + let context = this; + _.assert( arguments.length <= 1 ); + _.props.extend( context, o ) + delete context.default; + Object.preventExtensions( context ); + _.assert( context.encoder instanceof _.Gdf ); + let proxy = _.proxyMap( context, context.encoder ); + return proxy; +} + +// + +function encode_body( o ) +{ + let context = this; + + _.routine.assertOptions( encode, arguments ); + + if( o.format === null ) + o.format = context.inFormat; + + let result = context.encoder.encode.body.call( context.encoder, o ); + + return result; +} + +_.routineExtend( encode_body, _.Gdf.prototype.encode.body ); + +let encode = _.routine.uniteCloning_replaceByUnite( _.Gdf.prototype.encode.head, encode_body ); + +// -- +// declare +// -- + +let Proto = +{ + + init, + encode, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); + +// -- +// export +// -- + +_.gdf[ Self.shortName ] = Self; +if( typeof module !== 'undefined' && module !== null ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l3/Context.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Context_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Context_s */ })(); + +/* */ /* begin of file Base64_s */ ( function Base64_s() { function Base64_s_naked() { ( function _Base64_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.encode = _.encode || Object.create( null ); + +// -- +// base64 +// -- + +let base64ToBuffer = +{ + + shortName : 'base64', + ext : [], + inFormat : [ 'string.base64' ], + outFormat : [ 'buffer.bytes' ], + feature : {}, + + onEncode : function( op ) + { + _.assert( _.strIs( op.in.data ) ); + op.out.data = _base64ToBuffer( op.in.data, op.params ? op.params.chunkSize : undefined ) + op.out.format = 'buffer.bytes'; + }, + +} + +// + +function _base64ToBuffer( base64, chunkSize ) +{ + + function base64ToWrdBits6( chr ) + { + let result; + if( chr > 64 && chr < 91 ) + result = chr - 65; + else if( chr > 96 && chr < 123 ) + result = chr - 71; + else if( chr > 47 && chr < 58 ) + result = chr + 4; + else if( chr === 43 ) + result = 62; + else if( chr === 47 ) + result = 63; + else + result = 0; + return result; + } + + var srcSize = base64.length; + var dstSize = chunkSize ? Math.ceil( ( srcSize * 3 + 1 >> 2 ) / chunkSize ) * chunkSize : srcSize * 3 + 1 >> 2 + var bytes = new U8x( dstSize ); + + var factor3, factor4; + var wrd3 = 0; + var outIndex = 0; + + for( var inIndex = 0; inIndex < srcSize; inIndex++ ) + { + + factor4 = inIndex & 3; + wrd3 |= base64ToWrdBits6( base64.charCodeAt( inIndex ) ) << 18 - 6 * factor4; + if( factor4 === 3 || srcSize - inIndex === 1 ) + { + for( factor3 = 0; factor3 < 3 && outIndex < dstSize; factor3++, outIndex++ ) + { + bytes[ outIndex ] = wrd3 >>> ( 16 >>> factor3 & 24 ) & 255; + } + wrd3 = 0; + } + + } + + return bytes; +} + +// + +let base64FromBuffer = +{ + + shortName : 'base64', + ext : [], + inFormat : [ 'buffer.bytes' ], + outFormat : [ 'string.base64' ], + feature : {}, + + onEncode : function( op ) + { + _.assert( _.bufferBytesIs( op.in.data ) ); + op.out.data = _base64FromBuffer( op.in.data ) + op.out.format = 'string.base64'; + }, +} + +// + +function _base64FromBuffer( byteBuffer ) +{ + + function wrdBits6ToBase64( wrdBits6 ) + { + let result; + + if( wrdBits6 < 26 ) + result = wrdBits6 + 65; + else if( wrdBits6 < 52 ) + result = wrdBits6 + 71; + else if( wrdBits6 < 62 ) + result = wrdBits6 - 4; + else if( wrdBits6 === 62 ) + result = 43; + else if( wrdBits6 === 63 ) + result = 47; + else + result = 65; + + return result; + } + + _.assert( byteBuffer instanceof U8x ); + + var factor3 = 2; + var result = ''; + var size = byteBuffer.length; + + for( var l = size, wrd3 = 0, index = 0; index < l; index++ ) + { + + factor3 = index % 3; + + wrd3 |= byteBuffer[ index ] << ( 16 >>> factor3 & 24 ); + if( factor3 === 2 || l - index === 1 ) + { + + var a = wrdBits6ToBase64( wrd3 >>> 18 & 63 ); + var b = wrdBits6ToBase64( wrd3 >>> 12 & 63 ); + var c = wrdBits6ToBase64( wrd3 >>> 6 & 63 ); + var d = wrdBits6ToBase64( wrd3 & 63 ); + result += String.fromCharCode( a, b, c, d ); + wrd3 = 0; + + } + + } + + let postfix; + + if( factor3 === 2 ) + postfix = ''; + else if( factor3 === 1 ) + postfix = '='; + else + postfix = '=='; + + return result.substr( 0, result.length - 2 + factor3 ) + postfix; +} + +// + +let base64ToBlob = +{ + + shortName : 'base64', + ext : [], + inFormat : [ 'string.base64' ], + outFormat : [ 'buffer.blob' ], + feature : {}, + + onEncode : function( op ) + { + _.assert( _.strIs( op.in.data ) ); + op.out.data = _base64ToBlob( op.in.data, op.params ? op.params.mime : undefined ) + op.out.format = 'buffer.blob'; + }, +} + +function _base64ToBlob( base64Data, mime ) +{ + var mime = mime || 'application/octet-stream'; + var buffer = _base64ToBuffer( base64Data ); + return new Blob( buffer, { type : mime } ); +} + +// Vova : added opposite version of base64ToBlob, is it needed? +// qqq : yes + +// let base64FromBlob = null; +// if( _.workerIs() ) +// base64FromBlob = +// { +// ext : [], +// inFormat : [ 'buffer.blob' ], +// outFormat : [ 'string.base64' ], + +// onEncode : function( op ) +// { +// op.out.data = _base64FromBlob( op.in.data ) +// op.out.format = 'string.base64'; +// }, +// } + +// function _base64FromBlob( blob ) +// { +// if( !_.workerIs() ) +// return blob; + +// let reader = new FileReaderSync(); +// let result = reader.readAsText( blob ); +// result = _base64FromUtf8( result ); +// return result; +// } + +// -- +// utf8 +// -- + +let base64FromUtf8Slow = +{ + shortName : 'base64FromUtf8Slow', + + ext : [], + inFormat : [ 'string.utf8' ], + outFormat : [ 'string.base64' ], + feature : {}, + + onEncode : function( op ) + { + _.assert( _.strIs( op.in.data ) ); + op.out.data = _base64FromUtf8Slow( op.in.data ) + op.out.format = 'string.base64'; + }, +} + +function _base64FromUtf8Slow( string ) +{ + var base64 = btoa( unescape( encodeURIComponent( string ) ) ); + return base64; +} + +// + +let base64FromUtf8 = +{ + + shortName : 'base64', + // shortName : 'base64FromUtf8', + // default : 1, + + ext : [], + inFormat : [ 'string.utf8' ], + outFormat : [ 'string.base64' ], + feature : { default : 1 }, + + onEncode : function( op ) + { + _.assert( _.strIs( op.in.data ) ); + op.out.data = _base64FromUtf8( op.in.data ) + op.out.format = 'string.base64'; + }, +} + +// + +function _base64FromUtf8( string ) +{ + var buffer = _utf8ToBuffer( string ); + var result = _base64FromBuffer( buffer ); + return result; +} + +// + +let base64ToUtf8Slow = +{ + + shortName : 'base64', + ext : [], + inFormat : [ 'string.base64' ], + outFormat : [ 'string.utf8' ], + feature : {}, + + onEncode : function( op ) + { + _.assert( _.strIs( op.in.data ) ); + op.out.data = _base64ToUtf8Slow( op.in.data ) + op.out.format = 'string.utf8'; + }, +} + +function _base64ToUtf8Slow( base64 ) +{ + var result = atob( base64 ) + return result; +} + +// + +let base64ToUtf8 = +{ + + shortName : 'base64', + // shortName : 'base64ToUtf8', + // default : 1, + + ext : [], + inFormat : [ 'string.base64' ], + outFormat : [ 'string.utf8' ], + feature : { default : 1 }, + + onEncode : function( op ) + { + _.assert( _.strIs( op.in.data ) ); + op.out.data = _base64ToUtf8( op.in.data ) + op.out.format = 'string.utf8'; + }, +} + +function _base64ToUtf8( base64 ) +{ + var buffer = _base64ToBuffer( base64 ); + let result = _utf8FromBuffer( buffer ); + return result; +} + +// + +let utf8FromBuffer = +{ + + shortName : 'base64', + ext : [], + inFormat : [ 'buffer.bytes' ], + outFormat : [ 'string.utf8' ], + feature : {}, + + onEncode : function( op ) + { + _.assert( _.bufferBytesIs( op.in.data ) ); + op.out.data = _utf8FromBuffer( op.in.data ) + op.out.format = 'string.utf8'; + }, +} + +// + +function _utf8FromBuffer( byteBuffer ) +{ + var result = ''; + + _.assert( byteBuffer instanceof U8x ); + + for( var nPart, nLen = byteBuffer.length, index = 0; index < nLen; index++ ) + { + nPart = byteBuffer[ index ]; + + let charCode; + + if( nPart > 251 && nPart < 254 && index + 5 < nLen ) + charCode = ( nPart - 252 ) * 1073741824 + ( byteBuffer[ ++index ] - 128 << 24 ) + ( byteBuffer[ ++index ] - 128 << 18 ) + + ( byteBuffer[ ++index ] - 128 << 12 ) + ( byteBuffer[ ++index ] - 128 << 6 ) + byteBuffer[ ++index ] - 128; + else if( nPart > 247 && nPart < 252 && index + 4 < nLen ) + charCode = ( nPart - 248 << 24 ) + ( byteBuffer[ ++index ] - 128 << 18 ) + ( byteBuffer[ ++index ] - 128 << 12 ) + + ( byteBuffer[ ++index ] - 128 << 6 ) + byteBuffer[ ++index ] - 128; + else if( nPart > 239 && nPart < 248 && index + 3 < nLen ) + charCode = ( nPart - 240 << 18 ) + ( byteBuffer[ ++index ] - 128 << 12 ) + ( byteBuffer[ ++index ] - 128 << 6 ) + + byteBuffer[ ++index ] - 128; + else if( nPart > 223 && nPart < 240 && index + 2 < nLen ) + charCode = ( nPart - 224 << 12 ) + ( byteBuffer[ ++index ] - 128 << 6 ) + byteBuffer[ ++index ] - 128; + else if( nPart > 191 && nPart < 224 && index + 1 < nLen ) + charCode = ( nPart - 192 << 6 ) + byteBuffer[ ++index ] - 128; + else + charCode = nPart; + + result += String.fromCharCode( charCode ); + } + + return result; +} + + +// + +let utf8ToBuffer = +{ + + shortName : 'utf8', + ext : [], + inFormat : [ 'string.utf8' ], + outFormat : [ 'buffer.bytes' ], + feature : {}, + + onEncode : function( op ) + { + _.assert( _.strIs( op.in.data ) ); + op.out.data = _utf8ToBuffer( op.in.data ) + op.out.format = 'buffer.bytes'; + }, +} + +// + +function _utf8ToBuffer( str ) +{ + + var chr; + var nStrLen = str.length; + var size = 0; + + /* */ + + for( let index = 0; index < nStrLen; index++ ) + { + chr = str.charCodeAt( index ); + + if( chr < 0x80 ) + size += 1; + else if( chr < 0x800 ) + size += 2; + else if( chr < 0x10000 ) + size += 3; + else if( chr < 0x200000 ) + size += 4; + else if( chr < 0x4000000 ) + size += 5; + else + size += 6; + + } + + var byteBuffer = new U8x( size ); + + /* */ + + for( var index = 0, nChrIdx = 0; index < size; nChrIdx++ ) + { + chr = str.charCodeAt( nChrIdx ); + if( chr < 128 ) + { + /* one byte */ + byteBuffer[ index++ ] = chr; + } + else if( chr < 0x800 ) + { + /* two bytes */ + byteBuffer[ index++ ] = 192 + ( chr >>> 6 ); + byteBuffer[ index++ ] = 128 + ( chr & 63 ); + } + else if( chr < 0x10000 ) + { + /* three bytes */ + byteBuffer[ index++ ] = 224 + ( chr >>> 12 ); + byteBuffer[ index++ ] = 128 + ( chr >>> 6 & 63 ); + byteBuffer[ index++ ] = 128 + ( chr & 63 ); + } + else if( chr < 0x200000 ) + { + /* four bytes */ + byteBuffer[ index++ ] = 240 + ( chr >>> 18 ); + byteBuffer[ index++ ] = 128 + ( chr >>> 12 & 63 ); + byteBuffer[ index++ ] = 128 + ( chr >>> 6 & 63 ); + byteBuffer[ index++ ] = 128 + ( chr & 63 ); + } + else if( chr < 0x4000000 ) + { + /* five bytes */ + byteBuffer[ index++ ] = 248 + ( chr >>> 24 ); + byteBuffer[ index++ ] = 128 + ( chr >>> 18 & 63 ); + byteBuffer[ index++ ] = 128 + ( chr >>> 12 & 63 ); + byteBuffer[ index++ ] = 128 + ( chr >>> 6 & 63 ); + byteBuffer[ index++ ] = 128 + ( chr & 63 ); + } + else /* if ( chr <= 0x7fffffff ) */ + { + /* six bytes */ + byteBuffer[ index++ ] = 252 + ( chr / 1073741824 ); + byteBuffer[ index++ ] = 128 + ( chr >>> 24 & 63 ); + byteBuffer[ index++ ] = 128 + ( chr >>> 18 & 63 ); + byteBuffer[ index++ ] = 128 + ( chr >>> 12 & 63 ); + byteBuffer[ index++ ] = 128 + ( chr >>> 6 & 63 ); + byteBuffer[ index++ ] = 128 + ( chr & 63 ); + } + } + + return byteBuffer; +} + +// -- +// declare +// -- + +var Extension = +{ + // base64 + + base64ToBuffer : _base64ToBuffer, + base64FromBuffer : _base64FromBuffer, + base64ToBlob : _base64ToBlob, + // base64FromBlob : _base64FromBlob, + + base64FromUtf8Slow : _base64FromUtf8Slow, + base64FromUtf8 : _base64FromUtf8, + base64ToUtf8Slow : _base64ToUtf8Slow, + base64ToUtf8 : _base64ToUtf8, + + // utf8 + + utf8FromBuffer : _utf8FromBuffer, + utf8ToBuffer : _utf8ToBuffer, +} + +/* _.props.extend */Object.assign( _.encode, Extension ); + +// -- +// register +// -- + +_.Gdf([ base64ToBuffer, base64FromBuffer ]); +_.Gdf([ base64ToBlob ]); +_.Gdf([ base64FromUtf8Slow, base64ToUtf8Slow, base64FromUtf8, base64ToUtf8 ]); +_.Gdf([ utf8FromBuffer, utf8ToBuffer ]); + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy/Base64.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Base64_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Base64_s */ })(); + +/* */ /* begin of file Bson_s */ ( function Bson_s() { function Bson_s_naked() { ( function _Bson_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.encode = _.encode || Object.create( null ); + +// -- +// bson +// -- + +let Bson, BsonPath; +try +{ + BsonPath = require.resolve( 'bson' ); +} +catch( err ) +{ +} + +let bsonSupported = +{ + primitive : 2, + regexp : 2, + buffer : 0, + structure : 2 +} + +let readBson = null; +if( BsonPath ) +readBson = +{ + + ext : [ 'bson' ], + inFormat : [ 'buffer.node' ], + outFormat : [ 'structure' ], + + feature : bsonSupported, + + onEncode : function( op ) + { + if( !Bson ) + { + Bson = require( BsonPath ); + Bson.setInternalBufferSize( 1 << 30 ); + } + _.assert( _.bufferAnyIs( op.in.data ), 'Expects buffer' ); + op.in.data = _.bufferNodeFrom( op.in.data ); + op.out.data = Bson.deserialize( op.in.data ); + op.out.format = 'structure'; + }, + +} + +let writeBson = null; +if( BsonPath ) +writeBson = +{ + + ext : [ 'bson' ], + inFormat : [ 'structure' ], + outFormat : [ 'buffer.node' ], + + feature : bsonSupported, + + onEncode : function( op ) + { + + if( !Bson ) + { + Bson = require( BsonPath ); + Bson.setInternalBufferSize( 1 << 30 ); + } + + _.assert( _.mapIs( op.in.data ) ); + op.out.data = Bson.serialize( op.in.data ); + op.out.format = 'buffer.node'; + }, + +} + +// -- +// declare +// -- + +var Extension = +{ + +} + +Object.assign( _.encode, Extension ); + +// -- +// register +// -- + +// debugger; +_.Gdf([ readBson, writeBson ]); + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy/Bson.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Bson_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Bson_s */ })(); + +/* */ /* begin of file Cbor_s */ ( function Cbor_s() { function Cbor_s_naked() { ( function _Cbor_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.encode = _.encode || Object.create( null ); + +// -- +// cbor +// -- + +let Cbor, CborPath; +try +{ + CborPath = require.resolve( 'cbor' ); +} +catch( err ) +{ +} + +let cborSupported = +{ + primitive : 3, + regexp : 1, + buffer : 1, + structure : 2 +} + +let readCbor = null; +if( CborPath ) +readCbor = +{ + + ext : [ 'cbor' ], + inFormat : [ 'buffer.node' ], + outFormat : [ 'structure' ], + feature : cborSupported, + + onEncode : function( op ) + { + + if( !Cbor ) + Cbor = require( CborPath ); + + _.assert( _.bufferAnyIs( op.in.data ), 'Expects buffer' ); + op.in.data = _.bufferNodeFrom( op.in.data ); + op.out.data = Cbor.decodeFirstSync( op.in.data, { bigint : true } ); + op.out.format = 'structure'; + }, + +} + +// + +let writeCbor = null; +if( CborPath ) +writeCbor = +{ + + ext : [ 'cbor' ], + inFormat : [ 'structure' ], + outFormat : [ 'buffer.node' ], + feature : cborSupported, + + onEncode : function( op ) + { + + if( !Cbor ) + Cbor = require( CborPath ); + + _.assert( _.mapIs( op.in.data ) ); + + let encoder = new Cbor.Encoder({ highWaterMark : 1 << 30 }); + encoder.write( op.in.data ); + op.out.data = encoder.read(); + + _.assert( _.bufferNodeIs( op.out.data ) ); + + op.out.format = 'buffer.node'; + }, + +} + +// -- +// declare +// -- + +var Extension = +{ +} + +/* _.props.extend */Object.assign( _.encode, Extension ); + +// -- +// register +// -- + +_.Gdf([ readCbor, writeCbor ]); + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy/Cbor.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Cbor_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Cbor_s */ })(); + +/* */ /* begin of file Coffee_s */ ( function Coffee_s() { function Coffee_s_naked() { ( function _Coffee_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.encode = _.encode || Object.create( null ); + +// -- +// coffee +// -- + +let Coffee, CoffeePath; +try +{ + CoffeePath = require.resolve( 'coffeescript' ); +} +catch( err ) +{ +} + +let csonSupported = +{ + primitive : 1, + regexp : 2, + buffer : 3, + structure : 2 +} + +let readCoffee = null; +if( CoffeePath ) +readCoffee = +{ + + ext : [ 'coffee', 'cson' ], + inFormat : [ 'string.utf8' ], + outFormat : [ 'structure' ], + + feature : csonSupported, + + onEncode : function( op ) + { + let o = Object.create( null ); + + if( !Coffee ) + Coffee = require( CoffeePath ); + + if( op.filePath ) + o.filename = _.fileProvider.path.nativize( op.filePath ) + + op.out.data = Coffee.eval( op.in.data, o ); + op.out.format = 'structure'; + }, + +} + +// + +let Js2coffee, Js2coffeePath; +try +{ + Js2coffeePath = require.resolve( 'js2coffee' ); +} +catch( err ) +{ +} + +let writeCoffee = null; +if( Js2coffeePath ) +writeCoffee = +{ + + ext : [ 'coffee', 'cson' ], + inFormat : [ 'structure' ], + outFormat : [ 'string.utf8' ], + + feature : csonSupported, + + onEncode : function( op ) + { + + if( !Js2coffee ) + Js2coffee = require( Js2coffeePath ); + + let data = _.entity.exportString( op.in.data, { jsLike : 1, keyWrapper : '', stringWrapper : `'` } ); + if( _.mapIs( op.in.data ) ) + data = '(' + data + ')'; + op.out.data = Js2coffee( data ); + }, + +} + +// -- +// declare +// -- + +var Extension = +{ + +} + +/* _.props.extend */Object.assign( _.encode, Extension ); + +// -- +// register +// -- + +_.Gdf([ readCoffee, writeCoffee ]); + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy/Coffee.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Coffee_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Coffee_s */ })(); + +/* */ /* begin of file Json_s */ ( function Json_s() { function Json_s_naked() { ( function _Json_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.encode = _.encode || Object.create( null ); + +// -- +// json +// -- + +let jsonSupported = +{ + primitive : 1, + regexp : 0, + buffer : 0, + structure : 2 +} + +let readJson = +{ + + ext : [ 'json' ], + inFormat : [ 'string.utf8' ], + outFormat : [ 'structure' ], + + feature : _.props.extend( null, jsonSupported, { default : 1 } ), + + onEncode : function( op ) + { + + /* + +qqq : could throw different errors +cover them please + +SyntaxError: Unexpected end of JSON input + at JSON.parse (:null:null) + at wGenericDataFormatConverter.onEncode (C:\pro\web\Dave\git\trunk\builder\include\wtools\abase\l8\GdfFormats.s:59:26) + at wGenericDataFormatConverter.encode_body (C:\pro\web\Dave\git\trunk\builder\include\wtools\abase\l8\Converter.s:238:13) + at Proxy.encode_body (C:\pro\web\Dave\git\trunk\builder\include\wtools\abase\l8\GdfCurrent.s:59:45) + +*/ + try + { + op.out.data = JSON.parse( op.in.data ); + } + catch( err ) + { + let src = op.in.data; + let position = /at position (\d+)/.exec( err.message ); + if( position ) + position = Number( position[ 1 ] ); + let first = 0; + if( _.numberDefined( position ) && position >= 0 ) + { + let nearest = _.strLinesNearest( src, position ); + first = _.strLinesCount( src.substring( 0, nearest.spans[ 0 ] ) ); + src = nearest.splits.join( '' ); + } + let err2 = _.err( 'Error parsing JSON\n', err, '\n', _.strLinesNumber( src, first ) ); + throw err2; + } + + // op.out.data = _.jsonParse( op.in.data ); + op.out.format = 'structure'; + + }, + +} + +// + +let writeJsonMin = +{ + // default : 1, + ext : [ 'json.min', 'json' ], + shortName : 'json.min', + inFormat : [ 'structure' ], + outFormat : [ 'string.utf8' ], + feature : _.props.extend( null, jsonSupported, { default : 1, fine : 0, min : 1 } ), + + onEncode : function( op ) + { + op.out.data = JSON.stringify( op.in.data ); + op.out.format = 'string.utf8'; + } + +} + +// + +let writeJsonFine = +{ + + shortName : 'json.fine', + ext : [ 'json.fine', 'json' ], + inFormat : [ 'structure' ], + outFormat : [ 'string.utf8' ], + feature : _.props.extend( null, jsonSupported, { default : 0, fine : 1, min : 0 } ), + + onEncode : function( op ) + { + op.out.data = _.cloneData({ src : op.in.data }); + op.out.data = _.entity.exportJson( op.out.data, { cloning : 0 } ); + op.out.format = 'string.utf8'; + } + +} + +// -- +// declare +// -- + +var Extension = +{ + +} + +Object.assign( _.encode, Extension ); + +// -- +// register +// -- + +_.Gdf([ readJson, writeJsonMin, writeJsonFine ]); + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy/Json.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Json_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Json_s */ })(); + +/* */ /* begin of file JsStructure_s */ ( function JsStructure_s() { function JsStructure_s_naked() { ( function _JsStructure_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.encode = _.encode || Object.create( null ); + +// -- +// js +// -- + +// let ProcessBasic; +let IntrospectorBasic; +try +{ + // ProcessBasic = _.include( 'wProcess' ); + IntrospectorBasic = _.include( 'wIntrospectorBasic' ); +} +catch( err ) +{ +} + +let jsSupported = +{ + primitive : 3, + regexp : 2, + buffer : 3, + structure : 2 +} + +let readJsStructure = null; +if( IntrospectorBasic ) +readJsStructure = +{ + + // forConfig : 0, + ext : [ 'js.structure', 'js', 's', 'ss', 'jstruct', 'jslike' ], + inFormat : [ 'string.utf8' ], + outFormat : [ 'structure' ], + + feature : jsSupported, + + // onEncode : function( op ) + // { + // op.out.format = 'string.utf8'; + // }, + + onEncode : function( op ) + { + // _.assert( _.strDefined( op.filePath ) ); + op.out.data = _.exec({ code : op.in.data, filePath : op.filePath, prependingReturn : 1 }); /* yyy */ + // op.out.data = _.exec({ code : op.in.data, filePath : op.filePath, prependingReturn : 0 }); + op.out.format = 'structure'; + }, + +} + +// + +// let readJsNode = +// { +// +// forConfig : 0, +// ext : [ 'js', 's', 'ss', 'jstruct', 'jslike' ], +// inFormat : [ 'string.utf8' ], +// outFormat : [ 'structure' ], +// +// onEncode : function( op ) +// { +// op.out.data = require( _.fileProvider.path.nativize( op.filePath ) ); +// op.out.format = 'structure'; +// }, +// +// } +// +// // +// +// let readJsSmart = +// { +// +// ext : [ 'js', 's', 'ss', 'jstruct', 'jslike' ], +// inFormat : [ 'string.utf8' ], +// outFormat : [ 'structure' ], +// +// onEncode : function( op ) +// { +// +// // qqq +// // if( typeof process !== 'undefined' && typeof require !== 'undefined' ) +// // if( _.FileProvider.HardDrive && op.provider instanceof _.FileProvider.HardDrive ) +// // { +// // op.out.data = require( _.fileProvider.path.nativize( op.filePath ) ); +// // op.out.format = 'structure'; +// // return; +// // } +// +// op.out.data = _.exec +// ({ +// code : op.in.data, +// filePath : op.filePath, +// prependingReturn : 1, +// }); +// +// op.out.format = 'structure'; +// +// }, +// +// } + +// + +let writeJsStructure = +{ + + ext : [ 'js.structure', 'js', 's', 'ss', 'jstruct', 'jslike' ], + inFormat : [ 'structure' ], + outFormat : [ 'string.utf8' ], + + feature : jsSupported, + + onEncode : function( op ) + { + op.out.data = _.entity.exportJs( op.in.data ); + op.out.format = 'string.utf8'; + } + +} + +// + +let writeJsStructureExported = +{ + + shortName : 'js.structure.exported', + ext : [], + inFormat : [ 'structure' ], + outFormat : [ 'string.utf8' ], + feature : jsSupported, + + onEncode : function( op ) + { + op.out.data = `module.exports = ` + _.entity.exportJs( op.in.data ); + op.out.format = 'string.utf8'; + } + +} + +// -- +// declare +// -- + +var Extension = +{ + +} + +Object.assign( _.encode, Extension ); + +// -- +// register +// -- + +_.Gdf([ readJsStructure, writeJsStructure, writeJsStructureExported ]); + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy/JsStructure.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, JsStructure_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file JsStructure_s */ })(); + +/* */ /* begin of file MsgpackLite_s */ ( function MsgpackLite_s() { function MsgpackLite_s_naked() { ( function _MsgpackLite_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.encode = _.encode || Object.create( null ); + +// -- +// Msgpack-lite +// -- + +let MsgpackLite, MsgpackLitePath; +try +{ + MsgpackLitePath = require.resolve( 'msgpack-lite' ); +} +catch( err ) +{ +} + +let msgpackLiteSupported = +{ + primitive : 2, + regexp : 2, + buffer : 3, + structure : 2 +} + +let readMsgpackLite = null; +if( MsgpackLitePath ) +readMsgpackLite = +{ + + ext : [ 'msgpack.lite' ], + inFormat : [ 'buffer.node' ], + outFormat : [ 'structure' ], + feature : msgpackLiteSupported, + + onEncode : function( op ) + { + + if( !MsgpackLite ) + MsgpackLite = require( MsgpackLitePath ); + + _.assert( _.bufferAnyIs( op.in.data ), 'Expects buffer' ); + op.in.data = _.bufferNodeFrom( op.in.data ); + op.out.data = MsgpackLite.decode( op.in.data ); + op.out.format = 'structure'; + }, + +} + +let writeMsgpackLite = null; +if( MsgpackLitePath ) +writeMsgpackLite = +{ + + ext : [ 'msgpack.lite' ], + inFormat : [ 'structure' ], + outFormat : [ 'buffer.node' ], + feature : msgpackLiteSupported, + + onEncode : function( op ) + { + + if( !MsgpackLite ) + MsgpackLite = require( MsgpackLitePath ); + + _.assert( _.mapIs( op.in.data ) ); + op.out.data = MsgpackLite.encode( op.in.data ); + op.out.format = 'buffer.node'; + }, + +} + +// -- +// Msgpack-wtp +// -- + +// let MsgpackWtp, MsgpackWtpPath; +// try +// { +// MsgpackWtpPath = require.resolve( 'what-the-pack' ); +// } +// catch( err ) +// { +// } + +// let readMsgpackWtp = null; +// if( MsgpackWtpPath ) +// readMsgpackWtp = +// { + +// ext : [ 'msgpack.wtp' ], +// inFormat : [ 'buffer.node' ], +// outFormat : [ 'structure' ], + +// onEncode : function( op ) +// { +// _.assert( _.bufferAnyIs( op.in.data ), 'Expects buffer' ); + +// if( !MsgpackWtp ) +// { +// MsgpackWtp = require( MsgpackLitePath ); +// // if( !MsgpackWtp.decode ) +// MsgpackWtp = MsgpackWtp.initialize( 2**27 ); //134 MB +// } + +// op.out.data = MsgpackWtp.decode( op.in.data ); +// op.out.format = 'structure'; +// }, + +// } + +// let writeMsgpackWtp = null; +// if( MsgpackWtpPath ) +// writeMsgpackWtp = +// { + +// ext : [ 'msgpack.wtp' ], +// inFormat : [ 'structure' ], +// outFormat : [ 'buffer.node' ], + +// onEncode : function( op ) +// { +// _.assert( _.mapIs( op.in.data ) ); + +// if( !MsgpackWtp ) +// { +// MsgpackWtp = require( MsgpackLitePath ); +// MsgpackWtp = MsgpackWtp.initialize( 2**27 ); //134 MB +// } + +// // if( !MsgpackWtp.encode ) +// // MsgpackWtp = MsgpackWtp.initialize( 2**27 ); //134 MB + +// op.out.data = MsgpackWtp.encode( op.in.data ); +// op.out.format = 'buffer.node'; +// }, + +// } + +// -- +// declare +// -- + +var Extension = +{ + readMsgpackLite, + writeMsgpackLite +} + +/* _.props.extend */Object.assign( _.encode, Extension ); + +// -- +// register +// -- + +_.Gdf([ readMsgpackLite, writeMsgpackLite ]); + +// _.Gdf([ readMsgpackLite, writeMsgpackLite, readMsgpackWtp, writeMsgpackWtp ]); + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy/MsgpackLite.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, MsgpackLite_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file MsgpackLite_s */ })(); + +/* */ /* begin of file Yml_s */ ( function Yml_s() { function Yml_s_naked() { ( function _Yml_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.encode = _.encode || Object.create( null ); + +// -- +// yaml +// -- + +let Yaml, YamlPath; +try +{ + YamlPath = require.resolve( 'js-yaml' ); +} +catch( err ) +{ +} + +let ymlSupported = +{ + primitive : 2, + regexp : 2, + buffer : 1, + structure : 3 +} + +let readYml = null; +if( YamlPath ) +readYml = +{ + + ext : [ 'yaml', 'yml' ], + inFormat : [ 'string.utf8' ], + outFormat : [ 'structure' ], + + feature : ymlSupported, + + onEncode : function( op ) + { + let o = Object.create( null ); + + if( !Yaml ) + Yaml = require( YamlPath ); + + if( op.filePath ) + o.filename = _.fileProvider.path.nativize( op.filePath ) + + op.out.data = Yaml.load( op.in.data, o ); + op.out.format = 'structure'; + }, + +} + +/* qqq xxx : uncomment when js-yaml will be updated to v4.0.0 or higher */ +// readYml = +// { +// +// ext : [ 'yaml', 'yml' ], +// inFormat : [ 'string.utf8' ], +// outFormat : [ 'structure' ], +// +// feature : ymlSupported, +// +// onEncode : function( op ) +// { +// const o = Object.create( null ); +// +// if( !Yaml ) +// { +// Yaml = require( YamlPath ); +// const schemaUnsafe = require( 'js-yaml-js-types' ).all; +// Yaml.userUnsafeSchema = Yaml.DEFAULT_SCHEMA.extend( schemaUnsafe ); +// } +// +// o.schema = Yaml.userUnsafeSchema; +// +// if( op.filePath ) +// o.filename = _.fileProvider.path.nativize( op.filePath ); +// +// op.out.data = Yaml.load( op.in.data, o ); +// op.out.format = 'structure'; +// }, +// +// } + +let writeYml = null; +if( YamlPath ) +writeYml = +{ + + ext : [ 'yaml', 'yml' ], + inFormat : [ 'structure' ], + outFormat : [ 'string.utf8' ], + + feature : ymlSupported, + + onEncode : function( op ) + { + + if( !Yaml ) + Yaml = require( YamlPath ); + + op.out.data = Yaml.dump( op.in.data ); + op.out.format = 'string.utf8'; + }, + +} + +/* qqq xxx : uncomment when js-yaml will be updated to v4.0.0 or higher */ +// writeYml = +// { +// +// ext : [ 'yaml', 'yml' ], +// inFormat : [ 'structure' ], +// outFormat : [ 'string.utf8' ], +// +// feature : ymlSupported, +// +// onEncode : function( op ) +// { +// +// if( !Yaml ) +// { +// Yaml = require( YamlPath ); +// const schemaUnsafe = require( 'js-yaml-js-types' ).all; +// Yaml.userUnsafeSchema = Yaml.DEFAULT_SCHEMA.extend( schemaUnsafe ); +// } +// +// op.out.data = Yaml.dump( op.in.data, { schema : Yaml.userUnsafeSchema } ); +// op.out.format = 'string.utf8'; +// }, +// +// } + +// -- +// declare +// -- + +var Extension = +{ + +} + +Object.assign( _.encode, Extension ); + +// -- +// register +// -- + +_.Gdf([ readYml, writeYml ]); +_.assert( Config.interpreter === 'browser' || _.longHas( _.gdf.outMap[ 'structure' ].map( ( e ) => e.shortName ), 'yaml' ) ); + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy/Yml.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgdf/proto/wtools/amid/l1/gdf/l5_strategy' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Yml_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Yml_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgitpath/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgitpath/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wgitpath */ ( function wgitpath() { function wgitpath_naked() { +module.exports = require( '../wtools/amid/l3/git/entry/GitPath.ss' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wGitPath', 'wgitpath' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgitpath/proto/node_modules/wgitpath' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgitpath/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wgitpath_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wgitpath */ })(); + +/* */ /* begin of file GitPath_ss */ ( function GitPath_ss() { function GitPath_ss_naked() { ( function _GitTools_ss_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to operate over git paths reliably and consistently. GitPath leverages parsing, normalizing, nativizing git paths. Use the module to get uniform experience from playing with paths on different platforms. + * @module Tools/mid/GitPath +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../include/GitPathMid.ss' ); + module[ 'exports' ] = _global_.wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgitpath/proto/wtools/amid/l3/git/entry/GitPath.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgitpath/proto/wtools/amid/l3/git/entry' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, GitPath_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file GitPath_ss */ })(); + +/* */ /* begin of file GitPathBasic_ss */ ( function GitPathBasic_ss() { function GitPathBasic_ss_naked() { ( function _Base_s_() +{ + +'use strict'; + +/* GitPath */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../../node_modules/Tools' ); + + _.include( 'wUriBasic' ); + _.include( 'wStringsExtra' ); + _.include( 'wFilesBasic' ); + + module[ 'exports' ] = _global_.wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgitpath/proto/wtools/amid/l3/git/include/GitPathBasic.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgitpath/proto/wtools/amid/l3/git/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, GitPathBasic_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file GitPathBasic_ss */ })(); + +/* */ /* begin of file GitPathMid_ss */ ( function GitPathMid_ss() { function GitPathMid_ss_naked() { ( function _Mid_s_() +{ + +'use strict'; + +/* GitPath */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../../node_modules/Tools' ); + + require( './GitPathBasic.ss' ); + require( '../l0/Path.ss' ); + + module[ 'exports' ] = _global_.wTools; +} + +})(); + + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgitpath/proto/wtools/amid/l3/git/include/GitPathMid.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgitpath/proto/wtools/amid/l3/git/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, GitPathMid_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file GitPathMid_ss */ })(); + +/* */ /* begin of file Path_ss */ ( function Path_ss() { function Path_ss_naked() { ( function _Path_ss_() +{ + +'use strict'; + +const _ = _global_.wTools; +const Parent = _.uri; +_.git = _.git || Object.create( null ); +_.git.path = _.git.path || Object.create( Parent ); + +// -- +// +// -- + +/** + * Routine parse() parse string path into components. + * Routine supports three modes of parsing : full, atomic, objects. + * By default mode `full` is used. + * + * @example + * var srcPath = 'git+https:///github.com/user.repo.git/!alpha'; + * _.git.path.parse( srcPath ); + * // returns + * // { + * // protocol : 'git+https', + * // longPath : '/github.com/user/repo.git/', + * // tag : 'alpha', + * // localVcsPath : './', + * // protocols : [ 'git', 'https' ], + * // isFixated : false, + * // service : 'github.com', + * // user : 'user', + * // repo : 'repo', + * // }; + * + * @example + * var srcPath = 'git+https:///github.com/user.repo.git/!alpha'; + * _.git.path.parse({ remotePath : srcPath, full : 0, atomic : 1 }); + * // returns + * // { + * // protocol : 'git+https', + * // tag : 'alpha', + * // localVcsPath : './', + * // service : 'github.com', + * // user : 'user', + * // repo : 'repo', + * // isGlobal : true, + * // }; + * + * @example + * var srcPath = 'git+https:///github.com/user.repo.git/!alpha'; + * _.git.path.parse({ remotePath : srcPath, full : 0, atomic : 0, objects : 1 }); + * // returns + * // { + * // service : 'github.com', + * // user : 'user', + * // repo : 'repo', + * // }; + * + * First parameter set : + * @param { String } remotePath - String path. + * Second parameter set : + * @param { Aux } o - Options map. + * @param { String|Aux } o.remotePath - Path to parse. + * @param { BoolLike } o.full - Enables full parsing. Default is 1. + * @param { BoolLike } o.full - Enables atomic parsing. Default is 0. + * @param { BoolLike } o.objects - Enables parsing of objects. Default is 1. + * @returns { Map } - Returns map with parsed path. + * @throws { Error } If arguments.length is not equal to 1. + * @throws { Error } If {-remotePath-} has incompatible type. + * @throws { Error } If options map {-o-} has incompatible type. + * @throws { Error } If options map {-o-} has unknown option. + * @throws { Error } If options map {-o-} has conflicting options or no options for parsing. + * @throws { Error } If {-remotePath-} has tag and version simultaneously. + * @function parse + * @module Tools/GitTools + * @namespace Tools.git.path + */ + +function parse_head( routine, args ) +{ + let o = args[ 0 ]; + + _.assert( args.length === 1, 'Expects single options map {-o-}' ); + + if( _.strIs( o ) ) + o = { remotePath : o }; + + _.routine.options_( parse, o ); + _.assert( _.strIs( o.remotePath ) || _.mapIs( o.remotePath ), 'Expects file path {-o.remotePath-}' ); + _.assert + ( + ( !o.full || !o.atomic ) + || ( !o.full && !o.atomic ), + 'Expects only full parsing with {-o.full-} or atomic parsing with {-o.atomic-} but not both' + ); + + return o; +} + +// + +function parse_body( o ) +{ + if( _.mapIs( o.remotePath ) ) + return o.remotePath; + + + let result = pathParse( o.remotePath, o.full ); + let objects = objectsParse( result.longPath, result.protocol ); + + result = _.props.extend( result, objects ); + + if( o.full ) + return result; + else if( o.atomic ) + return pathAtomicMake( result ); + else if( o.objects ) + return objects; + else + throw _.err( 'Routine should return some parsed path, but options set to return nothing' ) + + /* */ + + function pathParse( remotePath, full ) + { + let result = Object.create( null ); + + let parsed1 = _.uri.parseConsecutive( remotePath ); + _.props.extend( result, parsed1 ); + + if( !result.tag && !result.hash ) + result.tag = 'master'; + + _.assert( !result.tag || !result.hash, 'Remote path:', _.strQuote( remotePath ), 'should contain only hash or tag, but not both.' ) + + let isolated = pathIsolateGlobalAndLocal( parsed1 ); + result.longPath = isolated.globalPath; + result.localVcsPath = isolated.localPath; + + if( !full ) + return result; + + /* remoteVcsPath */ + + let parsed2 = Object.create( null ); + result.protocols = parsed2.protocols = parsed1.protocol ? parsed1.protocol.split( '+' ) : []; + + // let isHardDrive = _.longHasAny( result.protocols, [ 'hd' ] ); + // + // parsed2.longPath = isolated.globalPath; + // if( !isHardDrive ) + // parsed2.longPath = _.strRemoveBegin( parsed2.longPath, '/' ); + // parsed2.longPath = _.strRemoveEnd( parsed2.longPath, '/' ); + // + // let protocols = _.longSlice( parsed2.protocols ); + // parsed2.protocols = _.arrayRemovedArrayOnce( protocols, [ 'git', 'hd' ] ); + // result.remoteVcsPath = _.uri.str( parsed2 ); + // + // if( isHardDrive ) + // result.remoteVcsPath = _.fileProvider.path.nativize( result.remoteVcsPath ); + // + // /* remoteVcsLongerPath */ + // + // let parsed3 = Object.create( null ); + // parsed3.longPath = parsed2.longPath; + // parsed3.protocols = protocols; + // result.remoteVcsLongerPath = _.uri.str( parsed3 ); + // + // if( isHardDrive ) + // result.remoteVcsLongerPath = _.fileProvider.path.nativize( result.remoteVcsLongerPath ); + + /* */ + + result.isFixated = _.git.path.isFixated( result ); + + _.assert( !_.boolLike( result.hash ) ); + + return result; + } + + /* */ + + function pathIsolateGlobalAndLocal( parsedPath ) + { + let splits = _.strIsolateLeftOrAll( parsedPath.longPath, '.git/' ); + if( parsedPath.query ) + { + let query = _.strStructureParse + ({ + src : parsedPath.query, + keyValDelimeter : '=', + entryDelimeter : '&' + }); + if( query.out ) + splits[ 2 ] = _.uri.join( splits[ 2 ], query.out ); + } + let globalPath = splits[ 0 ] + ( splits[ 1 ] || '' ); + let localPath = _.strRemoveBegin( splits[ 2 ], _.uri.rootToken ) || './'; + return { globalPath, localPath }; + } + + /* */ + + function objectsParse( remotePath, protocol ) + { + let objects = Object.create( null ); + let objectsRegexp; + if( protocol && ( _.strHas( protocol, 'http' ) || _.strHas( protocol, 'ssh' ) ) ) + objectsRegexp = /([a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+)\/([a-zA-Z0-9-_.]+)\/([a-zA-Z0-9-_.]+)/; + else if( protocol === undefined || _.strHas( protocol, 'git' ) ) + objectsRegexp = /([a-zA-Z0-9-_.]+\.[a-zA-Z0-9-_.]+):([a-zA-Z0-9-_.]+)\/([a-zA-Z0-9-_.]+)/ + else + return objects; + + let match = remotePath.match( objectsRegexp ); + if( match ) + { + objects.service = match[ 1 ]; + objects.user = match[ 2 ]; + objects.repo = _.strRemoveEnd( match[ 3 ], '.git' ); + } + + return objects; + } + + /* */ + + function pathAtomicMake( parsedPath ) + { + if( parsedPath.protocol && _.strHas( parsedPath.protocol, 'hd' ) ) + return parsedPath; + + const butMap = { longPath : null }; + if( _.strBegins( parsedPath.longPath, '/' ) ) + parsedPath.isGlobal = true; + return _.mapBut_( parsedPath, parsedPath, butMap ); + } +} + +parse_body.defaults = +{ + remotePath : null, + full : 1, + atomic : 0, + objects : 1, +}; + +// + +let parse = _.routine.uniteCloning_replaceByUnite( parse_head, parse_body ); + +// + +/** + * Routine str() assembles path string from components. + * + * @example + * let parsed = + * { + * protocol : 'git+https', + * tag : 'alpha', + * localVcsPath : './', + * service : 'github.com', + * user : 'user', + * repo : 'repo', + * isGlobal : true, + * }; + * _.git.path.str( parsed ); + * // returns : 'git+https:///github.com/user.repo.git!alpha' + * + * @param { Aux|String } srcPath - Map with parsed path components. + * @returns { String } - Returns path string. + * @throws { Error } If arguments.length is not equal to 1. + * @throws { Error } If {-srcPath-} has incompatible type. + * @function str + * @module Tools/GitTools + * @namespace Tools.git.path + */ + +function str( srcPath ) +{ + _.assert( arguments.length === 1, 'Expects single argument {-srcPath-}' ); + + if( _.strIs( srcPath ) ) + return srcPath; + + _.assert( _.mapIs( srcPath ), 'Expects map with parsed path to construct string' ); + + let result = ''; + let isParsedAtomic = srcPath.isFixated === undefined && srcPath.protocols === undefined; + + // if( isParsedAtomic && srcPath.protocol === undefined && srcPath.localVcsPath === undefined ) + // throw _.err( 'Cannot create path from objects. Not enough information about protocols' ); + + if( srcPath.protocol ) + result += srcPath.protocol + '://'; + if( srcPath.longPath ) + result += srcPath.longPath; + + if( isParsedAtomic ) + { + if( srcPath.protocol && srcPath.protocol !== 'git' && !_.strHas( srcPath.protocol, 'ssh' ) ) + { + if( srcPath.service ) + result += srcPath.isGlobal ? '/' + srcPath.service : srcPath.service; + if( srcPath.user ) + result = _.uri.join( result, srcPath.user ); + } + else + { + let prefix = srcPath.isGlobal ? '/' : '' + let postfix = ( srcPath.protocol && _.strHas( srcPath.protocol, 'ssh' ) ) ? '/' : ':' + if( srcPath.service ) + result += `${ prefix }git@${ srcPath.service }${ postfix }`; + if( srcPath.user ) + result += srcPath.user; + } + + if( srcPath.repo ) + result = _.uri.join( result, `${ srcPath.repo }.git` ); + } + + if( srcPath.localVcsPath && srcPath.localVcsPath !== './' ) + if( srcPath.query === undefined ) + result += ( _.strEnds( result, '/' ) ? '' : '/' ) + srcPath.localVcsPath; + if( srcPath.query ) + result += _.uri.queryToken + srcPath.query; + if( srcPath.tag ) + result += srcPath.tag === 'master' ? '' : _.uri.tagToken + srcPath.tag; + if( srcPath.hash ) + result += _.uri.hashToken + srcPath.hash; + + return result; +} + +// + +/** + * Routine normalize() transform provided string path {-srcPath-} to normalized form. + * Normalized form is global git path with protocols included part `git`. + * For remote path it looks like: + * git[+protocol]:///[service]/[user]/[repo]/[query][tag|hash] + * + * @example + * _.git.path.normalize( 'https://github.com/user.repo.git/!alpha' ); + * // returns : 'git+https:///github.com/user.repo.git/!alpha' + * + * @param { String } srcPath - Path to normalize. + * @returns { String } - Returns normalized path. + * @throws { Error } If arguments.length is not equal to 1. + * @throws { Error } If {-srcPath-} has incompatible type. + * @function normalize + * @module Tools/GitTools + * @namespace Tools.git.path + */ + +function normalize( srcPath ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.strIs( srcPath ), 'Expects string path {-srcPath-}' ); + + let parsed = _.git.path.parse( srcPath ); + + _.assert( !!parsed.longPath ); + + if( parsed.protocol ) + { + let match = parsed.protocol.match( /(\w+)$/ ); + let postfix = match[ 0 ] === 'git' ? `` : `+${ match[ 0 ] }`; + parsed.protocol = `git` + postfix; + } + else + { + if( _.strHas( parsed.longPath, 'git@' ) ) + parsed.protocol = 'git'; + else + parsed.protocol = 'git+hd'; + } + + parsed.longPath = _.uri.join( _.uri.rootToken, parsed.longPath ); + parsed.longPath = _.uri.normalize( parsed.longPath ); + return _.git.path.str( parsed ); +} + +// // +// +// function remotePathNormalize( remotePath ) +// { +// if( remotePath === null ) +// return remotePath; +// +// remotePath = remotePath.replace( /^(\w+):\/\//, 'git+$1://' ); +// remotePath = remotePath.replace( /:\/\/\b/, ':///' ); +// +// return remotePath; +// } + +// + +/** + * Routine nativize() transform provided string path {-srcPath-} to nativized for utility Git form. + * For remote path it looks like: + * [protocol]://[service]/[user]/[repo] + * + * @example + * _.git.path.nativize( 'git+https:///github.com/user.repo.git/!alpha' ); + * // returns : 'https://github.com/user.repo.git' + * + * @param { String } srcPath - Path to nativize. + * @returns { String } - Returns nativized path. + * @throws { Error } If arguments.length is not equal to 1. + * @throws { Error } If {-srcPath-} has incompatible type. + * @function nativize + * @module Tools/GitTools + * @namespace Tools.git.path + */ + +function nativize( srcPath ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.strIs( srcPath ), 'Expects string path {-srcPath-}' ); + + let parsed = _.git.path.parse( srcPath ); + + _.assert( !!parsed.longPath ); + + if( parsed.protocol ) + parsed.protocol = parsed.protocol.replace( /^git\+(\w+)/, '$1' ); + if( !parsed.protocol || parsed.protocol === 'git' ) + parsed.protocol = ''; + if( _.longHas( _.fileProvider.protocols, parsed.protocol ) ) + parsed.protocol = ''; + // parsed.protocol = 'git'; + + parsed.longPath = _.uri.normalize( parsed.longPath ); + + if( _.longHasAny( parsed.protocols, _.fileProvider.protocols ) ) + { + parsed.longPath = _.uri.nativize( parsed.longPath ); + if( parsed.query ) + parsed.query = _.uri.nativize( parsed.query ); + } + else + { + parsed.longPath = _.strRemoveBegin( parsed.longPath, '/' ); + } + + return _.git.path.str( parsed ); +} + +// // +// +// function remotePathNativize( remotePath ) +// { +// if( remotePath === null ) +// return remotePath; +// +// remotePath = remotePath.replace( /^git\+(\w+):\/\//, '$1://' ); +// remotePath = remotePath.replace( /:\/\/\/\b/, '://' ); +// +// return remotePath; +// } + +// + +/** + * Routine refine() transform provided string path {-srcPath-}. + * Routine refines up tokens in path. + * Works on local hard drive path. + * + * @example + * _.git.path.refine( 'hd:\\some\local\repo' ); + * // returns : 'hd://some/local/repo' + * + * @param { String } srcPath - Path to refine. + * @returns { String } - Returns refined path. + * @throws { Error } If arguments.length is not equal to 1. + * @throws { Error } If {-srcPath-} has incompatible type. + * @function refine + * @module Tools/GitTools + * @namespace Tools.git.path + */ + +function refine( srcPath ) +{ + _.assert( arguments.length === 1, 'Expects single path {-srcPath-}' ); + _.assert( _.strIs( srcPath ), 'Expects string path {-srcPath-}' ); + + let parsed = _.git.path.parse( srcPath ); + parsed.longPath = _.path.refine( parsed.longPath ); + return _.git.path.str( parsed ); +} + +// + +/** + * Routine isFixated() checks that provided string path {-srcPath-} has a valid version ( hash ). + * + * @example + * _.git.path.isFixated( 'git+https:///github.com/user.repo.git' ); + * // returns : false + * + * @example + * _.git.path.isFixated( 'git+https:///github.com/user.repo.git/!alpha' ); + * // returns : false + * + * @example + * _.git.path.isFixated( 'git+https:///github.com/user.repo.git/#ab6h2c8' ); + * // returns : true + * + * @param { String|Aux } srcPath - Path to check. + * @returns { Boolean } - Returns true if path has valid version, otherwise, returns false. + * @throws { Error } If {-srcPath-} has incompatible type. + * @function isFixated + * @module Tools/GitTools + * @namespace Tools.git.path + */ + +function isFixated( srcPath ) +{ + let parsed = _.git.path.parse({ remotePath : srcPath, full : 0, atomic : 1 }); + + if( !parsed.hash ) + return false; + + if( parsed.hash.length < 7 ) + return false; + + if( !/[0-9a-f]+/.test( parsed.hash ) ) + return false; + + return true; +} + +// + +/** + * Routine fixate() changes hash in provided path {-o.remotePath-} to hash of latest available commit. + * + * @example + * _.git.path.fixate( 'git+https:///github.com/user.repo.git' ); + * // returns : 'git+https://github.com/user.repo.git#abc6e1da8be34f69d24af6f90f323816a9d83f3b' + * + * First parameter set : + * @param { String } srcPath - Path to fixate. + * Second parameter set : + * @param { Aux } o - Options map. + * @param { String|Aux } o.srcPath - Path to fixate. + * @param { Number } o.logger - Level of verbosity. + * @returns { String } - Returns fixated path. + * @throws { Error } If arguments.length is not equal to 1. + * @throws { Error } If {-srcPath-} has incompatible type. + * @throws { Error } If options map {-o-} has incompatible type. + * @throws { Error } If options map {-o-} has unknown option. + * @function fixate + * @module Tools/GitTools + * @namespace Tools.git.path + */ + +function fixate( o ) +{ + + if( !_.mapIs( o ) ) + o = { remotePath : o } + _.routine.options_( fixate, o ); + // o = { remotePath : o }; + // _.routineOptions( fixate, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + let parsed = _.git.path.parse({ remotePath : o.remotePath }); + let latestVersion = _.git.remoteVersionLatest + ({ + remotePath : o.remotePath, + logger : o.logger, + }); + + let result = _.git.path.str + ({ + protocol : parsed.protocol, + longPath : parsed.longPath, + hash : latestVersion, + }); + + return result; +} + +var defaults = fixate.defaults = Object.create( null ); +defaults.remotePath = null; +defaults.logger = 0; + +// -- +// declare +// -- + +let Extension = +{ + + parse, + + str, + + normalize, + nativize, + refine, + + isFixated, + fixate, + +} + +/* _.props.extend */Object.assign( _.git.path, Extension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgitpath/proto/wtools/amid/l3/git/l0/Path.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgitpath/proto/wtools/amid/l3/git/l0' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Path_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Path_ss */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgittools/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgittools/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wgittools */ ( function wgittools() { function wgittools_naked() { +module.exports = require( '../wtools/amid/l3/git/entry/GitTools.ss' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wGitTools', 'wgittools' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgittools/proto/node_modules/wgittools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgittools/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wgittools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wgittools */ })(); + +/* */ /* begin of file GitTools_ss */ ( function GitTools_ss() { function GitTools_ss_naked() { ( function _GitTools_ss_() +{ + +'use strict'; + +/** + * Collection of tools to use git programmatically. + @module Tools/mid/GitTools +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../include/Mid.ss' ); + module[ 'exports' ] = _global_.wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgittools/proto/wtools/amid/l3/git/entry/GitTools.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgittools/proto/wtools/amid/l3/git/entry' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, GitTools_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file GitTools_ss */ })(); + +/* */ /* begin of file Basic_ss */ ( function Basic_ss() { function Basic_ss_naked() { ( function _Base_s_() +{ + +'use strict'; + +/* GitTools */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../../node_modules/Tools' ); + + _.include( 'wCopyable' ); + _.include( 'wIntrospectorExtra' ); + _.include( 'wProcess' ); + _.include( 'wFilesBasic' ); + _.include( 'wRemote' ); + _.include( 'wRepoBasic' ); + _.include( 'wGitPath' ); + _.include( 'wUnit' ); + + module[ 'exports' ] = _global_.wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgittools/proto/wtools/amid/l3/git/include/Basic.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgittools/proto/wtools/amid/l3/git/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Basic_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Basic_ss */ })(); + +/* */ /* begin of file Mid_ss */ ( function Mid_ss() { function Mid_ss_naked() { ( function _Mid_s_() +{ + +'use strict'; + +/* GitTools */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../../node_modules/Tools' ); + + require( './Basic.ss' ); + require( '../l1/Git.ss' ); + require( '../l1/Md.s' ); + + module[ 'exports' ] = _global_.wTools; +} + +})(); + + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgittools/proto/wtools/amid/l3/git/include/Mid.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgittools/proto/wtools/amid/l3/git/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Mid_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Mid_ss */ })(); + +/* */ /* begin of file Git_ss */ ( function Git_ss() { function Git_ss_naked() { ( function _Namespace_ss_() +{ + +'use strict'; + +const _ = _global_.wTools; +_.git = _.git || Object.create( null ); +let Ini = null; +let Prompt = null; + +// -- +// dichotomy +// + +/** + * Routine stateIsHash() checks weather the input element {-src-} is a git version ( hash ). + * + * @example + * _.git.stateIsHash( 'not a hash' ); + * // returns : false + * + * @example + * _.git.stateIsHash( 'e862c547239662eb77989fd56ab0d56afa7d3ce6' ); + * // returns : false + * + * @example + * _.git.stateIsHash( '#e862c547239662eb77989fd56ab0d56afa7d3ce6' ); + * // returns : true + * + * @example + * _.git.stateIsHash( '#e86' ); + * // returns : false + * + * @example + * _.git.stateIsHash( '#e862' ); + * // returns : true + * + * @param { * } src - An element to check. + * @returns { Boolean } - Returns true if {-src-} is a String that begins with '#' + * and length of hash is great or equal to 4 and less than 40. Otherwise, returns false. + * @function stateIsHash + * @throws { Error } If arguments.length is not equal to 1. + * @namespace wTools.git + * @module Tools/mid/GitTools + */ + +function stateIsHash( src ) +{ + _.assert( arguments.length === 1, 'Expects argument {-src-}' ); + + if( !_.strIs( src ) || !_.strBegins( src, '#' ) ) + return false; + + return /^[a-fA-F0-9]{7,40}$/.test( _.strRemoveBegin( src, '#' ) ); +} + +// + +/** + * Routine stateIsTag() checks weather the input element {-src-} is a git tag ( branch or tag ). + * + * @example + * _.git.stateIsTag( 'e862c547239662eb77989fd56ab0d56afa7d3ce6' ); + * // returns : false + * + * @example + * _.git.stateIsTag( '#e862c547239662eb77989fd56ab0d56afa7d3ce6' ); + * // returns : true + * + * @example + * _.git.stateIsTag( '#e86' ); + * // returns : false + * + * @example + * _.git.stateIsTag( '#e862' ); + * // returns : true + * + * @param { * } src - An element to check. + * @returns { Boolean } - Returns true if {-src-} is a String that begins with '#' + * and length of hash is great or equal to 4 and less than 40. Otherwise, returns false. + * @function stateIsTag + * @throws { Error } If arguments.length is not equal to 1. + * @namespace wTools.git + * @module Tools/mid/GitTools + */ + +function stateIsTag( src ) +{ + _.assert( arguments.length === 1, 'Expects argument {-src-}' ); + + return _.strIs( src ) && _.strBegins( src, '!' ) && src.length >= 2; +} + +// -- +// path +// -- + +// function objectsParse( remotePath ) +// { +// let result = Object.create( null ); +// let gitHubRegexp = /\:\/\/\/github\.com\/([a-zA-Z0-9-_.]+)\/([a-zA-Z0-9-_.]+)/; +// // let gitHubRegexp = /\:\/\/\/github\.com\/(\w+)\/(\w+)(\.git)?/; +// /* Dmytro : this regexp does not search dashes, maybe needs additional symbols */ +// +// // remotePath = this.remotePathNormalize( remotePath ); +// remotePath = _.git.path.normalize( remotePath ); +// let match = remotePath.match( gitHubRegexp ); +// +// if( match ) +// { +// result.service = 'github.com'; +// result.user = match[ 1 ]; +// result.repo = _.strRemoveEnd( match[ 2 ], '.git' ); +// } +// +// return result; +// } + +// // +// +// /** +// * @typedef {Object} RemotePathComponents +// * @property {String} protocol +// * @property {String} hash +// * @property {String} longPath +// * @property {String} localVcsPath +// * @property {String} remoteVcsPath +// * @property {String} remoteVcsLongerPath +// * @namespace wTools.git +// * @module Tools/mid/GitTools +// */ +// +// function pathParse( remotePath ) +// { +// let path = _.uri; +// let result = Object.create( null ); +// +// if( _.mapIs( remotePath ) ) +// return remotePath; +// +// _.assert( arguments.length === 1 ); +// _.assert( _.strIs( remotePath ) ); +// _.assert( path.isGlobal( remotePath ) ) +// +// /* */ +// +// let parsed1 = path.parseConsecutive( remotePath ); +// _.props.extend( result, parsed1 ); +// +// if( !result.tag && !result.hash ) +// result.tag = 'master'; +// +// _.assert( !result.tag || !result.hash, 'Remote path:', _.strQuote( remotePath ), 'should contain only hash or tag, but not both.' ) +// +// let isolated = pathIsolateGlobalAndLocal(); +// result.localVcsPath = isolated.localPath; +// +// /* remoteVcsPath */ +// +// let ignoreComponents = +// { +// hash : null, +// tag : null, +// protocol : null, +// query : null, +// longPath : null +// } +// let parsed2 = _.mapBut_( null, parsed1, ignoreComponents ); +// let protocols = parsed2.protocols = parsed1.protocol ? parsed1.protocol.split( '+' ) : []; +// let isHardDrive = false; +// let provider = _.fileProvider; +// +// if( protocols.length ) +// { +// isHardDrive = _.longHasAny( protocols, [ 'hd' ] ); +// if( protocols[ 0 ].toLowerCase() === 'git' ) +// protocols.shift(); +// if( protocols.length && protocols[ 0 ].toLowerCase() === 'hd' ) +// protocols.shift(); +// } +// +// parsed2.longPath = isolated.globalPath; +// if( !isHardDrive ) +// parsed2.longPath = _.strRemoveBegin( parsed2.longPath, '/' ); +// parsed2.longPath = _.strRemoveEnd( parsed2.longPath, '/' ); +// +// result.remoteVcsPath = path.str( parsed2 ); +// +// if( isHardDrive ) +// result.remoteVcsPath = provider.path.nativize( result.remoteVcsPath ); +// +// /* remoteVcsLongerPath */ +// +// let parsed3 = _.mapBut_( null, parsed1, ignoreComponents ); +// parsed3.longPath = parsed2.longPath; +// parsed3.protocols = parsed2.protocols.slice(); +// result.remoteVcsLongerPath = path.str( parsed3 ); +// +// if( isHardDrive ) +// result.remoteVcsLongerPath = provider.path.nativize( result.remoteVcsLongerPath ); +// +// /* */ +// +// result.isFixated = _.git.path.isFixated( result ); +// +// _.assert( !_.boolLike( result.hash ) ); +// return result +// +// /* */ +// +// function pathIsolateGlobalAndLocal() +// { +// let splits = _.strIsolateLeftOrAll( parsed1.longPath, '.git/' ); +// if( parsed1.query ) +// { +// let query = _.strStructureParse +// ({ +// src : parsed1.query, +// keyValDelimeter : '=', +// entryDelimeter : '&' +// }); +// if( query.out ) +// splits[ 2 ] = path.join( splits[ 2 ], query.out ); +// } +// let globalPath = splits[ 0 ] + ( splits[ 1 ] || '' ); +// let localPath = splits[ 2 ] || './'; +// return { globalPath, localPath }; +// } +// +// } +// +// // +// +// function pathIsFixated( filePath ) +// { +// // let parsed = _.git.pathParse( filePath ); +// let parsed = _.git.path.parse({ remotePath : filePath, full : 0, atomic : 1 }); +// +// if( !parsed.hash ) +// return false; +// +// if( parsed.hash.length < 7 ) +// return false; +// +// if( !/[0-9a-f]+/.test( parsed.hash ) ) +// return false; +// +// return true; +// } +// +// // +// +// /** +// * @summary Changes hash in provided path `o.remotePath` to hash of latest commit available. +// * @param {Object} o Options map. +// * @param {String} o.remotePath Remote path. +// * @param {Number} o.logger=0 Level of verbosity. +// * @function pathFixate +// * @namespace wTools.git +// * @module Tools/mid/GitTools +// */ +// +// function pathFixate( o ) +// { +// let path = _.uri; +// +// if( !_.mapIs( o ) ) +// o = { remotePath : o } +// _.routine.options_( pathFixate, o ); +// _.assert( arguments.length === 1, 'Expects single argument' ); +// +// // let parsed = _.git.pathParse( o.remotePath ); +// let parsed = _.git.path.parse( o.remotePath ); +// let latestVersion = _.git.remoteVersionLatest +// ({ +// remotePath : o.remotePath, +// logger : o.logger, +// }); +// +// let result = path.str +// ({ +// protocol : parsed.protocol, +// longPath : parsed.longPath, +// hash : latestVersion, +// }); +// +// return result; +// } +// +// var defaults = pathFixate.defaults = Object.create( null ); +// defaults.remotePath = null; +// defaults.logger = 0; +// +// // +// +// function remotePathNormalize( remotePath ) +// { +// if( remotePath === null ) +// return remotePath; +// +// remotePath = remotePath.replace( /^(\w+):\/\//, 'git+$1://' ); +// remotePath = remotePath.replace( /:\/\/\b/, ':///' ); +// +// return remotePath; +// } +// +// // +// +// function remotePathNativize( remotePath ) +// { +// if( remotePath === null ) +// return remotePath; +// +// remotePath = remotePath.replace( /^git\+(\w+):\/\//, '$1://' ); +// remotePath = remotePath.replace( /:\/\/\/\b/, '://' ); +// +// return remotePath; +// } + +// + +function remotePathFromLocal( o ) +{ + if( _.strIs( arguments[ 0 ] ) ) + o = { localPath : arguments[ 0 ] }; + + o = _.routine.options_( remotePathFromLocal, o ); + + let config = _.git.configRead( o.localPath ); + + if( !config ) + throw _.err( `No git repository at ${o.localPath}` ); + + if( !config[ 'remote "origin"' ] || !config[ 'remote "origin"' ].url ) + return null; + + let remotePath = config[ 'remote "origin"' ].url; + + // if( remotePath ) + // remotePath = this.remotePathNormalize( remotePath ); + if( remotePath ) + { + if( isLocalClone( remotePath ) ) + { + remotePath = _.git.path.parse( remotePath ) + remotePath.protocol = 'hd'; + remotePath = _.git.path.str( remotePath ); + } + remotePath = _.git.path.normalize( remotePath ); + } + + return remotePath; + + // + + function isLocalClone( remotePath ) + { + _.assert( _.strDefined( remotePath ) ); + let parsed = _.git.path.parse( remotePath ); + // let parsed = _.uri.parse( remotePath ); + if( parsed.user || parsed.protocols.length ) + return false; + return !_.git.path.isGlobal( remotePath ); + // return !_.path.isGlobal( remotePath ); + } +} + +remotePathFromLocal.defaults = +{ + localPath : null, +}; + +// + +function insideRepository( o ) +{ + return !!this.localPathFromInside( o ); +} + +var defaults = insideRepository.defaults = Object.create( null ); +defaults.insidePath = null; + +// + +function localPathFromInside( o ) +{ + let localProvider = _.fileProvider; + let path = localProvider.path; /* Dmytro : should be local provider path */ + + if( _.strIs( arguments[ 0 ] ) ) + o = { insidePath : o }; + + _.routine.options_( localPathFromInside, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + let paths = path.traceToRoot( o.insidePath ); + for( var i = paths.length - 1; i >= 0; i-- ) + if( _.git.isRepository({ localPath : paths[ i ] }) ) + return paths[ i ]; + + return null; +} + +var defaults = localPathFromInside.defaults = Object.create( null ); +defaults.insidePath = null; + +// -- +// tag +// -- + +/** + * Routine tagLocalChange() switches HEAD to defined tag {-o.tag-} in git repository located at {-o.localPath-}. + * + * @example + * // if script is run in git repository with branch 'test' + * let tag = _.git.tagLocalRetrive + * ({ + * localPath : _.path.current(), + * }); + * console.log( tag ); + * // log : 'master' + * + * _.git.tagLocalChange + * ({ + * localPath : _.path.current(), + * tag : 'test', + * }); + * let tag = _.git.tagLocalRetrive + * ({ + * localPath : _.path.current(), + * }); + * console.log( tag ); + * // log : 'test' + * + * @param { Aux } o - Options map. + * @param { String } o.localPath - Path to git repository on hard drive. + * @param { String } o.tag - Tag to switch on. + * @param { Number } o.logger - Level of verbosity. Default is 0. + * @returns { Boolean } - Returns true if HEAD switched to tag {-o.tag-}, otherwise, returns false. + * @function tagLocalChange + * @throws { Error } If arguments.length is not equal to 1. + * @throws { Error } If options map {-o-} has extra options. + * @throws { Error } If {-o.localPath-} is not a String with defined length. + * @namespace wTools.git + * @module Tools/mid/GitTools + */ + +function tagLocalChange( o ) +{ + if( !_.mapIs( o ) ) + o = { localPath : o }; + + _.routine.options_( tagLocalChange, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + const ready = _.git.tagLocalRetrive + ({ + localPath : o.localPath, + sync : 0, + logger : o.logger + }); + ready.then( ( localTag ) => + { + if( localTag === false ) + return false; + + if( localTag === o.tag ) + return true; + + let start = _.process.starter + ({ + logger : _.logger.relativeMaybe( o.logger, -1 ), + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + sync : 0, + deasync : 0, + outputCollecting : 1, + currentPath : o.localPath, + }); + + let localChanges = false; + const con = _.take( null ); + con.then( () => start( 'git status' ) ); + con.then( ( result ) => + { + localChanges = _.strHas( result.output, 'Changes to be committed' ); + return null; + }); + con.then( () => + { + if( localChanges ) + return start( 'git stash' ); + return null; + }); + + con.then( () => start( 'git checkout ' + o.tag ) ); + + con.then( () => + { + if( localChanges ) + return start( 'git pop' ); + return null; + }); + + return con.then( () => true ); + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +var defaults = tagLocalChange.defaults = Object.create( null ); +defaults.localPath = null; +defaults.tag = null +defaults.logger = 0; +defaults.sync = 1; + +// + +/** + * Routine tagLocalRetrive() returns tag of label HEAD ( current commit ) from git repository located at {-o.localPath-}. + * + * @example + * // if script is run in git repository on branch 'master' + * let tag = _.git.tagLocalRetrive + * ({ + * localPath : _.path.current(), + * detailing : 0, + * }); + * console.log( tag ); + * // log : 'master' + * + * @example + * // if script is run in git repository on branch 'master' + * let tag = _.git.tagLocalRetrive + * ({ + * localPath : _.path.current(), + * detailing : 1, + * }); + * console.log( tag ); + * // log : + * // { + * // tag : 'master', + * // isTag : false, + * // isBranch : true, + * // } + * + * @param { Aux } o - Options map. + * @param { String } o.localPath - Path to git repository on hard drive. + * @param { Number } o.logger - Level of verbosity. Default is 0. + * @param { BoolLike } o.detailing - If {-o.detailing-} is true, result is map with tag description. + * @returns { String|Map|Boolean } - Returns name of the tag or false if {-o.localPath-} is not a git repository. + * If {-o.detailing-} is true, routine returns map with tag description. + * @function tagLocalRetrive + * @throws { Error } If arguments.length is not equal to 1. + * @throws { Error } If options map {-o-} has extra options. + * @throws { Error } If {-o.localPath-} is not a String with defined length. + * @namespace wTools.git + * @module Tools/mid/GitTools + */ + +function tagLocalRetrive( o ) +{ + let localProvider = _.fileProvider; + let path = _.git.path; + // let path = localProvider.path; + + if( !_.mapIs( o ) ) + o = { localPath : o }; + + _.routine.options_( tagLocalRetrive, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( o.localPath ), 'Expects local path' ); + + let found; + const ready = _.git.isRepository({ localPath : o.localPath, sync : 0 }); + ready.then( ( isRepository ) => + { + if( isRepository ) + { + let gitPath = path.join( o.localPath, '.git' ); + + if( !localProvider.fileExists( gitPath ) ) + return false; + + let currentTag = localProvider.fileRead( path.join( gitPath, 'HEAD' ) ); + let r = /^ref: refs\/heads\/(.+)\s*$/; + + found = r.exec( currentTag ); + if( found ) + { + return found[ 1 ].trim(); + } + else + { + return _.git.repositoryVersionToTag + ({ + localPath : o.localPath, + version : currentTag.trim(), + local : 1, + remote : 0, + sync : 0, + }) + .then( ( tag ) => + { + if( tag.length ) + return ( _.strIs( tag ) ? tag : tag[ 0 ] ); + else + return ''; + }); + } + } + return false; + }); + ready.then( ( currentTag ) => + { + if( o.detailing ) + { + let result = Object.create( null ); + result.tag = currentTag; + result.isTag = !found && !!currentTag; + result.isBranch = !!found; + + return result; + } + return currentTag; + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +var defaults = tagLocalRetrive.defaults = Object.create( null ); +defaults.localPath = null; +defaults.logger = 0; +defaults.detailing = 0; +defaults.sync = 1; + +// + +function tagExplain( o ) +{ + let localProvider = _.fileProvider; + let path = _.git.path; + // let path = localProvider.path; + + if( !_.mapIs( o ) ) + o = { localPath : o }; + + _.routine.options_( tagExplain, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( o.tag ), 'Expects tag' ); + _.assert( _.strIs( o.localPath ), 'Expects local path' ); + _.assert( _.strIs( o.remotePath ) || _.mapIs( o.remotePath ), 'Expects remote path' ); + + if( !_.git.isRepository({ localPath : o.localPath }) ) + return false; + + let start = _.process.starter + ({ + logger : _.logger.relativeMaybe( o.logger, -1 ), + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + sync : 1, + deasync : 0, + outputCollecting : 1, + currentPath : o.localPath, + throwingExitCode : 0 + }); + + let remotePath = 'origin'; + if( o.remotePath ) + { + let parsed = _.git.path.parse({ remotePath : o.remotePath, full : 1, atomic : 0 }); + let remoteVcsPathParsed = _.mapBut_( null, parsed, { localVcsPath : null, tag : null, hash : null, query : null } ); + remoteVcsPathParsed.longPath = _.strRemoveEnd( parsed.longPath, '/' ); + let remoteVcsPath = _.git.path.str( remoteVcsPathParsed ); + remotePath = _.git.path.nativize( remoteVcsPath ); + } + + let result = + { + tag : o.tag, + isBranch : null, + isTag : null + } + + if( o.local ) + { + let localCheck = `git show-ref --tags --heads -- ${o.tag}`; + if( check( localCheck ) ) + return result; + } + + if( o.remote ) + { + let remoteCheck = `git ls-remote --tags --refs --heads ${remotePath} -- ${o.tag}`; + if( check( remoteCheck ) ) + return result; + } + + /* Dmytro : change order in accordance to case where remote path is an hd path and simultaneously it is not a repository */ + // if( o.remote ) + // { + // let remoteCheck = `git ls-remote --tags --refs --heads ${remotePath} -- ${o.tag}`; + // if( check( remoteCheck ) ) + // return result; + // } + // + // if( o.local ) + // { + // let localCheck = `git show-ref --tags --heads -- ${o.tag}`; + // if( check( localCheck ) ) + // return result; + // } + + return false; + + function check( command ) + { + let got = start( command ); + + if( got.exitCode !== 0 && got.output ) + throw _.errOnce( `Exit code : ${got.exitCode}\n`, got.output ); + + if( !got.output ) + return false; + result.isTag = _.strHas( got.output, `refs/tags/${o.tag}` ); + result.isBranch = _.strHas( got.output, `refs/heads/${o.tag}` ); + return true; + } +} + +var defaults = tagExplain.defaults = Object.create( null ); +defaults.localPath = null; +defaults.remotePath = null; +defaults.local = 1; +defaults.remote = 1; +defaults.tag = null; +defaults.logger = 0; + +// -- +// version +// -- + +function versionLocalChange( o ) +{ + if( !_.mapIs( o ) ) + o = { localPath : o }; + + _.routine.options_( versionLocalChange, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + let localVersion = _.git.localVersion + ({ + localPath : o.localPath, + logger : o.logger + }); + + if( !localVersion ) + return false; + + if( localVersion === o.version ) + return true; + + let start = _.process.starter + ({ + logger : _.logger.relativeMaybe( o.logger, -1 ), + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + sync : 1, + deasync : 0, + outputCollecting : 1, + currentPath : o.localPath, + }); + + let result = start( 'git status' ); + let localChanges = _.strHas( result.output, 'Changes to be committed' ); + + if( localChanges ) + start( 'git stash' ); + + start( 'git checkout ' + o.version ); + + if( localChanges ) + start( 'git pop' ); + + return true; +} + +var defaults = versionLocalChange.defaults = Object.create( null ); +defaults.localPath = null; +defaults.version = null +defaults.logger = 0; + +// + +function localVersion( o ) +{ + let localProvider = _.fileProvider; + let path = _.git.path; + // let path = localProvider.path; + + if( !_.mapIs( o ) ) + o = { localPath : o }; + + _.routine.options_( localVersion, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( o.localPath ), 'Expects local path' ); + + if( !_.git.isRepository({ localPath : o.localPath }) ) + return ''; + + let gitPath = path.join( o.localPath, '.git' ); + + if( !localProvider.fileExists( gitPath ) ) + return ''; + + let currentVersion = localProvider.fileRead( path.join( gitPath, 'HEAD' ) ); + let r = /^ref: refs\/heads\/(.+)\s*$/; + + let found = r.exec( currentVersion ); + if( found ) + currentVersion = found[ 1 ]; + + currentVersion = currentVersion.trim() || null; + + if( o.detailing ) + { + let result = Object.create( null ); + result.version = currentVersion; + result.isHash = false; + result.isBranch = false; + + if( result.version ) + { + result.isHash = !found; + result.isBranch = !result.isHash; + } + return result; + } + + return currentVersion; +} + +var defaults = localVersion.defaults = Object.create( null ); +defaults.localPath = null; +defaults.logger = 0; +defaults.detailing = 0; + +// + +/** + * @summary Returns hash of latest commit from git repository using its remote path `o.remotePath`. + * @param {Object} o Options map. + * @param {String} o.remotePath Remote path to git repository. + * @param {Number} o.logger=0 Level of verbosity. + * @function remoteVersionLatest + * @namespace wTools.git + * @module Tools/mid/GitTools + */ + +function remoteVersionLatest( o ) +{ + if( !_.mapIs( o ) ) + o = { remotePath : o } + + _.routine.options_( remoteVersionLatest, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + // let parsed = _.git.pathParse( remotePath ); + let parsed = _.git.path.parse({ remotePath : o.remotePath, full : 1, atomic : 0 }); + parsed = _.mapBut_( null, parsed, { localVcsPath : null, tag : null, hash : null, query : null } ); + parsed.longPath = _.strRemoveEnd( parsed.longPath, '/' ); + let remotePath = _.git.path.str( parsed ); + remotePath = _.git.path.nativize( remotePath ); + + let start = _.process.starter + ({ + logger : _.logger.relativeMaybe( o.logger, -1 ), + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + sync : 1, + deasync : 0, + outputCollecting : 1, + }); + + // let got = start( 'git ls-remote ' + parsed.remoteVcsLongerPath ); + let got = start( `git ls-remote ${ remotePath }` ); + let latestVersion = /([0-9a-f]+)\s+HEAD/.exec( got.output ); + if( !latestVersion || !latestVersion[ 1 ] ) + return null; + + latestVersion = latestVersion[ 1 ]; + + return latestVersion; +} + +var defaults = remoteVersionLatest.defaults = Object.create( null ); +defaults.remotePath = null; +defaults.logger = 0; + +// + +/** + * @summary Returns commit hash from remote path `o.remotePath`. + * @description Returns hash of latest commit if no hash specified in remote path. + * @param {Object} o Options map. + * @param {String} o.remotePath Remote path. + * @param {Number} o.logger=0 Level of verbosity. + * @function remoteVersionCurrent + * @namespace wTools.git + * @module Tools/mid/GitTools + */ + +function remoteVersionCurrent( o ) +{ + if( !_.mapIs( o ) ) + o = { remotePath : o } + + _.routine.options_( remoteVersionCurrent, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + // let parsed = _.git.pathParse( o.remotePath ); + let parsed = _.git.path.parse( o.remotePath ); + if( parsed.isFixated ) + return parsed.hash; + + return _.git.remoteVersionLatest( o ); +} + +var defaults = remoteVersionCurrent.defaults = Object.create( null ); +defaults.remotePath = null; +defaults.logger = 0; + +// + +/** + * @summary Checks if provided version `o.version` is a commit hash. + * @description + * Returns false if version is a branch name or tag. + * There is a limitation. Result can be inaccurate if provided version is specified + * in short form and commit doesn't exist in repository at `o.localPath`. + * Use long form of version( SHA-1 ) to get accurate result. + * @param {Object} o Options map. + * @param {String} o.localPath Local path to git repository. + * @param {Number} o.sync=1 Controls execution mode. + * @function versionIsCommitHash + * @namespace wTools.git + * @module Tools/mid/GitTools + */ + +function versionIsCommitHash( o ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + _.routine.options_( versionIsCommitHash, o ); + _.assert( _.strDefined( o.localPath ) ); + _.assert( _.strDefined( o.version ) ); + + let ready = _.take( null ); + let start = _.process.starter + ({ + sync : 0, + deasync : 0, + outputCollecting : 1, + mode : 'shell', + currentPath : o.localPath, + throwingExitCode : 0, + inputMirroring : 0, + outputPiping : 0, + ready + }); + + ready.then( () => + { + if( !self.isRepository({ localPath : o.localPath }) ) + throw _.err( `Provided {-o.localPath-}: ${_.strQuote( o.localPath )} doesn't contain a git repository.` ) + return null; + }); + + start( `git rev-parse --symbolic-full-name ${o.version}` ) + + ready.then( ( got ) => + { + if( got.exitCode !== 0 || got.output && _.strHas( got.output, 'refs/' ) ) + return false; + return true; + }); + + ready.catch( ( err ) => + { + _.errAttend( err ); + throw _.err( 'Failed to check if provided version is a commit hash.\n', err ); + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +versionIsCommitHash.defaults = +{ + localPath : null, + version : null, + sync : 1, +}; + +// + +function versionsRemoteRetrive( o ) +{ + _.routine.options_( versionsRemoteRetrive, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( o.localPath ) ); + + let ready = _.process.start + ({ + execPath : 'git', + mode : 'spawn', + currentPath : o.localPath, + args : + [ + 'for-each-ref', + 'refs/remotes', + '--format=%(refname:strip=3)' + ], + inputMirroring : 0, + outputPiping : 0, + outputCollecting : 1, + }); + + ready.finally( ( err, got ) => + { + if( err ) + throw _.err( 'Can\'t retrive remote versions. Reason:', err ); + + let result = _.strSplitNonPreserving({ src : got.output, delimeter : '\n' }); + return result.slice( 1 ); + }); + + return ready; +} + +var defaults = versionsRemoteRetrive.defaults = Object.create( null ); +defaults.localPath = null; + +// + +function versionsPull( o ) +{ + _.routine.options_( versionsPull, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + return _.git.versionsRemoteRetrive({ localPath : o.localPath }) + .then( ( versions ) => + { + _.assert( _.arrayIs( versions ) && versions.length > 0 ); + + let ready = _.take( null ); + let start = _.process.starter + ({ + mode : 'shell', + currentPath : o.localPath, + ready, + }); + _.each( versions, ( version ) => start( `git checkout ${version} && git pull` ) ); + + return ready; + }) +} + +var defaults = versionsPull.defaults = Object.create( null ); +defaults.localPath = null; + +// -- +// dichotomy +// -- + +/** + * @summary Returns true if local copy of repository `o.localPath` is up to date with remote repository `o.remotePath`. + * @param {Object} o Options map. + * @param {String} o.localPath Local path to repository. + * @param {String} o.remotePath Remote path to repository. + * @param {Number} o.logger=0 Level of verbosity. + * @function isUpToDate + * @namespace wTools.git + * @module Tools/mid/GitTools + */ + +function isUpToDate( o ) +{ + let localProvider = _.fileProvider; + let path = localProvider.path; + + _.routine.options_( isUpToDate, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + let status = statusInit(); + + /* Vova: used full:1 because repositoryHasTag expects remote path as full */ + let parsed = _.git.path.parse({ remotePath : o.remotePath, /* full : 0, atomic : 1 */ full : 1, atomic : 0 }); + + let ready = _.Consequence(); + + /* xxx : aaa : check mode. shell should be, probably */ /* Dmytro : the default mode is `shell` and commands passed to functors are shell commands */ + let start = _.process.starter + ({ + logger : _.logger.relativeMaybe( o.logger, -1 ), + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + currentPath : o.localPath, + mode : 'shell', + ready, + }); + + /* xxx : aaa : check mode. shell should be, probably */ /* Dmytro : the default mode is `shell` and commands passed to functors are shell commands */ + let shell = _.process.starter + ({ + logger : _.logger.relativeMaybe( o.logger, -1 ), + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + ready, + mode : 'shell', + currentPath : o.localPath, + throwingExitCode : 0, + outputCollecting : 1, + }); + + status.dirExists = localProvider.fileExists( o.localPath ); + + if( !status.dirExists ) + return end( false ); + + status.isRepository = localProvider.fileExists( path.join( o.localPath, '.git' ) ); + + if( !status.isRepository ) + return end( false ); + + status.isClonedFromRemote = isClonedFromRemote(); + + if( !status.isClonedFromRemote ) + { + ready.take( end( false ) ); + return ready.split(); + } + + ready.take( null ); + + start( 'git fetch origin' ); + + ready.finally( ( err, arg ) => + { + if( err ) + throw _.err( err ); + return null; + }); + + // shellAll + // ([ + // // 'git diff origin/master --quiet --exit-code', + // // 'git diff --quiet --exit-code', + // // 'git branch -v', + // 'git status', + // ]); + + shell( 'git status' ); + + ready.then( ( got ) => + { + let result = false; + let detachedRegexp = /* /HEAD detached at (\w+)/ */ /(HEAD detached at (.+)|Not currently on any branch.)/; + let detachedParsed = detachedRegexp.exec( got.output ); + // let versionLocal = _.git.tagLocalRetrive({ localPath : o.localPath, logger : o.logger }); + + // if( detachedParsed ) + // { + // result = _.strBegins( parsed.hash, detachedParsed[ 1 ] ); + // } + // else if( _.strBegins( parsed.hash, versionLocal ) ) + // { + // result = !_.strHasAny( got.output, [ 'Your branch is behind', 'have diverged' ] ); + // } + + /* qqq: find better way to check if hash is not a branch name */ + // if( parsed.hash && !parsed.isFixated ) + // throw _.err( `Remote path: ${_.color.strFormat( String( o.remotePath ), 'path' )} is fixated, but hash: ${_.color.strFormat( String( parsed.hash ), 'path' ) } doesn't look like commit hash.` ) + + /* aaa: replace with versionIsCommitHash after testing */ /* Dmytro : replaced, the routine versionIsCommitHash is tested */ + // if( parsed.hash && !parsed.isFixated ) + if( parsed.hash && !_.git.versionIsCommitHash({ localPath : o.localPath, version : parsed.hash }) ) + throw _.err( `Remote path: ( ${_.color.strFormat( String( o.remotePath ), 'path' )} ) looks like path with tag, but defined as path with version. Please use ! instead of # to specify tag` ); + + result = status.isHead = _.git.isHead + ({ + localPath : o.localPath, + tag : parsed.tag, + hash : parsed.hash + }); + + if( o.differentiatingTags ) + if( result && parsed.tag ) + { + /* Vova: + Local repo is up to date with "real" remote tag ( not a branch ) only when local repo is in detached state and heads are same + Next lines check last part of this rule. + */ + let tagExplained = _.git.tagExplain + ({ + localPath : o.localPath, + remotePath : parsed, + tag : parsed.tag + }); + if( tagExplained.isTag ) + result = !!detachedParsed; + } + + if( !result && parsed.tag ) + { + status.repositoryHasTag = _.git.repositoryHasTag + ({ + localPath : o.localPath, + remotePath : parsed, + tag : parsed.tag + }); + + if( !status.repositoryHasTag ) + { + let remoteVcsPathParsed = _.mapBut_( null, parsed, { tag : null, hash : null, query : null } ); + let remoteVcsPath = _.git.path.str( remoteVcsPathParsed ); + throw _.err + ( + `Specified tag: ${_.strQuote( parsed.tag )} doesn't exist in local and remote copy of the repository.\ + \nLocal path: ${_.color.strFormat( String( o.localPath ), 'path' )}\ + \nRemote path: ${_.color.strFormat( String( remoteVcsPath ), 'path' )}` + ); + } + } + + status.gitStatus = got.output; + + if( result && !detachedParsed ) + result = status.branchIsUpToDate = !_.strHasAny( got.output, [ 'Your branch is behind', 'have diverged' ] ); + + if( o.logger && o.logger.verbosity > 0 ) + o.logger.log( o.remotePath, result ? 'is up to date' : 'is not up to date' ); + + return end( result ); + }); + + ready.finally( ( err, arg ) => + { + if( err ) + throw _.err( err ); + return arg; + }); + + return ready.split(); + + /* */ + + function statusInit() + { + let status = Object.create( null ); + status.dirExists = null; + status.isRepository = null; + status.isClonedFromRemote = null; + status.isHead = null; + status.branchIsUpToDate = null; + status.originPath = null; + status.hasOrigin = null; + status.gitStatus = null; + return status; + } + + /* */ + + function isClonedFromRemote() + { + let conf = _.git.configRead( o.localPath ); + + status.hasOrigin = true; + + if( !conf || !conf[ 'remote "origin"' ] || !_.strIs( conf[ 'remote "origin"' ].url ) ) + { + status.hasOrigin = false; + return false; + } + + status.originPath = conf[ 'remote "origin"' ].url; + let originParsed = _.git.path.parse( status.originPath ); + + // if( !_.strEnds( status.originPath, remoteVcsPath ) ) + if + ( + parsed.service !== originParsed.service + || parsed.user !== originParsed.user + || parsed.repo !== originParsed.repo + ) + return false; + + return true; + } + + /* */ + + function end( result ) + { + status.result = result; + + if( !o.detailing ) + return result; + + if( result === false ) + { + if( status.dirExists === false ) + status.reason = `Path does not exist: ${o.localPath}`; + else if( status.isRepository === false ) + status.reason = `No git repository at: ${o.localPath}`; + else if( status.hasOrigin === false ) + status.reason = `Repository does not have origin.`; + else if( status.isClonedFromRemote === false ) + status.reason = `Repository has different origin.\nCurrent origin: ${status.originPath}\nRemote path: ${o.remotePath}`; + else if( status.isHead === false ) + status.reason = `HEAD of the repository does not point to: ${parsed.tag ? `!${parsed.tag}` : `#${parsed.hash}`}`; + else if( status.branchIsUpToDate === false ) + status.reason = `Current branch is not up-to-date with remote. Git status:\n${status.gitStatus}`; + } + + return status; + } +} + +var defaults = isUpToDate.defaults = Object.create( null ); +defaults.localPath = null; +defaults.remotePath = null; +defaults.differentiatingTags = true; +defaults.logger = 0; +defaults.detailing = 0; + +// + +/** + * @summary Returns true if path `o.localPath` contains a git repository. + * @param {Object} o Options map. + * @param {String} o.localPath Local path to package. + * @param {Number} o.logger=0 Level of verbosity. + * @function hasFiles + * @namespace wTools.git + * @module Tools/mid/GitTools + */ + +function hasFiles( o ) +{ + let localProvider = _.fileProvider; + + _.routine.options_( hasFiles, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( !localProvider.isDir( o.localPath ) ) + return false; + if( !localProvider.dirIsEmpty( o.localPath ) ) + return true; + + return false; +} + +var defaults = hasFiles.defaults = Object.create( null ); +defaults.localPath = null; +// defaults.verbosity = 0; /* aaa : for Dmytro : why?? */ /* Dmytro : I don't know. I saw not this code. */ + +// + +/** + * @summary Returns true if path `o.localPath` contains a git repository that was cloned from remote `o.remotePath`. + * @param {Object} o Options map. + * @param {String} o.localPath Local path to package. + * @param {String} o.remotePath Remote path to package. + * @param {Number} o.logger=0 Level of verbosity. + * @function hasRemote + * @namespace wTools.git + * @module Tools/mid/GitTools + */ + +function hasRemote( o ) +{ + let localProvider = _.fileProvider; + let path = _.git.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options_( hasRemote, o ); + _.assert( _.strDefined( o.localPath ) ); + _.assert( _.strDefined( o.remotePath ) ); + + let ready = _.take( null ); + + ready.then( () => + { + let result = Object.create( null ); + result.downloaded = true; + result.remoteIsValid = false; + + if( !localProvider.fileExists( o.localPath ) ) + { + result.downloaded = false; + return result; + } + + let gitConfigExists = localProvider.fileExists( path.join( o.localPath, '.git/config' ) ); + + if( !gitConfigExists ) + { + result.downloaded = false; + return result; + } + + let config = _.git.configRead( o.localPath ); + + let parsed = path.parse({ remotePath : o.remotePath, full : 0, atomic : 1 }); + let remoteVcsPathParsed = _.mapBut_( null, parsed, { tag : null, hash : null, query : null, localVcsPath : null } ); + let remoteVcsPath = path.str( remoteVcsPathParsed ); + remoteVcsPath = path.nativize( remoteVcsPath ); + + let remoteOrigin = config[ 'remote "origin"' ]; + let originVcsPath = null; + + if( remoteOrigin ) /* qqq : for Dmytro : cover */ + { + originVcsPath = path.normalize( remoteOrigin.url ); + originVcsPath = path.nativize( originVcsPath ); + } + + _.sure( _.strDefined( remoteVcsPath ) ); + _.sure( _.strDefined( originVcsPath ) || originVcsPath === null ); + + result.remoteVcsPath = remoteVcsPath; + result.originVcsPath = originVcsPath; + if( originVcsPath === null ) + result.remoteIsValid = false; + else + result.remoteIsValid = path.trail( path.refine( originVcsPath ) ) === path.trail( path.refine( remoteVcsPath ) ); + + return result; + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +var defaults = hasRemote.defaults = Object.create( null ); +defaults.localPath = null; +defaults.remotePath = null; +defaults.sync = 1; + +// + +function isRepository( o ) +{ + let self = this; + let path = _.git.path; + + _.routine.options_( isRepository, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( o.localPath !== null ) + o.localPath = pathNormalize( o.localPath ); + if( o.remotePath !== null ) + o.remotePath = pathNormalize( o.remotePath ); + + let ready = _.take( false ); + if( o.localPath !== null ) + ready.then( () => _.fileProvider.fileExists( path.join( o.localPath, '.git/config' ) ) ); + + if( o.remotePath !== null ) + { + ready.then( ( exists ) => + { + if( !exists && o.localPath ) + return false; + return remoteIsRepository( o.remotePath ); + }); + ready.then( ( isRepo ) => + { + if( !isRepo || o.localPath === null ) + return isRepo; + return localHasRightOrigin( o.remotePath ); + }); + } + + if( o.sync ) + return ready.syncMaybe(); + return ready; + + /* */ + + function pathNormalize( remotePath ) + { + let parsed = _.git.path.parse({ remotePath, full : 1, atomic : 0 }); + let remoteVcsPathParsed = _.mapBut_( null, parsed, { localVcsPath : null, tag : null, hash : null, query : null } ); + if( remoteVcsPathParsed.longPath !== _.git.path.rootToken ) + remoteVcsPathParsed.longPath = _.strRemoveEnd( parsed.longPath, _.git.path.rootToken ); + let remoteVcsPath = _.git.path.str( remoteVcsPathParsed ); + if( path.isGlobal( remoteVcsPath ) ) + return _.git.path.nativize( remoteVcsPath ); + return remoteVcsPath; + } + + /* */ + + function remoteIsRepository( remotePath ) + { + let ready = _.Consequence.Try( () => + { + return _.process.start + ({ + execPath : `git ls-remote ${ remotePath }`, + mode : 'shell', /* aaa : for Dmytro : why? random?? */ /* Dmytro : not random, we use `shell` for commands in all module, mode `spawn` has some old routines */ + throwingExitCode : 0, + outputPiping : 0, + stdio : 'ignore', + sync : o.sync, + deasync : 0, + inputMirroring : 0, + outputCollecting : 0 + }); + }); + return ready.then( ( op ) => + { + return op.exitCode === 0; + }); + } + + /* */ + + function localHasRightOrigin( remotePath ) + { + let config = configRead( o.localPath ); + let originPath = config[ 'remote "origin"' ].url; + if( !path.isGlobal( originPath ) ) + originPath = path.normalize( originPath ); + remotePath = path.normalize( remotePath ); + return originPath === remotePath; + } +} + +var defaults = isRepository.defaults = Object.create( null ); +defaults.localPath = null; +defaults.remotePath = null; +defaults.sync = 1; + +// + +/** + * @summary Returns true if HEAD of repository located at `o.localPath` points to `o.hash` or `o.tag`. + * Expects only `o.hash` or `o.tag` at same time. + * @param {Object} o Options map. + * @param {String} o.localPath Local path to package. + * @param {String} o.tag Target tag or branch name. + * @param {String} o.hash Target commit hash. + * @function isHead + * @namespace wTools.git + * @module Tools/mid/GitTools + */ + +function isHead( o ) +{ + let localProvider = _.fileProvider; + let path = _.git.path; + // let path = localProvider.path; + + _.routine.options_( isHead, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strDefined( o.localPath ) ); + _.assert( !!o.tag || !!o.hash, 'Expects {-o.hash-} or {-o.tag-} to be defined.' ); + _.assert( !o.tag || !o.hash, 'Expects only {-o.hash-} or {-o.tag-}, but not both at same time.' ); + + let ready = _.take( null ); + + let shell = _.process.starter + ({ + currentPath : o.localPath, + throwingExitCode : 0, + outputPiping : 0, + sync : 0, + deasync : 0, + inputMirroring : 0, + outputCollecting : 1 + }); + + let head = null; + let tag = null; + + ready.then( () => this.isRepository({ localPath : o.localPath }) ) + + if( o.hash ) + ready.then( hashCheck ) + else if( o.tag ) + ready.then( tagCheck ) + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + + /* */ + + function hashCheck( got ) + { + if( !got ) + return false; + + return getHead() + .then( ( head ) => + { + if( !head ) + return false; + return head === o.hash; + }) + } + + function tagCheck( got ) + { + if( !got ) + return false; + + return getHead() + .then( ( head ) => + { + if( !head ) + return false; + return getTag(); + }) + .then( ( got ) => + { + if( !got ) + return false; + + let result = head === got.hash; + + /* return result if we are checking tag or hash comparison result is negative */ + if( got.tag || !result ) + return result; + + /* compare branches in case when HEAD and target branch are on same commit */ + return getHead( true ) + .then( ( branchName ) => + { + if( !branchName ) + return false; + return got.branch === branchName; + }) + }) + } + + function getHead( refName ) + { + refName = refName ? '--abbrev-ref' : ''; + + return shell({ execPath : `git rev-parse ${refName} HEAD`, ready : null }) + .then( ( got ) => + { + if( got.exitCode ) + return false; + head = _.strStrip( got.output ); + return head; + }) + } + + function getTag() + { + return shell({ execPath : `git show-ref ${o.tag} -d --heads --tags`, ready : null }) + .then( ( got ) => + { + if( got.exitCode ) + return false; + let output = _.strSplitNonPreserving({ src : got.output, delimeter : '\n' }); + if( !output.length ) + return false; + _.assert( output.length <= 2 ); + tag = output[ 0 ]; + if( output.length === 2 ) + { + tag = output[ 1 ]; + _.assert( _.strHas( tag, '^{}' ), 'Expects annotated tag, got:', tag ); + } + + let isolated = _.strIsolateLeftOrAll( tag, ' ' ); + let result = Object.create( null ); + + result.hash = isolated[ 0 ]; + result.ref = isolated[ 2 ]; + + if( _.strBegins( result.ref, 'refs/heads/' ) ) + result.branch = _.strRemoveBegin( result.ref, 'refs/heads/' ) + else if( _.strBegins( result.ref, 'refs/tags/' ) ) + result.tag = _.strRemoveBegin( result.ref, 'refs/tags/' ) + + _.assert( _.strDefined( result.hash ) ); + _.assert( _.strDefined( result.ref ) ); + _.assert( !_.strDefined( result.branch ) || !_.strDefined( result.tag ) ); + + return result; + }) + } +} + +var defaults = isHead.defaults = Object.create( null ); +defaults.localPath = null; +defaults.hash = null; +defaults.tag = null; +defaults.sync = 1; + +// + +function sureHasOrigin( o ) +{ + if( !_.mapIs( o ) ) + o = { localPath : o } + + _.routine.options_( sureHasOrigin, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strDefined( o.localPath ), 'Expects local path' ); + _.assert( _.strDefined( o.remotePath ) || _.mapIs( o.remotePath ), 'Expects remote path' ); + + if( !_.git.isRepository({ localPath : o.localPath }) ) + throw _.err( `Provided path is not a git repository:${o.localPath}` ); + + // let parsed = _.git.pathParse( o.remotePath ); + let parsed = _.git.path.parse({ remotePath : o.remotePath, full : 1, atomic : 0 }); + let remoteVcsPathParsed = _.mapBut_( null, parsed, { localVcsPath : null, tag : null, hash : null, query : null } ); + remoteVcsPathParsed.longPath = _.strRemoveEnd( parsed.longPath, '/' ); + let remoteVcsPath = _.git.path.str( remoteVcsPathParsed ); + let remoteVcsNativized = _.git.path.nativize( remoteVcsPath ); + + let config = _.git.configRead( o.localPath ); + + _.sure + ( + !!config[ 'remote "origin"' ] && !!config[ 'remote "origin"' ] && _.strIs( config[ 'remote "origin"' ].url ), + 'GIT config does not have {-remote.origin.url-}' + ); + + let srcCurrentPath = config[ 'remote "origin"' ].url; + srcCurrentPath = _.git.path.nativize( _.git.path.normalize( config[ 'remote "origin"' ].url ) ); /* qqq : for Dmytro : cover */ + + // _.sure + // ( + // _.strEnds( _.strRemoveEnd( srcCurrentPath, '/' ), _.strRemoveEnd( parsed.remoteVcsPath, '/' ) ), + // () => 'GIT repository at directory ' + _.strQuote( o.localPath ) + '\n' + // + 'Has origin ' + _.strQuote( srcCurrentPath ) + '\n' + // + 'Should have ' + _.strQuote( parsed.remoteVcsPath ) + // ); + + _.sure + ( + _.strEnds( _.strRemoveEnd( srcCurrentPath, '/' ), _.strRemoveEnd( remoteVcsNativized, '/' ) ), + () => 'GIT repository at directory ' + _.strQuote( o.localPath ) + '\n' + + 'Has origin ' + _.strQuote( srcCurrentPath ) + '\n' + + 'Should have ' + _.strQuote( remoteVcsPath ) + ); + + return config; +} + +sureHasOrigin.defaults = +{ + localPath : null, + remotePath : null +} + +// -- +// status +// -- + +/** + * @summary Checks local repo for uncommitted, unpushed changes and conflicts. + * + * @description + * Explanation for short format of 'git status': https://git-scm.com/docs/git-status#_short_format + * Explanation for result of `uncommittedUnstaged`: + * XY Meaning + * ------------------------------------------------- + * ММ modified->staged->modified + * MD modified->staged->deleted + * AM added->staged->modified + * AD added->staged->deleted + * RM renamed->staged->modified + * RD renamed->staged->deleted + * CM copied->staged->modified + * CD copied->staged->deleted + * + * @param {Object} o Options map. + * @param {String} o.localPath Path to local repo. + * @param {Boolean} o.uncommitted=1 Checks for uncommitted changes. Enables all uncommitted* checks that are not disabled explicitly. + * @param {Boolean} o.uncommittedUntracked=null Checks for untracked files + * @param {Boolean} o.uncommittedAdded=null Checks for new files + * @param {Boolean} o.uncommittedChanged=null Checks for modified files + * @param {Boolean} o.uncommittedDeleted=null Checks for deleted files + * @param {Boolean} o.uncommittedRenamed=null Checks for renamed files + * @param {Boolean} o.uncommittedCopied=null Checks for copied files + * @param {Boolean} o.uncommittedIgnored=0 Checks for new files that are ignored + * @param {Boolean} o.uncommittedUnstaged=null Checks for unstaged changes + * @param {Boolean} o.unpushed=1 Checks for unpsuhed changes. Enables all unpushed* checks that are not disabled explicitly. + * @param {Boolean} o.unpushedCommits=null Checks for unpushed commit + * @param {Boolean} o.unpushedTags=null Checks for unpushed tags + * @param {Boolean} o.unpushedBranches=null Checks for unpushed branches + * @param {Boolean} o.conflicts=1 Check for conflicts + * @param {Boolean} o.detailing=0 Performs check of each enabled option if enabled, otherwise performs fast check. + * @param {Boolean} o.explaining=0 Properties from result map will contain explanation if result of check is positive. + * @function statusLocal + * @namespace wTools.git + * @module Tools/mid/GitTools + */ + +function statusLocal_head( routine, args ) +{ + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { localPath : o } + + _.routine.options_( routine, o ); + _.assert( _.strDefined( o.localPath ) ); + _.assert( args.length === 1 ); + + if( o.uncommitted !== null ) + _.each( routine.uncommittedGroup, ( k ) => + { + if( o[ k ] === null ) + o[ k ] = o.uncommitted; + }) + + if( o.unpushed !== null ) + _.each( routine.unpushedGroup, ( k ) => + { + if( o[ k ] === null ) + o[ k ] = o.unpushed; + }) + + for( let k in o ) + if( o[ k ] === null ) + o[ k ] = true; + + return o; +} + +// + +function statusLocal_body( o ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + let start = _.process.starter + ({ + currentPath : o.localPath, + mode : 'spawn', + sync : 0, + deasync : o.sync, + throwingExitCode : 1, + outputCollecting : 1, + // verbosity : o.verbosity - 1, + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + logger : _.logger.relativeMaybe( o.logger, -1 ), + }); + + let result = resultPrepare(); + + let optimizingCheck = o.uncommittedUntracked && o.uncommittedAdded + && o.uncommittedChanged && o.uncommittedDeleted + && o.uncommittedRenamed && o.uncommittedCopied + && !o.detailing; + + let ready = _.take( null ); + + ready.then( uncommittedCheck ); + + if( o.unpushedCommits ) + ready.then( unpushedCommitsCheck ) + + if( o.unpushedTags ) + ready.then( checkTags ) + + if( o.unpushedBranches ) + ready.then( checkBranches ) + + ready.finally( end ); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + + /* aaa : for Dmytro : list of subroutines? */ + /* + Dmytro : list of subroutines is given below + statusMake + uncommittedCheck + optimizedCheck + detailedCheck + resultPrepare + uncommittedDetailedCheck + checkTags + retry + remoteTagsGet + remoteTagsGetSync + checkBranches + unpushedCommitsCheck + */ + + function end( err, got ) + { + + if( err ) + throw _.err( err, `\nFailed to check if repository ${_.color.strFormat( String( o.localPath ), 'path' )} has local changes` ); + + statusMake(); + + return result; + } + + /* */ + + function statusMake() + { + + /* */ + + if( !optimizingCheck ) + { + for( let i = 0; i < statusLocal_body.uncommittedGroup.length; i++ ) + { + let k = statusLocal_body.uncommittedGroup[ i ]; + + if( !_.strIs( result[ k ] ) ) + continue; + + if( result.uncommitted === null ) + result.uncommitted = []; + + if( !result[ k ] ) + continue; + + result.uncommitted.push( result[ k ] ); + } + if( _.arrayIs( result.uncommitted ) ) + result.uncommitted = result.uncommitted.join( '\n' ) + } + + if( result.uncommitted ) + result.uncommitted = 'List of uncommited changes in files:\n' + ' ' + _.strLinesIndentation( result.uncommitted, ' ' ); + + /* */ + + for( let i = 0; i < statusLocal_body.unpushedGroup.length; i++ ) + { + let k = statusLocal_body.unpushedGroup[ i ]; + + if( !_.strIs( result[ k ] ) ) + continue; + + if( result.unpushed === null ) + result.unpushed = []; + + if( !result[ k ] ) + continue; + + if( k === 'unpushedCommits' ) + result.unpushed.push( 'List of branches with unpushed commits:' ) + else if( k === 'unpushedBranches' || k === 'unpushedTags' ) + _.arrayAppendOnce( result.unpushed, 'List of unpushed:' ); + + result.unpushed.push( ' ' + _.strLinesIndentation( result[ k ], ' ' ) ); + } + if( _.arrayIs( result.unpushed ) ) + result.unpushed = result.unpushed.join( '\n' ); + + /* */ + + result.status = result.uncommitted; + + if( _.strIs( result.unpushed ) ) + { + if( !result.status ) + result.status = result.unpushed; + else if( result.unpushed ) + result.status += '\n' + result.unpushed; + } + + _.assert( _.strIs( result.status ) || result.status === null ); + + /* */ + + if( optimizingCheck ) + { + let uncommitted = !!result.uncommitted; + + _.each( statusLocal_body.uncommittedGroup, ( k ) => + { + if( !o[ k ] ) + return; + _.assert( result[ k ] === null ) + result[ k ] = uncommitted ? _.maybe : ''; + }) + + if( uncommitted ) + { + result.unpushed = _.maybe; + _.each( statusLocal_body.unpushedGroup, ( k ) => + { + if( !o[ k ] ) + return; + _.assert( result[ k ] === null ) + result[ k ] = _.maybe; + }) + } + } + + for( let k in result ) + { + if( _.strIs( result[ k ] ) ) + { + if( !o.explaining ) + result[ k ] = !!result[ k ]; + else if( o.detailing && !result[ k ] ) + result[ k ] = false; + } + } + } + + /* */ + + function uncommittedCheck( got ) + { + let gitStatusArgs = [ '-u', '--porcelain', '-b' ] + if( o.uncommittedIgnored ) + gitStatusArgs.push( '--ignored' ); + + return start({ execPath : 'git status', args : gitStatusArgs }) + .then( ( got ) => + { + let output = _.strSplitNonPreserving({ src : got.output, delimeter : '\n' }); + + /* + check for any changes, except new commits/tags/branches + */ + + if( optimizingCheck ) + { + return optimizedCheck( output ); + } + else + { + return detailedCheck( output ); + } + + }) + } + + /* */ + + function optimizedCheck( output ) + { + result.uncommitted = ''; + + if( output.length > 1 ) + result.uncommitted = output.join( '\n' ); + + return result.uncommitted; + } + + /* */ + + function detailedCheck( output ) + { + let outputStripped = output.join( '\n' ); + + if( o.conflicts ) + if( uncommittedDetailedCheck( outputStripped, 'conflicts', /^D[DU]|A[AU]|U[DAU] .*/gm ) ) + return true; + + if( o.uncommittedUntracked ) + if( uncommittedDetailedCheck( outputStripped, 'uncommittedUntracked', /^\?{1,2} .*/gm ) ) + return true; + + if( o.uncommittedAdded ) + if( uncommittedDetailedCheck( outputStripped, 'uncommittedAdded', /^A .*/gm ) ) + return true; + + if( o.uncommittedChanged ) + if( uncommittedDetailedCheck( outputStripped, 'uncommittedChanged', /^M .*/gm ) ) + return true; + + if( o.uncommittedDeleted ) + if( uncommittedDetailedCheck( outputStripped, 'uncommittedDeleted', /^D .*/gm ) ) + return true; + + if( o.uncommittedRenamed ) + if( uncommittedDetailedCheck( outputStripped, 'uncommittedRenamed', /^R .*/gm ) ) + return true; + + if( o.uncommittedCopied ) + if( uncommittedDetailedCheck( outputStripped, 'uncommittedCopied', /^C .*/gm ) ) + return true; + + if( o.uncommittedIgnored ) + if( uncommittedDetailedCheck( outputStripped, 'uncommittedIgnored', /^!{1,2} .*/gm ) ) + return true; + + if( o.uncommittedUnstaged ) + if( uncommittedDetailedCheck( outputStripped, 'uncommittedUnstaged', /^[MARC][MD] .*/gm ) ) + return true; + + return false; + } + + /* */ + + function resultPrepare() + { + let result = Object.create( null ); + + result.uncommitted = null; + result.unpushed = null; + + _.each( statusLocal_body.uncommittedGroup, ( k ) => { result[ k ] = null } ) + _.each( statusLocal_body.unpushedGroup, ( k ) => { result[ k ] = null } ) + + return result; + } + + /* */ + + function uncommittedDetailedCheck( output, check, regexp ) + { + let match = output.match( regexp ); + + result[ check ] = ''; + + if( match ) + { + match = _.str.lines.strip( match ); + result[ check ] = match.join( '\n' ) + } + + return result[ check ] && !o.detailing; + } + + /* */ + + function checkTags( got ) + { + if( got && !o.detailing ) + return got; + + /* Nothing to check if there no tags*/ + + let tagsDirPath = _.git.path.join( o.localPath, '.git/refs/tags' ); + let tags = _.fileProvider.dirRead({ filePath : tagsDirPath, throwing : 0 }) + if( !tags || !tags.length ) + { + result.unpushedTags = ''; + return result.unpushedTags; + } + + /* if origin is no defined include all tags to list, with "?" at right side */ + + let config = configRead.call( this, o.localPath ); + if( !config[ 'remote "origin"' ] ) + { + result.unpushedTags = ''; + + if( tags && tags.length ) + { + tags = tags.map( ( tag ) => `[new tag] ${tag} -> ?` ) + result.unpushedTags += tags.join( '\n' ) + } + + return result.unpushedTags; + } + + /* check tags */ + + return start( 'git for-each-ref */tags/* --format=%(refname:short)' ) + .then( ( got ) => + { + tags = _.strSplitNonPreserving({ src : got.output, delimeter : '\n' }); + _.assert( tags.length > 0 ); + return remoteTagsGet(); + }) + .then( ( got ) => + { + result.unpushedTags = ''; + let unpushedTags = []; + _.each( tags, ( tag ) => + { + if( !_.strHas( got.output, `refs/tags/${tag}` ) ) + unpushedTags.push( `[new tag] ${tag} -> ${tag}` ); + }) + + if( unpushedTags.length ) + result.unpushedTags += unpushedTags.join( '\n' ); + + return result.unpushedTags; + }) + } + + /* */ + + function retry() + { + o.attempt -= 1; + return _.time.out( o.attemptDelay, () => remoteTagsGet() ); + } + + /* */ + + function remoteTagsGet() + { + _.assert( o.attempt >= 1, 'Expects defined number of attempts {-o.attempt-}' ); + + let result = remoteTagsGetSync(); + if( result.exitCode === 0 ) + return result; + + if( _.strHas( result.output, /(C|c)ould not resolve host/ ) && o.attempt > 1 ) + return retry(); + else + throw _.errOnce( `Exit code : ${result.exitCode}\n`, result.output ); + } + + /* */ + + function remoteTagsGetSync() + { + return _.process.start + ({ + execPath : 'git ls-remote --tags --refs', + currentPath : o.localPath, + mode : 'spawn', + sync : 1, + throwingExitCode : 0, + outputCollecting : 1, + // verbosity : o.verbosity - 1, + logger : _.logger.relativeMaybe( o.logger, -1 ), + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + }) + } + + /* */ + + function checkBranches( got ) + { + if( got && !o.detailing ) + return got; + + let startOptions = + { + execPath : 'git for-each-ref', + args : + [ + 'refs/heads', + `--format={ "branch" : "%(refname:short)", "upstream" : "%(upstream)" }` + ] + }; + + return start( startOptions ) + .then( ( got ) => + { + let output = _.strSplitNonPreserving({ src : got.output, delimeter : '\n' }); + let branches = output.map( ( src ) => JSON.parse( src ) ); + let explanation = []; + + result.unpushedBranches = ''; + + for( let i = 0; i < branches.length; i++ ) + { + let record = branches[ i ]; + + _.assert( _.strIs( record.upstream ) ); + + if( /\(HEAD detached at .+\)/.test( record.branch ) ) + continue; + if( record.upstream.length ) + continue; + + explanation.push( `[new branch] ${record.branch} -> ?` ); + } + + if( explanation.length ) + result.unpushedBranches += explanation.join( '\n' ); + + return result.unpushedBranches; + }) + } + + /* - */ + + function unpushedCommitsCheck( got ) + { + if( got && !o.detailing ) + return got; + + return start( 'git branch -vv' ) + .then( ( got ) => + { + + let match = got.output.match( /^.*\[.*ahead .*\].*$/gm ); + result.unpushedCommits = ''; + if( match ) + { + match = _.str.lines.strip( match ); + result.unpushedCommits = match.join( '\n' ); + } + + return result.unpushedCommits; + }) + } +} + +statusLocal_body.uncommittedGroup = +[ + 'uncommittedUntracked', + 'uncommittedAdded', + 'uncommittedChanged', + 'uncommittedDeleted', + 'uncommittedRenamed', + 'uncommittedCopied', + 'uncommittedIgnored', + 'uncommittedUnstaged', + 'conflicts' +] + +statusLocal_body.unpushedGroup = +[ + 'unpushedCommits', + 'unpushedTags', + 'unpushedBranches', +] + +var defaults = statusLocal_body.defaults = Object.create( null ); + +defaults.localPath = null; +defaults.sync = 1; +defaults.logger = 0; +defaults.attempt = 2; +defaults.attemptDelay = 250; + +defaults.uncommitted = null; +defaults.uncommittedUntracked = null; +defaults.uncommittedAdded = null; +defaults.uncommittedChanged = null; +defaults.uncommittedDeleted = null; +defaults.uncommittedRenamed = null; +defaults.uncommittedCopied = null; +defaults.uncommittedIgnored = 0; +defaults.uncommittedUnstaged = null; + +defaults.unpushed = null; +defaults.unpushedCommits = null; +defaults.unpushedTags = null; +defaults.unpushedBranches = null; + +defaults.conflicts = null; + +defaults.detailing = 0; +defaults.explaining = 0; + +let statusLocal = _.routine.uniteCloning_replaceByUnite( statusLocal_head, statusLocal_body ); + +// + +/* + additional check for branch + git reflog --pretty=format:"%H, %D" + if branch is not listed in `git branch` but exists in output of reflog, then branch was deleted +*/ + +function statusRemote_head( routine, args ) +{ + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { localPath : o } + + _.routine.options_( routine, o ); + _.assert( arguments.length === 2 ); + _.assert( args.length === 1, 'Expects single argument' ); + _.assert( _.strDefined( o.localPath ) ); + _.assert( _.strDefined( o.version ) || o.version === _.all || o.version === null, 'Expects {-o.version-} to be: null/str/_.all, but got:', o.version ); + + for( let k in o ) + if( o[ k ] === null && k !== 'version' ) + /* aaa Vova: should we just use something else for version instead of null? */ /* Dmytro : resolved in common conversation */ + o[ k ] = true; + + return o; +} + +// + +function statusRemote_body( o ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + let ready = new _.Consequence(); + let start = _.process.starter + ({ + currentPath : o.localPath, + mode : 'shell', + sync : 0, + deasync : o.sync, + throwingExitCode : 0, + outputCollecting : 1, + outputPiping : 0, + inputMirroring : 0, + stdio : [ 'pipe', 'pipe', 'ignore' ], + logger : _.logger.relativeMaybe( o.logger, -1 ), + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + ready, + }); + + let result = + { + remoteCommits : null, + remoteBranches : null, + remoteTags : null, + status : null + } + + if( !o.remoteCommits && !o.remoteBranches && !o.remoteTags ) + { + ready.take( result ); + return end(); + } + + ready.take( null ); + + let remotes, tags, heads, output; + let status = []; + let version = o.version; + + if( o.version === null ) + { + start( 'git rev-parse --abbrev-ref HEAD' ) + ready.then( ( got ) => + { + version = _.strStrip( got.output ); + if( version === 'HEAD' ) + throw _.err( `Can't determine current branch: local repository is in detached state` ); + return null; + }) + } + + /* aaa : for Dmytro : ask */ /* Dmytro : asked, temporary mistakes */ + start( 'git ls-remote' ) /* prints list of remote tags and branches */ + ready.then( parse ) + start( 'git show-ref --heads --tags -d' ) /* prints list of local tags and branches */ + ready.then( ( got ) => + { + output = got.output; + return null; + }) + + + if( o.remoteBranches ) + ready.then( branchesCheck ) + if( o.remoteCommits ) + ready.then( commitsCheck ) + if( o.remoteTags ) + ready.then( tagsCheck ) + + ready.finally( ( err, got ) => + { + if( err ) + throw _.err( err, '\nFailed to check if remote repository has changes' ); + statusMake(); + return result; + }) + + /* */ + + return end(); + + /* - */ + + function end() + { + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + } + + /* */ + + function parse( arg ) + { + remotes = _.strSplitNonPreserving({ src : arg.output, delimeter : '\n' }); + remotes = remotes.map( ( src ) => _.strSplitNonPreserving({ src, delimeter : /\s+/ }) ); + remotes = remotes.slice( 1 ); + + /* aaa : for Dmytro : bad format of comments! */ /* Dmytro : formatted */ + /* remote heads */ + heads = remotes.filter( ( r ) => + { + if( version === _.all ) + return _.strBegins( r[ 1 ], 'refs/heads' ) + return _.strBegins( r[ 1 ], `refs/heads/${version}` ) + }); + + /* remote tags */ + tags = remotes.filter( ( r ) => _.strBegins( r[ 1 ], 'refs/tags' ) ) + + return null; + } + + function branchesCheck( got ) + { + result.remoteBranches = ''; + + for( var h = 0; h < heads.length ; h++ ) + { + let ref = heads[ h ][ 1 ]; + + if( !_.strHas( output, ref ) ) /* looking for remote branch in list of local branches */ + { + if( result.remoteBranches ) + result.remoteBranches += '\n'; + result.remoteBranches += ref; + _.arrayAppendOnce( status, 'List of unpulled remote branches:' ) + status.push( ' ' + ref ); + } + } + + return result.remoteBranches + } + + /* */ + + function commitsCheck( got ) + { + result.remoteCommits = ''; + + if( got && !o.detailing ) + { + if( heads.length ) + result.remoteCommits = _.maybe; + return got; + } + + if( !heads.length ) + return result.remoteCommits; + + let con = _.take( null ); + + _.each( heads, ( head ) => + { + let hash = head[ 0 ]; + let ref = head[ 1 ]; + // let execPath = `git branch --contains ${hash} --quiet --format=%(refname)`; + let execPath = `git for-each-ref refs/heads --contains ${hash} --format=%(refname)`; + + if( !_.strHas( output, ref ) ) /* skip if branch is not downloaded */ + return; + + con.then( () => + { + return start({ execPath, ready : null, mode : 'spawn' }) + }) + .then( ( got ) => + { + if( !_.strHas( got.output, ref ) ) + { + if( result.remoteCommits ) + result.remoteCommits += '\n'; + result.remoteCommits += ref; + _.arrayAppendOnce( status, 'List of remote branches that have new commits:' ) + status.push( ' ' + ref ); + } + return result.remoteCommits; + }) + }) + + return con; + } + + /* */ + + function tagsCheck( got ) + { + result.remoteTags = ''; + + if( got && !o.detailing ) + { + if( tags.length ) + result.remoteTags = _.maybe; + return got; + } + + for( var h = 0; h < tags.length ; h++ ) + { + let tag = tags[ h ][ 1 ]; + + if( !_.strHas( output, tag ) ) /* looking for remote tag in list of local tags */ + { + if( result.remoteTags ) + result.remoteTags += '\n'; + result.remoteTags += tag; + _.arrayAppendOnce( status, 'List of unpulled remote tags:' ) + status.push( ' ' + tag ); + } + } + + return result.remoteTags; + } + + /* */ + + function statusMake() + { + result.status = status.join( '\n' ); + + for( let k in result ) + if( _.strIs( result[ k ] ) ) + { + if( !o.explaining ) + result[ k ] = !!result[ k ]; + else if( o.detailing && !result[ k ] ) + result[ k ] = false; + } + } + + /* */ + +} + +var defaults = statusRemote_body.defaults = Object.create( null ); +defaults.localPath = null; +defaults.logger = 0; +defaults.version = _.all; +defaults.remoteCommits = null; +defaults.remoteBranches = 0; +defaults.remoteTags = null; +defaults.detailing = 0; +defaults.explaining = 0; +defaults.sync = 1; + +// + +let statusRemote = _.routine.uniteCloning_replaceByUnite( statusRemote_head, statusRemote_body ); + +// + +function status_head( routine, args ) +{ + let o = args[ 0 ]; + + if( !_.mapIs( o ) ) + o = { localPath : o } + + _.routine.options_( routine, o ); + _.assert( arguments.length === 2 ); + _.assert( args.length === 1, 'Expects single argument' ); + _.assert( _.strDefined( o.localPath ) ); + + if( o.unpushed === null ) + o.unpushed = o.local; + if( o.uncommitted === null ) + o.uncommitted = o.local; + + if( o.remoteCommits === null ) + o.remoteCommits = o.remote; + if( o.remoteBranches === null ) + o.remoteBranches = o.remote; + if( o.remoteTags === null ) + o.remoteTags = o.remote; + + return o; +} + +// + +function status_body( o ) +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let localReady = null; + let o2 = _.mapOnly_( null, o, self.statusLocal.defaults ); + o2.sync = 0; + localReady = self.statusLocal.call( this, o2 ); + + let remoteReady = null; + let o3 = _.mapOnly_( null, o, self.statusRemote.defaults ); + o3.sync = 0; + remoteReady = self.statusRemote.call( this, o3 ); + + let ready = _.Consequence.And( localReady, remoteReady ) + .finally( ( err, arg ) => + { + if( err ) + { + let errors = _.arrayAppendArrayOnce( localReady.errorsGet().slice(), remoteReady.errorsGet() ); + _.each( errors, ( err ) => _.errAttend( err ) ) + throw _.err.apply( _, errors ); + } + + let result = _.props.extend( null, arg[ 0 ] || {}, arg[ 1 ] || {} ); + + if( arg[ 0 ] ) + { + result.local = arg[ 0 ].status; + if( arg[ 0 ].status !== null ) + result.status = arg[ 0 ].status; + } + + + if( arg[ 1 ] ) + { + result.remote = arg[ 1 ].status; + if( arg[ 1 ].status !== null ) + { + if( !result.status ) + { + result.status = arg[ 1 ].status; + return result; + } + + if( o.explaining && arg[ 1 ].status ) + if( arg[ 0 ] && arg[ 0 ].status ) + result.status += '\n' + arg[ 1 ].status; + } + } + + + return result; + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +_.assert( _.routineIs( statusLocal.body ) ); +_.routineExtend( status_body, statusLocal.body ) +_.assert( _.routineIs( statusRemote.body ) ); +_.routineExtend( status_body, statusRemote.body ) + +var defaults = status_body.defaults; +defaults.localPath = null; +defaults.remote = 1; +defaults.local = 1; +defaults.detailing = 0; +defaults.explaining = 0; + +let status = _.routine.uniteCloning_replaceByUnite( status_head, status_body ); + +// + +/* + qqq : extend and cover please +*/ + +function statusFull( o ) +{ + let result = Object.create( null ); + + o = _.routine.options_( statusFull, arguments ); + + result.isRepository = false; + if( o.prs ) + o.prs = []; + + if( !o.localPath && o.insidePath ) + o.localPath = _.git.localPathFromInside( o.insidePath ); + + if( !o.localPath ) + return result; + + result.isRepository = true; + + _.assert( _.strIs( o.localPath ), 'Expects local path of inside path to deduce local path' ); + + if( !o.remotePath ) + o.remotePath = _.git.remotePathFromLocal( o.localPath ); + + let statusReady = _.take( null ); + let prsReady = _.take( null ); + + if( o.remotePath ) + { + let o2 = _.mapOnly_( null, o, status.defaults ); + o2.sync = 0; + statusReady = _.git.status( o2 ) + + if( o.prs ) + prsReady = _.repo.pullList({ remotePath : o.remotePath, throwing : 0, sync : 0, token : o.token }); + } + + let ready = _.Consequence.AndKeep( statusReady, prsReady ) + .finally( ( err, arg ) => + { + if( err ) + throw _.err( err ); + let status = arg[ 0 ]; + statusAdjust( status, arg[ 1 ] ? arg[ 1 ].result.elements : null ); + return result; + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + + /* */ + + function statusAdjust( status, prs ) + { + _.props.extend( result, status ); + + result.prs = prs; + if( !result.prs ) + result.prs = o.prs ? _.maybe : null; + + if( prs && !prs.length && !result.result ) + { + if( result.status === null ) + result.status = false; + return result; + } + + if( prs && prs.length ) + { + if( o.explaining ) + { + let prsExplanation= `Has ${prs.length} opened pull request(s)`; + + if( result.status ) + result.status += '\n' + prsExplanation; + else + result.status = prsExplanation; + + } + else + { + result.status = true; + } + } + + return result; + } +} + +statusFull.defaults = +{ + insidePath : null, + localPath : null, + remotePath : null, + local : 1, + remote : 1, + prs : 1, + detailing : 1, + explaining : 1, + sync : 1, + token : null, +}; + +_.props.supplement( statusFull.defaults, status.defaults ); + +// + +function hasLocalChanges() +{ + let self = this; + let result = self.statusLocal.apply( this, arguments ); + + if( _.consequenceIs( result ) ) + return result.then( end ); + return end( result ); + + function end( result ) + { + _.assert( result.status !== undefined ); + + if( _.boolIs( result.status ) ) + return result.status; + if( _.strIs( result.status ) && result.length ) + return true; + + return false; + } +} + +_.routineExtend( hasLocalChanges, statusLocal ) + +// + +function hasRemoteChanges() +{ + let self = this; + + let result = self.statusRemote.apply( this, arguments ); + + if( _.consequenceIs( result ) ) + return result.then( end ); + return end( result ); + + function end( result ) + { + _.assert( result.status !== undefined ); + + if( _.boolIs( result.status ) ) + return result.status; + if( _.strIs( result.status ) && result.length ) + return true; + + return false; + } +} + +_.routineExtend( hasRemoteChanges, statusRemote ) + +// + +function hasChanges() +{ + let result = status.apply( this, arguments ); + + if( _.consequenceIs( result ) ) + return result.then( end ); + return end( result ); + + function end( result ) + { + _.assert( result.status !== undefined ); + + if( _.boolIs( result.status ) ) + return result.status; + if( _.strIs( result.status ) && result.length ) + return true; + + return false; + } +} + +_.routineExtend( hasChanges, status ) + +// + +function repositoryHasTag( o ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + _.routine.options_( repositoryHasTag, o ); + _.assert( _.strDefined( o.localPath ) ); + _.assert( _.strDefined( o.tag ) ); + _.assert( o.remotePath === null || _.strDefined( o.remotePath ) || _.mapIs( o.remotePath ) ); + _.assert( !!o.local || !!o.remote ); + + let ready = _.take( null ); + let start = _.process.starter + ({ + sync : 0, + deasync : 0, + outputCollecting : 1, + mode : 'shell', + currentPath : o.localPath, + throwingExitCode : 0, + inputMirroring : 0, + outputPiping : 0, + }); + + ready.then( () => + { + if( !self.isRepository({ localPath : o.localPath }) ) + throw _.err( `Provided {-o.localPath-}: ${_.strQuote( o.localPath )} doesn't contain a git repository.` ); + return null; + }) + + if( o.local ) + ready.then( checkLocal ); + + if( o.remote ) + ready.then( checkRemote ); + + ready.catch( ( err ) => + { + _.errAttend( err ); + throw _.err( 'Failed to obtain tags and heads from remote repository.\n', err ); + }) + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + + /* */ + + function checkLocal() + { + // return start( `git show-ref --heads --tags` ) + // .then( hasTag ); + return start( `git show-ref --heads --tags -- ${o.tag}` ) /* Dmytro : fast searching for tag - result empty string or tag */ + .then( ( got ) => + { + if( got.output !== '' ) + { + let splits = _.strSplitNonPreserving({ src : got.output, delimeter : /\s+/, stripping : 1 }); + return o.returnVersion ? splits[ 0 ] : true; + } + return false; + }); + } + + function checkRemote( result ) + { + if( result ) + return result; + + // let remotePath = o.remotePath ? self.pathParse( o.remotePath ).remoteVcsPath : 'origin'; + let remotePath = 'origin'; + if( o.remotePath ) + { + let parsed = _.git.path.parse({ remotePath : o.remotePath, full : 1, atomic : 0 }); + let remoteVcsPathParsed = _.mapBut_( null, parsed, { localVcsPath : null, tag : null, hash : null, query : null } ); + remoteVcsPathParsed.longPath = _.strRemoveEnd( parsed.longPath, '/' ); + let remoteVcsPath = _.git.path.str( remoteVcsPathParsed ); + remotePath = _.git.path.nativize( remoteVcsPath ); + } + + /* Dmytro : searching tag, the tag can be a glob, decrease volume of output */ + return start( `git ls-remote --tags --refs --heads ${remotePath} -- ${o.tag}` ) + .then( hasTag ) + + // let remotePath = o.remotePath ? self.pathParse( o.remotePath ).remoteVcsPath : ''; + // return start( `git ls-remote --tags --refs --heads ${remotePath}` ) + // .then( hasTag ) + } + + function hasTag( got ) + { + let possibleTag = `refs/tags/${o.tag}`; + let possibleHead = `refs/heads/${o.tag}`; + + let refs = _.strSplitNonPreserving({ src : got.output, delimeter : '\n' }); + refs = refs.map( ( src ) => _.strSplitNonPreserving({ src, delimeter : /\s+/, stripping : 1 }) ); + + for( let i = 0, l = refs.length; i < l; i++ ) + if( refs[ i ][ 1 ] === possibleTag || refs[ i ][ 1 ] === possibleHead ) + return o.returnVersion ? refs[ i ][ 0 ] : true; + + return false; + } +} + +repositoryHasTag.defaults = +{ + localPath : null, + remotePath : null, + tag : null, + local : 1, + remote : 1, + returnVersion : 0, + sync : 1 +}; + +// + +function repositoryHasVersion( o ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + _.routine.options_( repositoryHasVersion, o ); + _.assert( _.strDefined( o.localPath ) ); + _.assert( _.strDefined( o.version ) ); + + let ready = _.take( null ); + let start = _.process.starter + ({ + sync : 0, + deasync : 0, + outputCollecting : 1, + mode : 'spawn', + currentPath : o.localPath, + throwingExitCode : 0, + inputMirroring : 0, + outputPiping : 0, + }); + + ready.then( () => + { + if( !self.isRepository({ localPath : o.localPath }) ) + throw _.err( `Provided {-o.localPath-}: ${_.strQuote( o.localPath )} doesn't contain a git repository.` ) + + // if( !_.git.versionIsCommitHash( _.mapOnly_( null, o, _.git.versionIsCommitHash.defaults )) ) /* Dmytro : the routine `versionIsCommitHash` searches a hash in local repository, but the hash can be on remote repository */ + // throw _.err( `Provided version: ${_.strQuote( o.version ) } is not a commit hash.` ) + + if( !_.git.stateIsHash( `#${ o.version }` ) ) + throw _.err( `Provided version: ${_.strQuote( o.version ) } is not a commit hash.` ) + + return null; + }) + + if( o.local ) + ready.then( checkLocal ); + + if( o.remote ) + ready.then( checkRemote ); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + + /* - */ + + function checkLocal() + { + let con = start({ execPath : `git cat-file -t ${o.version}` }) + con.then( ( got ) => got.exitCode === 0 ); + return con; + } + + /* - */ + + function checkRemote( result ) + { + if( result ) + return result; + + let ready = _.take( null ); + + start({ execPath : `git fetch -v -n --dry-run`, throwingExitCode : 1, ready }) + + ready.then( ( got ) => + { + // if( _.strHas( got.output, /.+\.\..+/ ) ) + /* + Dmytro : the output has range of commits that will be fetched, it is more convenient regexp than the previous one. + The regexp does not include strings like : `From ../repo` + */ + if( _.strHas( got.output, /[a-hA-H0-9]+\.\.[a-hA-H0-9]+/ ) ) + throw _.err( `Local repository at ${o.localPath} is not up-to-date with remote. Please run "git fetch" and try again.` ) + return true; + }) + + start({ execPath : `git branch -r --contains ${o.version}`, ready }) + + ready.then( ( got ) => + { + if( got.exitCode !== 0 ) + return false; + let lines = _.strSplitNonPreserving({ src : got.output, delimeter : /\s+/, stripping : 1 }); + return lines.length >= 1; + }) + + return ready; + } +} + +repositoryHasVersion.defaults = +{ + localPath : null, + version : null, + local : 1, + remote : 0, + sync : 1 +} + +// + +function repositoryTagToVersion( o ) +{ + let self = this; + _.routine.options_( repositoryTagToVersion, o ); + _.assert( arguments.length === 1 ); + let o2 = _.props.extend( null, o, { returnVersion : 1 } ); + return self.repositoryHasTag( o2 ); +} + +repositoryTagToVersion.defaults = +{ + localPath : null, + remotePath : null, + tag : null, + local : 1, + remote : 1, + sync : 1 +}; + +// + +function repositoryVersionToTag( o ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + _.routine.options_( repositoryVersionToTag, o ); + _.assert( _.strDefined( o.localPath ) ); + _.assert( _.strDefined( o.version ) ); + _.assert( o.remotePath === null || _.strDefined( o.remotePath ) ); + _.assert( !!o.local || !!o.remote ); + + let ready = _.take( null ); + let start = _.process.starter + ({ + sync : 0, + deasync : 0, + outputCollecting : 1, + mode : 'shell', + currentPath : o.localPath, + throwingExitCode : 0, + inputMirroring : 0, + outputPiping : 0, + }); + + ready.then( () => + { + if( !self.isRepository({ localPath : o.localPath }) ) + throw _.err( `Provided {-o.localPath-}: ${_.strQuote( o.localPath )} doesn't contain a git repository.` ) + return null; + }) + + if( o.local ) + ready.then( checkLocal ); + + if( o.remote ) + ready.then( checkRemote ); + + ready.catch( ( err ) => + { + _.errAttend( err ); + throw _.err( 'Failed to obtain tags and heads from remote repository.\n', err ); + }) + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + + /* */ + + function checkLocal() + { + // return start( `git show-ref --heads --tags` ) + return start( `git show-ref --dereference --heads --tags` ) + .then( hasTag ) + } + + function checkRemote( result ) + { + if( result ) + return result; + + // let remotePath = o.remotePath ? self.pathParse( o.remotePath ).remoteVcsPath : ''; + let remotePath = ''; + if( o.remotePath ) + { + let parsed = _.git.path.parse({ remotePath : o.remotePath, full : 1, atomic : 0 }); + let remoteVcsPathParsed = _.mapBut_( null, parsed, { localVcsPath : null, tag : null, hash : null, query : null } ); + remoteVcsPathParsed.longPath = _.strRemoveEnd( parsed.longPath, '/' ); + let remoteVcsPath = _.git.path.str( remoteVcsPathParsed ); + remotePath = _.git.path.nativize( remoteVcsPath ); + } + + return start( `git ls-remote --tags --heads ${ remotePath }` ) + .then( hasTag ) + + // return start( `git ls-remote --tags --heads ${remotePath}` ) + // .then( hasTag ) + } + + function hasTag( got ) + { + let headsPrefix = 'refs/heads/'; + let tagsPrefix = 'refs/tags/'; + let tagsPostfix = '^{}'; + + let refs = _.strSplitNonPreserving({ src : got.output, delimeter : '\n' }); + refs = refs.map( ( src ) => _.strSplitNonPreserving({ src, delimeter : /\s+/, stripping : 1 }) ); + + let result = []; + + for( let i = 0, l = refs.length; i < l; i++ ) + if( _.strBegins( refs[ i ][ 0 ], o.version ) ) + { + let tag = refs[ i ][ 1 ]; + if( _.strBegins( tag, headsPrefix ) ) + tag = _.strRemoveBegin( tag, headsPrefix ) + else if( _.strBegins( tag, tagsPrefix ) ) + tag = _.strRemoveBegin( tag, tagsPrefix ) + + if( _.strEnds( tag, tagsPostfix ) ) + tag = _.strRemoveEnd( tag, tagsPostfix ); + + _.arrayAppendOnce( result, tag ); + } + + if( result.length === 1 ) + return result[ 0 ]; + + return result; + } +} + +repositoryVersionToTag.defaults = +{ + localPath : null, + remotePath : null, + version : null, + local : 1, + remote : 1, + sync : 1 +}; + +// + +function exists( o ) +{ + let self = this; + + _.routine.options_( exists, o ); + _.assert( arguments.length === 1 ); + _.assert( _.strDefined( o.local ) || _.strDefined( o.remote ) ); + + let ready = _.take( null ); + + if( o.local ) + ready.then( checkLocal ) + + if( o.remote ) + ready.then( checkRemote ) + + ready.catch( ( err ) => + { + throw _.err( 'Failed to obtain tags and heads from remote repository. Reason:\n', err ); + }) + + if( o.sync ) + return ready.sync(); + + return ready; + + /* - */ + + function checkLocal() + { + let local = parse( o.local ); + if( !local ) + throw _.err( `Failed to determine kind of {o.local}. Expects "!tag" or "#version", but got:${o.local}` ); + + if( local.tag ) + return self.repositoryHasTag + ({ + localPath : o.localPath, + local : 1, + remote : 0, + tag : local.tag, + sync : o.sync + }) + + return self.repositoryHasVersion + ({ + localPath : o.localPath, + version : local.version, + sync : o.sync + }) + } + + /* - */ + + function checkRemote( result ) + { + if( result ) + return result; + + let remote = parse( o.remote ); + if( !remote ) + throw _.err( `Failed to determine kind of {o.remote}. Expects "!tag" or "#version", but got:${o.remote}` ); + + if( remote.tag ) + return self.repositoryHasTag + ({ + localPath : o.localPath, + remotePath : o.remotePath, + local : 0, + remote : 1, + returnVersion : o.returnVersion, + tag : remote.tag, + sync : o.sync + }); + + return self.repositoryHasVersion + ({ + localPath : o.localPath, + local : 0, + remote : 1, + version : remote.version, + sync : o.sync + }); + + /* qqq3: Find how to check if remote has commit */ + /* Dmytro : the first way is fetching of all commits and searching for desired ( implemented above ) + + Also, it can be checked by specific API of git provider. + For example, for github.com we can use Rest API of Github or module `@octokit/core` instead. + */ + // _.assert( 0, 'Case remote:#version is not implemented' ); + // + // return true; + } + + /* - */ + + function parse( src ) + { + if( _.strBegins( src, '!' ) ) + return { tag : _.strRemoveBegin( src, '!' ) }; + else if( _.strBegins( src, '#' ) ) + return { version : _.strRemoveBegin( src, '#' ) }; + } +} + +exists.defaults = +{ + localPath : null, + remotePath : null, + local : null, + remote : null, + returnVersion : 0, + sync : 1 +} + +// + +// /** +// * Routine tagMake() makes tag for current commit. +// * +// * @example +// * // make tag `v0.1` if script run in git repository +// * let tag = _.git.tagMake +// * ({ +// * localPath : _.path.current(), +// * tag : 'v0.1', +// * description : 'version 0.1', +// * }); +// * +// * @param { Aux } o - Options map. +// * @param { String } o.localPath - Path to git repository on hard drive. +// * @param { String } o.tag - Name of tag. +// * @param { String } o.description - Description of tag. +// * @param { BoolLike } o.light - Enable lightweight tags. Default is 0. +// * @param { BoolLike } o.deleting - Enable deleting of duplicated tags. Default is 1. +// * @param { BoolLike } o.sync - Enable synchronous execution of code. Default is 1. +// * @returns { Consequence|Aux } - Returns map like object with results of Process execution +// * or Consequence that handle such Process. +// * @function tagMake +// * @throws { Error } If arguments.length is not equal to 1. +// * @throws { Error } If options map {-o-} has extra options. +// * @throws { Error } If {-o.localPath-} is not a String with defined length. +// * @throws { Error } If {-o.tag-} is not a String with defined length. +// * @throws { Error } If added two tags with identical names to single commit and {-o.deleting-} is false. +// * @namespace wTools.git +// * @module Tools/mid/GitTools +// */ +// +// function tagMake( o ) +// { +// let ready; +// +// _.assert( arguments.length === 1, 'Expects options map {-o-}' ); +// _.routine.options_( tagMake, arguments ); +// +// let start = _.process.starter +// ({ +// sync : 0, +// deasync : 0, +// outputCollecting : 1, +// mode : 'shell', +// currentPath : o.localPath, +// throwingExitCode : 1, +// inputMirroring : 0, +// outputPiping : 0, +// }); +// +// if( o.deleting ) +// { +// +// ready = _.git.repositoryHasTag +// ({ +// localPath : o.localPath, +// tag : o.tag, +// local : 1, +// remote : 0, +// sync : 0, +// }); +// +// ready.then( ( has ) => +// { +// if( has ) +// return start( `git tag -d ${o.tag}` ); +// return has; +// }) +// +// } +// else +// { +// ready = _.take( null ); +// } +// +// ready.then( () => +// { +// if( o.light ) +// return start( `git tag ${o.tag}` ); +// else +// return start( `git tag -a ${o.tag} -m "${o.description}"` ); +// }); +// +// // if( got.exitCode !== 0 || got.output && _.strHas( got.output, 'refs/' ) ) +// // return false; +// +// if( o.sync ) +// { +// ready.deasync(); +// return ready.sync(); +// } +// +// return ready; +// } +// +// tagMake.defaults = +// { +// localPath : null, +// tag : null, +// description : '', +// light : 0, +// deleting : 1, +// sync : 1, +// }; + +// -- +// hook +// -- + +function hookRegister( o ) +{ + let provider = _.fileProvider; + let path = _.git.path; + // let path = provider.path; + + _.assert( arguments.length === 1 ); + _.routine.options_( hookRegister, o ); + + if( o.repoPath === null ) + o.repoPath = path.current(); + + _.assert( _.strDefined( o.repoPath ) ); + + try + { + check(); + hookLauncherMake(); + register(); + setPermissions(); + return true; + } + catch( err ) + { + if( o.throwing ) + throw _.err( err ); + return null; + } + + /* */ + + function check() + { + + if( !provider.fileExists( o.filePath ) ) + throw _.err( 'Source handler path doesn\'t exit:', o.filePath ) + + if( !provider.fileExists( path.join( o.repoPath, '.git' ) ) ) + throw _.err( 'No git repository found at:', o.filePath ); + + if( !_.longHas( KnownHooks, o.hookName ) ) + throw _.err( 'Unknown git hook:', o.hookName ); + + let handlerNamePattern = new RegExp( `^${o.hookName}\\..*` ); + if( !handlerNamePattern.test( o.handlerName ) ) + throw _.err( 'Handler name:', o.handlerName, 'should match the pattern ', handlerNamePattern.toString() ) + + if( !o.rewriting ) + if( provider.fileExists( path.join( o.repoPath, '.git/hooks', o.handlerName ) ) ) + throw _.err( 'Handler:', o.handlerName, 'for git hook:', o.hookName, 'is already registered. Enable option {-o.rewriting-} to rewrite existing handler.' ); + + if( o.handlerName === o.hookName || o.handlerName === o.hookName + '.was' ) + throw _.err( 'Rewriting of original git hook script', o.handlerName, 'is not allowed.' ); + + } + + /* */ + + function hookLauncherMake() + { + let specialComment = 'This script is generated by utility willbe'; + + let originalHandlerPath = path.join( o.repoPath, '.git/hooks', o.hookName ); + + if( provider.fileExists( originalHandlerPath ) ) + { + let read = provider.fileRead( originalHandlerPath ); + + if( _.strHas( read, specialComment ) ) + return true + + let originalHandlerPathDst = originalHandlerPath + '.was'; + if( provider.fileExists( originalHandlerPathDst ) ) + throw _.err( 'Can\'t rename original git hook file:', originalHandlerPath, '. Path :', originalHandlerPathDst, 'already exists.' ); + provider.fileRename( originalHandlerPathDst, originalHandlerPath ); + } + + _.assert( !provider.fileExists( originalHandlerPath ) ); + + let hookLauncher = hookLauncherCode(); + + provider.fileWrite( originalHandlerPath, hookLauncher ); + + /* */ + + function hookLauncherCode() + { + return `#!/bin/bash + + #${specialComment} + #Based on + #https://github.com/henrik/dotfiles/blob/master/git_template/hooks/pre-commit + + hook_dir=$(dirname $0) + hook_name=$(basename $0) + + if [[ -d $hook_dir ]]; then + stdin=$(cat /dev/stdin) + + if stat -t $hook_dir/$hook_name.* >/dev/null 2>&1; then + for hook in $hook_dir/$hook_name.*; do + echo "Running $hook hook" + echo "$stdin" | $hook "$@" + + exit_code=$? + + if [ $exit_code != 0 ]; then + exit $exit_code + fi + done + fi + fi + + exit 0 + ` + } + } + + /* */ + + function register() + { + let handlerPath = path.join( o.repoPath, '.git/hooks', o.handlerName ); + let sourceCode = provider.fileRead( o.filePath ); + provider.fileWrite( handlerPath, sourceCode ); + } + + function setPermissions() /* aaa : use _.fileProvider.* routine */ /* Dmytro : used, the mask 0o754 is equivalent to ug+x */ + { + + const files = provider.filesFind + ({ + filePath : _.git.path.join( o.repoPath, '.git/hooks' ), + // filePath : provider.path.join( o.repoPath, '.git/hooks' ), + outputFormat : 'absolute', + }); + _.each( files, ( filePath ) => provider.rightsWrite({ filePath, setRights : 0o754 }) ); + + // if( process.platform !== 'win32' ) + // _.process.start + // ({ + // execPath : 'chmod ug+x .git/hooks/*', + // currentPath : o.repoPath, + // sync : 1, + // inputMirroring : 0, + // outputPiping : 1 + // }) + } +} + +hookRegister.defaults = +{ + repoPath : null, + filePath : null, + handlerName : null, + hookName : null, + throwing : 1, + rewriting : 0 +} + +// + +function hookUnregister( o ) +{ + let provider = _.fileProvider; + let path = _.git.path; + // let path = provider.path; + + _.assert( arguments.length === 1 ); + _.routine.options_( hookUnregister, o ); + + if( o.repoPath === null ) + o.repoPath = path.current(); + + _.assert( _.strDefined( o.repoPath ) ); + + try + { + if( _.longHas( KnownHooks, o.handlerName ) ) + if( !o.force ) + throw _.err( 'Removal of original git hook handler is not allowed. Please enable option {-o.force-} to delete it.' ) + + let handlerPath = path.join( o.repoPath, '.git/hooks', o.handlerName ); + + if( !provider.fileExists( handlerPath ) ) + throw _.err( 'Git hook handler:', handlerPath, 'doesn\'t exist.' ) + + provider.fileDelete + ({ + filePath : handlerPath, + sync : 1, + throwing : 1 + }); + + return true; + } + catch( err ) + { + if( o.throwing ) + throw _.err( err ); + return null; + } +} + +hookUnregister.defaults = +{ + repoPath : null, + handlerName : null, + force : 0, + throwing : 1 +} + +// + +function hookPreservingHardLinksRegister( repoPath ) +{ + let provider = _.fileProvider; + let path = provider.path; /* Dmytro : should be provider path */ + + _.assert( arguments.length === 1 ); + _.assert( _.strDefined( repoPath ) ); + + // let toolsPath = path.resolve( __dirname, '../../../../../wtools/Tools.s' ); + let toolsPath = _.module.toolsPathGet(); + _.sure( provider.fileExists( toolsPath ) ); + toolsPath = path.nativize( toolsPath ); + + // let sourceCode = '#!/usr/bin/env node\n' + restoreHardLinksCode(); + // let tempPath = _.process.tempOpen({ sourceCode }); + let routineCode = '#!/usr/bin/env node\n' + restoreHardLinksCode(); + let tempPath = path.tempOpen(); /* xxx : review */ + let name = 'archivePerform'; + let filePath = path.join( tempPath, name ); + + _.program.make + ({ + // sourceCode, + routineCode, + name, + filePath, + // filePath/*programPath*/ : filePath, + }); + + try + { + _.git.hookRegister + ({ + repoPath, + filePath, + // filePath : tempPath, + handlerName : 'post-merge.restoreHardLinks', + hookName : 'post-merge', + throwing : 1, + rewriting : 0 + }) + } + catch( err ) + { + throw _.err( err ); + } + finally + { + path.tempClose( tempPath ); + } + + return true; + + /* */ + + function restoreHardLinksCode() + { + let sourceCode = + ` + function archivePerform() + { + try + { + try + { + var _ = require( "${ _.strEscape( toolsPath) }" ); + } + catch( err ) + { + var _ = require( 'wTools' ); + } + _.include( 'wFilesArchive' ); + } + catch( err ) + { + console.log( err, 'Git post pull hook fails to preserve hardlinks due missing dependency.' ); + return; + } + + let provider = _.FileFilter.Archive(); + provider.archive.basePath = _.path.join( __dirname, '../..' ); + provider.archive.fileMapAutosaving = 0; + provider.archive.filesUpdate(); + provider.archive.filesLinkSame({ consideringFileName : 0 }); + provider.finit(); + provider.archive.finit(); + } + ` + return sourceCode; + } +} + +// + +function hookPreservingHardLinksUnregister( repoPath ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.strDefined( repoPath ) ); + + return _.git.hookUnregister + ({ + repoPath, + handlerName : 'post-merge.restoreHardLinks', + force : 0, + throwing : 1 + }) +} + +// -- +// ignore +// -- + +function ignoreAdd( o ) +{ + let provider = _.fileProvider; + let path = _.git.path; + // let path = provider.path; + + if( arguments.length === 2 ) + o = { insidePath : arguments[ 0 ], pathMap : arguments[ 1 ] } + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.routine.options_( ignoreAdd, o ); + + if( !provider.isDir( o.insidePath ) ) + throw _.err( 'Provided {-o.insidePath-} is not a directory:', _.strQuote( o.insidePath ) ); + + if( !this.insideRepository( o.insidePath ) ) + throw _.err( 'Provided {-o.insidePath-}:', _.strQuote( o.insidePath ), 'is not inside of a git repository.' ); + + let gitignorePath = path.join( o.insidePath, '.gitignore' ); + let records = _.props.keys( o.pathMap ); + + let result = 0; + + if( !records.length ) + return result; + + let gitconfig = []; + + if( provider.fileExists( gitignorePath ) ) + { + gitconfig = provider.fileRead( gitignorePath ); + gitconfig = _.strSplitNonPreserving({ src : gitconfig, delimeter : '\n' }) + } + + result = _.arrayAppendedArrayOnce( gitconfig, records ); + + let data = gitconfig.join( '\n' ); + provider.fileWrite({ filePath : gitignorePath, data, writeMode : 'append' }); + + return result; +} + +var defaults = ignoreAdd.defaults = Object.create( null ); +defaults.insidePath = null; +defaults.pathMap = null; + +// + +function ignoreRemove( o ) +{ + let provider = _.fileProvider; + let path = _.git.path; + // let path = provider.path; + + if( arguments.length === 2 ) + o = { insidePath : arguments[ 0 ], pathMap : arguments[ 1 ] } + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.routine.options_( ignoreRemove, o ); + + let gitignorePath = path.join( o.insidePath, '.gitignore' ); + + if( !provider.fileExists( gitignorePath ) ) + throw _.err( 'Provided .gitignore file doesn`t exist at:', _.strQuote( gitignorePath ) ); + + if( !this.isTerminal( o.insidePath ) ) + throw _.err( 'Provided .gitignore file:', _.strQuote( gitignorePath ), 'is not terminal' ); + + let records = _.props.keys( o.pathMap ); + + if( !records.length ) + return false; + + let gitconfig = provider.fileRead( gitignorePath ); + gitconfig = _.strSplitNonPreserving({ src : gitconfig, delimeter : '\n' }) + + let result = 0; + + if( !gitconfig.length ) + return result; + + result = _.arrayRemovedArrayOnce( gitconfig, records ); + + let data = gitconfig.join( '\n' ); + provider.fileWrite({ filePath : gitignorePath, data, writeMode : 'rewrite' }); + + return result; +} + +_.routineExtend( ignoreRemove, ignoreAdd ); + +// + +function ignoreRemoveAll( o ) +{ + let provider = _.fileProvider; + let path = _.git.path; + // let path = provider.path; + + if( !_.object.isBasic( o ) ) + o = { insidePath : arguments[ 0 ] } + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.routine.options_( ignoreRemoveAll, o ); + + let gitignorePath = path.join( o.insidePath, '.gitignore' ); + if( !provider.fileExists( gitignorePath ) ) + return false; + provider.fileDelete( gitignorePath ); + return true; +} + +var defaults = ignoreRemoveAll.defaults = Object.create( null ); +defaults.insidePath = null; + +// -- +// maker +// -- + +function repositoryInit( o ) +{ + let self = this; + let ready = _.take( null ); + + o = _.routine.options_( repositoryInit, o ); + + let nativeRemotePath = null; + let parsed = null; + let remoteExists = null; + + _.assert( !o.remote || _.strDefined( o.remotePath ), `Expects path to remote repository {-o.remotePath-}, but got ${_.color.strFormat( String( o.remotePath ), 'path' )}` ) + + if( o.remotePath ) + { + o.remotePath = nativeRemotePath = _.git.path.nativize( o.remotePath ); + + parsed = _.git.path.parse({ remotePath : o.remotePath, full : 0, atomic : 0, objects : 1 }); + remoteExists = self.isRepository({ remotePath : o.remotePath, sync : 1 }); + } + + if( o.remote === null ) + o.remote = !!o.remotePath; + if( o.local === null ) + o.local = !!o.localPath; + + let start = _.process.starter + ({ + logger : _.logger.relativeMaybe( o.logger, -1 ), + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + sync : 0, + deasync : 0, + outputCollecting : 1, + mode : 'spawn', + currentPath : o.localPath, + }); + + if( o.remote && !remoteExists ) + ready.then( () => remoteInit() ); + if( o.local ) + ready.then( () => localInit() ); + + ready.finally( ( err, arg ) => + { + if( err ) + { + _.error.attend( err ); + if( o.throwing ) + throw _.err( err, `\nFailed to init git repository remotePath:${_.color.strFormat( String( o.remotePath ), 'path' )}` ); + return null; + } + return arg; + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + + /* */ + + function remoteInit() + { + if( o.logger && o.logger.verbosity > 0 ) + o.logger.log( `Making remote repository ${_.color.strFormat( String( o.remotePath ), 'path' )}` ); + + if( o.dry ) + return true; + + const o2 = _.mapOnly_( null, o, _.repo.repositoryInit.defaults ); + return _.repo.repositoryInit( o2 ) + } + + /* */ + + function localInit() + { + _.assert( _.git.path.is( o.localPath ) && !_.git.path.isGlobal( o.localPath ), () => `Expects local path, but got ${_.color.strFormat( String( o.localPath ), 'path' )}` ); + + o.localPath = _.git.path.canonize( o.localPath ); + + if( _.fileProvider.fileExists( o.localPath ) && !_.fileProvider.isDir( o.localPath ) ) + throw _.err( `Can't clone repository to ${_.color.strFormat( String( o.localPath ), 'path' )}. It is occupied by non-directory.` ); + + if( o.remotePath && remoteExists ) + { + + if( self.isRepository({ localPath : o.localPath }) ) + return localRepositoryRemoteAdd(); + else + return localRepositoryClone(); + + } + else + { + + if( self.isRepository({ localPath : o.localPath }) ) + return localRepositoryRemoteAdd(); + else + return localRepositoryNew(); + + } + } + + /* */ + + function localRepositoryNew() + { + if( o.logger && o.logger.verbosity > 0 ) + o.logger.log( `Making a new local repository at ${_.color.strFormat( String( o.localPath ), 'path' )}` ); + if( o.dry ) + return null; + _.fileProvider.dirMake( o.localPath ); + start( `git init .` ); + return start( `git remote add origin ${nativeRemotePath}` ); + } + + /* */ + + function localRepositoryRemoteAdd() + { + let wasRemotePath = _.git.remotePathFromLocal( o.localPath ); + if( wasRemotePath ) + { + if( wasRemotePath !== o.remotePath ) + throw _.err( `Repository at ${o.localPath} already exists, but has different origin ${wasRemotePath}` ); + return null; + } + if( o.logger ) + o.logger.log( `Adding origin ${_.color.strFormat( String( o.remotePath ), 'path' )} to local repository ${_.color.strFormat( String( o.localPath ), 'path' )}` ); + if( o.dry ) + return null; + return start( `git remote add origin ${nativeRemotePath}` ); + } + + /* */ + + function localRepositoryClone() + { + + if( o.logger && o.logger.verbosity > 0 ) + if( _.fileProvider.isDir( o.localPath ) ) + o.logger.log( `Directory ${_.color.strFormat( String( o.localPath ), 'path' )} will be moved` ); + + if( o.logger && o.logger.verbosity > 0 ) + o.logger.log( `Cloning repository from ${_.color.strFormat( String( o.remotePath ), 'path' )} to ${_.color.strFormat( String( o.localPath ), 'path' )}` ); + + if( o.dry ) + return null; + + let downloadPath = o.localPath; + if( _.fileProvider.isDir( o.localPath ) ) + { + downloadPath = _.git.path.join( o.localPath + '-' + _.idWithGuid() ); + } + + _.fileProvider.dirMake( downloadPath ); + + let start = _.process.starter + ({ + logger : _.logger.relativeMaybe( o.logger, -1 ), + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + sync : 0, + deasync : 0, + outputCollecting : 1, + mode : 'spawn', + currentPath : downloadPath, + }); + + return start( `git clone ${nativeRemotePath} .` ) + .finally( ( err, arg ) => + { + if( err ) + { + _.fileProvider.filesDelete( downloadPath ); + if( err ) + throw _.err( err ); + } + try + { + let o2 = + { + dst : o.localPath, + src : downloadPath, + dstRewriting : 1, + dstRewritingOnlyPreserving : 1, + linkingAction : 'hardLink', + } + _.fileProvider.filesReflect( o2 ); + } + catch( err ) + { + _.fileProvider.filesDelete( downloadPath ); + throw _.err( err, `\nCollision of local files with remote files at ${_.color.strFormat( String( o.localPath ), 'path' )}` ); + } + _.fileProvider.filesDelete( downloadPath ); + return arg; + }); + + } +} + +repositoryInit.defaults = +{ + remotePath : null, + localPath : null, + remote : null, + local : null, + throwing : 1, + sync : 0, + logger : 0, + dry : 0, + description : null, + token : null, +}; + +// + +function repositoryDelete( o ) +{ + o = _.routine.options_( repositoryDelete, o ); + + let ready = _.take( null ); + let parsed = ''; + + if( o.remotePath ) + { + o.remotePath = _.git.path.normalize( o.remotePath ); + parsed = _.git.path.parse({ remotePath : o.remotePath, full : 0, atomic : 0, objects : 1 }); + } + + if( o.remote === null ) + o.remote = !!o.remotePath; + if( o.local === null ) + o.local = !!o.localPath; + + if( o.local ) + ready.then( () => removeLocal() ); + if( o.remote ) + ready.then( () => removeRemote() ); + + ready.finally( ( err, arg ) => + { + if( err ) + { + if( o.throwing ) + throw _.err( err, `\nFailed to delete repository : ${_.color.strFormat( String( o.remotePath ), 'path' )}` ); + _.error.attend( err ); + } + return arg || false; + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + + /* */ + + function removeRemote() + { + _.assert( false, 'not implemented' ); + } + + /* */ + + function removeRemote() + { + if( o.logger && o.logger.verbosity > 0 ) + o.logger.log( `Deleting remote repository ${_.color.strFormat( String( o.remotePath ), 'path' )}` ); + + if( o.dry ) + return true; + + let o2 = _.mapOnly_( null, o, _.repo.repositoryDelete.defaults ); + return _.retry + ({ + routine : () => _.repo.repositoryDelete( o2 ), + attemptLimit : o.attemptLimit, + attemptDelay : o.attemptDelay, + attemptDelayMultiplier : o.attemptDelayMultiplier, + defaults : _.remote.attemptDefaults, + }); + } +} + +repositoryDelete.defaults = +{ + remotePath : null, + localPath : null, + local : null, + remote : null, + token : null, + throwing : 1, + sync : 0, + logger : 1, + dry : 0, + attemptLimit : null, + attemptDelay : null, + attemptDelayMultiplier : null, +}; + +// + +function repositoryClone( o ) +{ + let localProvider = _.fileProvider; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options_( repositoryClone, o ); + _.assert( _.strDefined( o.localPath ), 'Expects local path' ); + _.assert( _.strDefined( o.remotePath ) || _.mapIs( o.remotePath ), 'Expects remote path' ); + + let ready = _.take( null ); + + if( _.git.isRepository({ localPath : o.localPath }) ) + return ready; + + let parsed = _.git.path.parse({ remotePath : o.remotePath, full : 1, atomic : 0 }); + let remoteVcsPathParsed = _.mapBut_( null, parsed, { localVcsPath : null, tag : null, hash : null, query : null } ); + remoteVcsPathParsed.longPath = _.strRemoveEnd( parsed.longPath, '/' ); + let remoteVcsLongerPath = _.git.path.str( remoteVcsPathParsed ); + remoteVcsLongerPath = _.git.path.nativize( remoteVcsLongerPath ); + + if( localProvider.fileExists( o.localPath ) ) + _.sure( localProvider.dirIsEmpty( o.localPath ) ); + else + localProvider.dirMake( o.localPath ); + + const logger = _.logger.relativeMaybe( o.logger, -1 ); + const shell = _.process.starter + ({ + logger, + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + currentPath : o.localPath, + ready, + }); + + ready = _.retry + ({ + routine : () => shell( `git clone ${ remoteVcsLongerPath } . --config core.autocrlf=false` ), + attemptLimit : o.attemptLimit, + attemptDelay : o.attemptDelay, + attemptDelayMultiplier : o.attemptDelayMultiplier, + defaults : _.remote.attemptDefaults, + onError, + logger, + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + + /* */ + + function onError( err ) + { + const errorMsgs = + [ + 'Could not resolve host', + 'Could not read from remote repository', + 'Failed to connect', + 'returned error: 429', + 'expected flush after ref listing', + ]; + if( !_.strHasAny( err.originalMessage, errorMsgs ) ) + return false; + + _.error.attend( err ); + return true; + } +} + +repositoryClone.defaults = +{ + remotePath : null, + localPath : null, + logger : 0, + sync : 0, + attemptLimit : null, + attemptDelay : null, + attemptDelayMultiplier : null, +}; + +// + +function repositoryCheckout( o ) +{ + let localProvider = _.fileProvider; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options_( repositoryCheckout, o ); + _.assert( _.strDefined( o.localPath ), 'Expects local path' ); + _.assert( _.strDefined( o.remotePath ) || _.mapIs( o.remotePath ), 'Expects remote path' ); + + let ready = _.take( null ); + // let parsed = _.git.pathParse( o.remotePath ); + + let parsed = _.git.path.parse({ remotePath : o.remotePath, full : 1, atomic : 0 }); + + let shell = _.process.starter + ({ + // verbosity : o.verbosity, + logger : _.logger.relativeMaybe( o.logger, -1 ), + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + currentPath : o.localPath, + outputCollecting : 1, + ready, + }); + + if( parsed.tag ) + ready.then( () => + { + let repoHasTag = _.git.repositoryHasTag + ({ + localPath : o.localPath, + remotePath : parsed, + tag : parsed.tag + }); + + if( !repoHasTag ) + { + let remoteVcsPathParsed = _.mapBut_( null, parsed, { tag : null, hash : null, query : null } ); + let remoteVcsPath = _.git.path.str( remoteVcsPathParsed ); + remoteVcsPath = _.git.path.nativize( remoteVcsPath ); + throw _.err + ( + `Specified tag: ${_.strQuote( parsed.tag )} doesn't exist in local and remote copy of the repository.\ + \nLocal path: ${_.color.strFormat( String( o.localPath ), 'path' )}\ + \nRemote path: ${_.color.strFormat( String( remoteVcsPath ), 'path' )}` + ); + } + + return null; + }); + + let checkoutOptions = + { + execPath : 'git -c "core.autocrlf=false" checkout ' + ( parsed.hash || parsed.tag ) + } + + shell( checkoutOptions ) + + ready.catch( ( err ) => + { + _.errAttend( err ); + if( o.localChanges && o.stashing ) + shell + ({ + execPath : 'git -c "core.autocrlf=false" stash pop', + sync : 1, + deasync : 0, + throwingExitCode : 0, + ready : null + }) + + if( !_.strHasAny( checkoutOptions.output, [ 'fatal: reference', 'error: pathspec' ] ) ) + throw _.err( err ); + + err = _.err + ( + 'Failed to checkout, branch/commit: ' + + _.strQuote( parsed.hash || parsed.tag ) + + ' doesn\'t exist in repository at ' + + _.strQuote( o.localPath ) + ); + err.reason = 'git'; + throw err; + }) + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +repositoryCheckout.defaults = +{ + remotePath : null, + localPath : null, + logger : 0, + sync : 0 +}; + +// + +function repositoryStash( o ) +{ + _.routine.options_( repositoryStash, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strDefined( o.localPath ), 'Expects local path' ); + + let ready = _.take( null ); + let shell = _.process.starter + ({ + // verbosity : o.verbosity, + logger : _.logger.relativeMaybe( o.logger, -1 ), + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + currentPath : o.localPath, + outputCollecting : 1, + ready, + }); + + let shellOptions = { execPath : `git -c "core.autocrlf=false" stash ${ o.pop ? 'pop' : '' }` } + + shell( shellOptions ); + + ready.catch( ( err ) => + { + if( !_.strHas( shellOptions.output, 'CONFLICT' ) ) + throw _.err( err ); + _.errAttend( err ); + err = _.err( 'Automatic merge of stashed changes failed in repository at ' + _.strQuote( o.localPath ) + '. Fix conflict(s) manually.' ); + err.reason = 'git'; + throw err; + }) + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +repositoryStash.defaults = +{ + localPath : null, + // verbosity : null, + logger : 0, + pop : 0 +}; + +// + +function repositoryMerge( o ) +{ + _.routine.options_( repositoryMerge, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strDefined( o.localPath ), 'Expects local path' ); + + let ready = _.take( null ); + let shell = _.process.starter + ({ + // verbosity : o.verbosity, + logger : _.logger.relativeMaybe( o.logger, -1 ), + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + currentPath : o.localPath, + outputCollecting : 1, + ready, + }); + + let shellOptions = + { + execPath : `git -c "merge.defaultToUpstream=true" -c "core.autocrlf=false" merge` + } + + shell( shellOptions ); + + ready.catch( ( err ) => + { + if( !_.strHas( shellOptions.output, 'CONFLICT' ) ) + throw _.err( err ) + _.errAttend( err ); + err = _.err( 'Automatic merge of remote-tracking branch failed in repository at ' + _.strQuote( o.localPath ) + '. Fix conflict(s) manually.' ); + err.reason = 'git'; + throw err; + }) + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +repositoryMerge.defaults = +{ + localPath : null, + logger : 0, +}; + +// + +function _tagStrip( src ) +{ + const parsed = _.git.path.parse( src ); + delete parsed.tag; + return _.git.path.str( parsed ); +} + +// + +function _statusLocalGet( localPath ) +{ + return _.git.statusLocal + ({ + localPath, + unpushedCommits : 0, + unpushedTags : 0, + unpushedBranches : 0, + explaining : 1, + detailing : 1, + sync : 0, + }); +} + + +// + +function _subrepositoryInitMaybe( dstBasePath, basePath ) +{ + dstBasePath = _.git.path.normalize( dstBasePath ); + const parsed = _.git.path.parse( basePath ); + + _.assert + ( + _.str.begins( parsed.longPath, _.git.path.detrail( _.git.path.parse( dstBasePath ).longPath ) ), + '{-o.dstDirPath-} should be a subdirectory of {-o.dstBasePath-}.' + ); + + if( !_.fileProvider.fileExists( basePath ) ) + _.fileProvider.dirMake( basePath ); + + const isSubrepository = _.git.isRepository({ localPath : basePath }); + + const con = _.take( null ); + if( !isSubrepository ) + { + con.then( () => + { + return _.git.repositoryInit + ({ + localPath : basePath, + remote : 0, + local : 1, + }); + }); + + con.then( () => _statusLocalGet( basePath ) ); + con.then( ( status ) => + { + const shell = _.process.starter + ({ + logger, + currentPath : basePath, + inputMirroring : 0, + outputCollecting : 0, + }); + if( status.uncommitted ) + shell( 'git add .' ); + shell({ execPath : 'git commit --allow-empty -m Init' }) + return shell({ execPath : 'git commit --allow-empty -m "Indexed"' }) + }); + } + + return con.then( () => isSubrepository ); +} + +// + +function _branchFromPath( basePath, path, local ) +{ + const parsed = _.git.path.parse( path ); + if( parsed.tag ) + { + const tagDescriptor = _.git.tagExplain + ({ + remotePath : path, + localPath : basePath, + tag : parsed.tag, + remote : !local, + local, + }); + + if + ( + tagDescriptor.isBranch + && ( _.str.has( path, _.git.path.tagToken ) || !_.longHasAny( parsed.protocols, [ 'hd', 'file' ] ) ) + ) + return parsed.tag; + } + return null; +} + +// + +function _remoteNameGenerate( basePath ) +{ + let remoteName = `_temp-${ _.idWithGuid() }`; + const config = _.git.configRead( basePath ); + while( `remote "${ remoteName }"` in config ) + remoteName = `_temp-${ _.idWithGuid() }`; + return remoteName; +} + +// + +function repositoryAgree( o ) +{ + _.routine.options_( repositoryAgree, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.str.defined( o.dstBasePath ), 'Expects local path to destination repository {-o.dstBasePath-}.' ); + _.assert( _.str.defined( o.srcBasePath ) || _.aux.is( o.srcBasePath ), 'Expects path to source repository {-o.srcBasePath-}.' ); + _.assert( _.str.is( o.commitMessage ) || o.commitMessage === null, 'Expects string with commit message {-o.commitMessage-}' ); + _.assert( _.longHasAny( [ 'src', 'dst', 'manual' ], o.mergeStrategy ) ); + + /* */ + + let error = null; + const ready = _.take( null ); + + let basePath = o.dstBasePath; + o.dstBasePath = _tagStrip( basePath ); + if( o.dstDirPath ) + basePath = _.git.path.join( o.dstBasePath, o.dstDirPath ); + basePath = _.git.path.detrail( _tagStrip( basePath ) ); + let shouldRemove = false; + + const logger = _.logger.relativeMaybe( o.logger, -1 ); + const shell = _.process.starter + ({ + logger, + currentPath : basePath, + inputMirroring : 0, + outputCollecting : 0, + }); + + if( basePath !== o.dstBasePath ) + { + ready.then( () => _subrepositoryInitMaybe( o.dstBasePath, basePath ) ); + ready.then( ( isSubrepository ) => shouldRemove = !isSubrepository ); + } + ready.then( () => + { + if( !o.dstBranch ) + o.dstBranch = _branchFromPath( basePath, o.dstBasePath, true ) || _.git.tagLocalRetrive({ localPath : basePath }); + _.sure + ( + _.str.defined( o.dstBranch ), + 'Expects defined branch in destination repository. Provide it by option {-o.dstBranch-} or in path.' + ); + return null; + }); + + const normalized = _.git.path.normalize( o.srcBasePath ); + const srcBasePath = _.git.path.nativize( normalized ); + const srcBasePathIsRepository = _.git.isRepository({ remotePath : normalized }); + + let srcState = o.srcState; + if( o.srcState ) + srcState = _.git._stateParse( o.srcState ).value; + + let remoteName, srcBranch; + let tempPath = _.fileProvider.path.tempOpen(); + ready.then( () => _remoteNameGenerate( basePath ) ) + ready.then( ( name ) => { remoteName = name; return null }); + ready.then( () => shell( `git remote add ${ remoteName } ${ tempPath }` ) ); + srcRepositoryPrepare(); + ready.then( () => + { + if( srcBasePathIsRepository ) + srcBranch = _branchFromPath( basePath, normalized, false ) || _.git.tagLocalRetrive({ localPath : tempPath }); + else + srcBranch = 'master'; + return null; + }); + + /* */ + + ready.then( () => _.git.tagLocalChange({ localPath : o.dstBasePath, tag : o.dstBranch }) ); + ready.then( () => shell({ execPath : `git fetch ${ remoteName }`, outputPiping : 0 }) ); + + if( logger ) + ready.then( () => + { + logger.log( 'Files that will be merged :' ); + return shell + ({ + execPath : `git diff --name-only ${ o.dstBranch }..${ remoteName }/${ srcBranch }`, + outputCollecting : 1 + }); + }); + if( !o.dry ) + { + ready.then( () => + { + let strategy = '-s recursive'; + if( o.mergeStrategy !== 'manual' ) + strategy += ` -X ${ o.mergeStrategy === 'src' ? 'theirs' : 'ours' }`; + const mergeBranch = `${ remoteName }/${ srcBranch }`; + + return shell + ({ + execPath : `git merge ${ strategy } --allow-unrelated-histories --squash ${ mergeBranch } ${ o.dstBranch }`, + outputPiping : 0, + }); + }); + + ready.then( () => _statusLocalGet( basePath ) ); + ready.then( ( status ) => + { + if( status.uncommitted ) + { + let uncommittedFiles = filesFilter( status.uncommitted ); + if( shouldRemove ) + _.fileProvider.filesDelete( _.git.path.join( basePath, '.git' ) ); + + if( !o.commitMessage ) + o.commitMessage = `Merge branch '${ srcBranch }' of ${ srcBasePath } into ${ o.dstBranch }`; + + if( uncommittedFiles === undefined || uncommittedFiles.length ) + { + const srcHeadDescriptorCon = _.git.repositoryHistoryToJson + ({ + localPath : tempPath, + state1 : '#HEAD', + state2 : '#HEAD', + }); + const dstHeadDescriptorCon = _.git.repositoryHistoryToJson + ({ + localPath : o.dstBasePath, + state1 : '#HEAD', + state2 : '#HEAD', + }); + return _.Consequence.And( srcHeadDescriptorCon, dstHeadDescriptorCon ); + } + } + return null; + }); + ready.then( ( descriptors ) => + { + if( descriptors ) + { + const onDate = _.git._onDate_functor({ relative : o.relative, delta : o.delta || 0 }); + let date = onDate( descriptors[ 0 ][ 0 ].date ); + + const srcHeadDate = Date.parse( date ); + const dstHeadDate = Date.parse( descriptors[ 1 ][ 0 ].date ); + + _.sure( srcHeadDate > dstHeadDate, 'The new commit should be newer than the last one.' ); + + process.env.GIT_COMMITTER_DATE = date; + date = `--date="${ date }"`; + shell({ currentPath : o.dstBasePath, execPath : 'git add .' }); + return shell + ({ + currentPath : o.dstBasePath, + execPath : `git commit -m "${ o.commitMessage }" ${ date }`, + outputPiping : 0, + }); + } + return null; + }); + } + ready.finally( ( err, arg ) => + { + if( err ) + error = err; + _.fileProvider.path.tempClose( tempPath ); + delete process.env.GIT_COMMITTER_DATE; + + if( !shouldRemove ) + return shell( `git remote remove ${ remoteName }` ); + return null; + }); + ready.finally( () => + { + if( error ) + throw _.err( error ); + return true; + }); + + return ready; + + /* */ + + function srcRepositoryPrepare() + { + if( srcBasePathIsRepository ) + { + ready.then( () => _.git.repositoryClone({ localPath : tempPath, remotePath : normalized }) ); + } + else + { + ready.then( () => _.fileProvider.filesReflect({ dst : tempPath, src : srcBasePath }) ); + ready.then( () => _.git.repositoryInit({ localPath : tempPath, remote : 0, local : 1 }) ); + ready.then( () => + { + return shell + ({ + currentPath : tempPath, + execPath : [ 'git add .', 'git commit -m Init', 'git commit --allow-empty -m "Indexed"' ] + }); + }); + } + if( srcState ) + ready.then( () => shell({ currentPath : tempPath, execPath : `git reset --hard ${ srcState }` }) ); + return ready; + } + + /* */ + + function filesFilter( msg ) + { + if( o.srcDirPath ) + { + _.assert( !_.git.path.isGlob( o.srcDirPath ) ); + let srcDirPath = o.srcDirPath; + if( _.git.path.isAbsolute( o.srcDirPath ) ) + { + srcDirPath = _.git.path.relative( srcBasePath, srcDirPath ); + _.assert( !_.git.path.isDotted( srcDirPath ) ); + } + + if( o.only ) + o.only = _.array.as( o.only ); + else + o.only = _.array.make( 0 ); + + if( o.only.length ) + for( let i = 0 ; i < o.only.length ; i++ ) + o.only[ i ] = _.git.path.join( srcDirPath, o.only[ i ] ); + else + o.only.push( _.git.path.join( srcDirPath, '**' ) ); + } + + let pathsFromStatus; + if( o.only || o.but ) + pathsFromStatus = pathsProduceFromMessage( msg, o.only ); + + if( o.only ) + { + const paths = pathsFilter( pathsFromStatus, o.only ); + const exclude = _.arrayAppendArray( null, pathsFromStatus ); + _.arrayRemovedArrayOnce( exclude, paths ); + if( exclude.length ) + filesUnstage( exclude ); + pathsFromStatus = paths; + } + if( o.but ) + { + const exclude = pathsFilter( pathsFromStatus, o.but ); + if( exclude.length ) + filesUnstage( exclude ); + _.arrayRemovedArrayOnce( pathsFromStatus, exclude ); + } + return pathsFromStatus; + } + + /* */ + + function pathsProduceFromMessage( msg ) + { + const files = msg.split( '\n' ); + files.splice( 0, 1 ); + _.arrayRemoveOnce( files, '' ); + for( let i = 0 ; i < files.length ; i++ ) + files[ i ] = _.str.remove( files[ i ], /^\s*\w+\s+/ ); + return files; + } + + /* */ + + function pathsFilter( paths, selectors ) + { + selectors = _.array.as( selectors ); + const result = _.array.make(); + for( let i = 0 ; i < selectors.length ; i++ ) + { + const selector = _.str.removeBegin( selectors[ i ], './' ); + const entries = _.path.globShortFilter({ src : paths, selector }); + _.arrayAppendArrayOnce( result, entries ); + } + return result; + } + + /* */ + + function filesUnstage( exclude ) + { + shell({ execPath : `git restore --staged ${ exclude.join( ' ' ) }`, sync : 1 }); + shell({ execPath : `git clean -df`, sync : 1 }); + shell({ execPath : `git checkout ./`, sync : 1 }); + } +} + +repositoryAgree.defaults = +{ + srcBasePath : null, + dstBasePath : null, + srcState : null, + dstBranch : null, + srcDirPath : null, + dstDirPath : null, + commitMessage : null, + mergeStrategy : 'src', /* can be any of [ 'src', 'dst', 'manual' ] */ + relative : 'commit', + delta : null, + but : null, + only : null, + logger : 0, + dry : 0, +}; + +// + +function repositoryMigrate( o ) +{ + _.routine.options_( repositoryMigrate, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.str.defined( o.dstBasePath ), 'Expects local path to destination repository {-o.dstBasePath-}.' ); + _.assert( _.str.defined( o.srcBasePath ) || _.aux.is( o.srcBasePath ), 'Expects path to source repository {-o.srcBasePath-}.' ); + + /* */ + + let error = null; + const ready = _.take( null ); + + let basePath = o.dstBasePath; + o.dstBasePath = _tagStrip( basePath ); + if( o.dstDirPath ) + basePath = _.git.path.join( o.dstBasePath, o.dstDirPath ); + basePath = _.git.path.detrail( _tagStrip( basePath ) ); + let shouldRemove = false; + + const logger = _.logger.relativeMaybe( o.logger, -1 ); + const shell = _.process.starter + ({ + logger, + currentPath : basePath, + outputCollecting : 0, + inputMirroring : 0, + }); + + if( basePath !== o.dstBasePath ) + { + ready.then( () => _subrepositoryInitMaybe( o.dstBasePath, basePath ) ); + ready.then( ( isSubrepository ) => shouldRemove = !isSubrepository ); + } + ready.then( () => + { + if( !o.dstBranch ) + o.dstBranch = _branchFromPath( basePath, o.dstBasePath, true ) || _.git.tagLocalRetrive({ localPath : basePath }); + _.sure + ( + _.str.defined( o.dstBranch ), + 'Expects defined branch in destination repository. Provide it by option {-o.dstBranch-} or in path.' + ); + return null; + }); + + const normalized = _.git.path.normalize( o.srcBasePath ); + const srcBasePath = _.git.path.nativize( normalized ); + if( !o.srcBranch ) + o.srcBranch = + _branchFromPath( basePath, normalized, false ) || _.git.tagLocalRetrive({ localPath : _.git.path.nativize( normalized ) }); + + let srcState1 = o.srcState1; + let srcState2 = o.srcState2; + if( o.srcState1 ) + srcState1 = _.git._stateParse( o.srcState1 ).value; + _.assert( _.str.defined( srcState1 ), 'Expects state {-o.srcState1-} to start with.' ); + if( o.srcState2 ) + srcState2 = _.git._stateParse( o.srcState2 ).value; + + if( !o.onCommitMessage ) + if( !o.editMessage ) + o.onCommitMessage = ( e ) => e; + if( o.editMessage ) + { + _.assert( !o.onCommitMessage, 'Expects manual or automated commit message editing, but not both.' ); + o.onCommitMessage = onCommitData_functor(); + } + if( _.str.is( o.onCommitMessage ) ) + { + let msg = o.onCommitMessage; + o.onCommitMessage = ( e ) => msg; + } + _.assert( _.routine.is( o.onCommitMessage ), 'Expects routine to produce commit message {-o.onCommitMessage-}.' ); + + if( o.onDate === null ) + if( !o.editDate ) + o.onDate = ( e ) => e; + if( o.editDate ) + { + _.assert( !o.onDate, 'Expects manual or automated commit date editing, but not both.' ); + o.onCommitMessage = onCommitData_functor(); + } + if( _.aux.is( o.onDate ) ) + o.onDate = _.git._onDate_functor( o.onDate ); + _.assert( _.routine.is( o.onDate ), 'Expects routine to produce commit date {-o.onDate-}.' ); + + let remoteName; + ready.then( () => _remoteNameGenerate( basePath ) ) + ready.then( ( name ) => { remoteName = name; return null }); + + ready.then( () => shell( `git remote add ${ remoteName } ${ srcBasePath }` ) ); + ready.then( () => _.git.tagLocalChange({ localPath : basePath, tag : o.dstBranch }) ); + ready.then( () => shell({ execPath : `git fetch ${ remoteName }`, outputPiping : 0 }) ); + verifyRepositoriesHasSameFiles() + + let commitsArray = []; + ready.then( () => + { + return _.git.repositoryHistoryToJson + ({ + localPath : basePath, + state1 : o.srcState1, + state2 : o.srcState2 || `!${ remoteName }/${ o.srcBranch }`, + }); + }); + if( logger ) + ready.then( ( commits ) => + { + logger.log( 'List of commits to migrate :' ); + logger.log( _.entity.exportJson( commits ) ); + return commits; + }); + + if( !o.dry ) + { + ready.then( ( commits ) => + { + commitsArray = commits; + return _.git.repositoryHistoryToJson + ({ + localPath : o.dstBasePath, + state1 : '#HEAD', + state2 : '#HEAD', + }); + }); + ready.then( ( head ) => writeCommits( head, commitsArray ) ); + } + ready.finally( ( err, arg ) => + { + if( err ) + { + _.error.attend( err ); + error = err; + } + delete process.env.GIT_COMMITTER_DATE; + if( shouldRemove ) + { + _.fileProvider.filesDelete( _.git.path.join( basePath, '.git' ) ); + return null; + } + else + { + return shell( `git remote remove ${ remoteName }` ); + } + }); + ready.finally( () => + { + if( error ) + throw _.err( error ); + return true; + }); + + return ready; + + /* */ + + function remoteNameGenerate() + { + ready.then( () => + { + let remoteName = `_temp-${ _.idWithGuid() }`; + const config = _.git.configRead( basePath ); + while( `remote "${ remoteName }"` in config ) + remoteName = `_temp-${ _.idWithGuid() }`; + return remoteName; + }); + return ready; + } + + /* */ + + function verifyRepositoriesHasSameFiles() + { + ready.then( () => + { + return shell + ({ + execPath : `git diff --name-only --diff-filter=d ${ o.dstBranch }..${ srcState1 }`, + outputCollecting : 1, + }); + }); + ready.then( ( diff ) => + { + if( diff && diff.output ) + { + const files = outputDiffPathsFilter( diff.output, false ); + if( files.length ) + throw _.err + ( + `Expects no diffs between ${ o.dstBranch } and ${ o.srcBasePath }.` + + `\nPlease, synchronize states before reflecting of commits.` + ); + } + return null; + }); + return ready; + } + + /* */ + + function writeCommits( head, commits ) + { + const length = commits.length; + + const gitDir = _.git.path.join( basePath, '.git' ); + const tempGitDir = _.git.path.join( basePath, '../-git.temp' ); + let storeGitDir = () => {}; + let restoreGitDir = ( e ) => e; + if( shouldRemove ) + { + storeGitDir = () => + { + _.fileProvider.fileRename( tempGitDir, gitDir ); + }; + restoreGitDir = ( e ) => + { + _.fileProvider.fileRename( gitDir, tempGitDir ); + return e; + }; + } + + const con = _.take( null ); + con.then( () => o.onDate( commits[ length - 1 ].date, 'date', commits[ length - 1 ] ) ); + con.then( ( startCommitDate ) => + { + const headDate = Date.parse( head[ 0 ].date ); + const commitStartDate = Date.parse( startCommitDate ) || _.time.now(); + _.assert( headDate <= commitStartDate, 'New commit should be newer than last commit in branch.' ); + return null; + }); + + let commitMessage, date; + for( let i = length - 1 ; i >= 0 ; i-- ) + { + con.then( () => + { + return shell + ({ + execPath : `git cherry-pick --strategy=recursive -X theirs -n -m 1 ${ commits[ i ].hash }`, + throwingExitCode : 0, + }); + }); + con.then( ( op ) => + { + if( op.exitCode !== 0 ) + return shell( `git add .` ); + return null; + }); + con.then( () => shell({ execPath : `git diff --name-only HEAD`, outputCollecting : 1, outputPiping : 0 }) ); + con.then( ( diff ) => + { + if( diff.output ) + if( !_.str.begins( commits[ i ].message, 'Merge pull request' ) ) + { + if( !outputDiffPathsFilter( diff.output, true ).length ) + return null; + + let dateCon = o.onDate( commits[ i ].date, 'date', commits[ i ] ); + let commitMessageCon = o.onCommitMessage( commits[ i ].message, 'message', commits[ i ] ); + return _.Consequence.And( dateCon, commitMessageCon ); + } + return null; + }); + con.then( ( commitData ) => + { + if( commitData ) + { + _.assert( _.str.is( commitData[ 0 ] ), 'Callback {-o.onDate-} should return string date.' ); + date = commitData[ 0 ].length > 0 ? `--date="${ commitData[ 0 ] }"` : ''; + commitMessage = commitData[ 1 ]; + process.env.GIT_COMMITTER_DATE = commitData[ 0 ] || ''; + return _statusLocalGet( basePath ); + } + return null; + }); + con.then( ( status ) => + { + if( status && status.uncommitted ) + { + const con2 = _.take( null ); + con2.then( () => + { + storeGitDir(); + return null; + }); + con2.then( () => shell({ currentPath : o.dstBasePath, execPath : `git add .` }) ); + con2.then( () => _statusLocalGet( o.dstBasePath ) ); + con2.then( ( status ) => + { + if( status && status.uncommitted ) + return shell + ({ + currentPath : o.dstBasePath, + execPath : `git commit -m "${ commitMessage }" ${ date }`, + outputPiping : 0 + }); + return null; + }); + con2.then( () => + { + restoreGitDir(); + return null; + }); + return con2; + } + return null; + }); + } + + return con; + } + + /* */ + + function outputDiffPathsFilter( output, unstage ) + { + let pathsFromStatus = pathsProduceFromMessage( output ); + _.arrayRemoveOnce( pathsFromStatus, '' ); + + if( o.srcDirPath ) + { + _.assert( !_.git.path.isGlob( o.srcDirPath ) ); + let srcDirPath = o.srcDirPath; + if( _.git.path.isAbsolute( o.srcDirPath ) ) + { + srcDirPath = _.git.path.relative( srcBasePath, srcDirPath ); + _.assert( !_.git.path.isDotted( srcDirPath ) ); + } + + if( o.only ) + o.only = _.array.as( o.only ); + else + o.only = _.array.make( 0 ); + + if( o.only.length ) + for( let i = 0 ; i < o.only.length ; i++ ) + o.only[ i ] = _.git.path.join( srcDirPath, o.only[ i ] ); + else + o.only.push( _.git.path.join( srcDirPath, '**' ) ); + } + + if( o.only ) + { + let paths = pathsFilter( pathsFromStatus, o.only ); + let exclude = _.arrayAppendArray( null, pathsFromStatus ); + _.arrayRemovedArrayOnce( exclude, paths ); + if( unstage && exclude.length ) + filesUnstage( exclude ); + pathsFromStatus = paths; + } + if( o.but ) + { + let exclude = pathsFilter( pathsFromStatus, o.but ); + if( unstage && exclude.length ) + filesUnstage( exclude ); + _.arrayRemovedArrayOnce( pathsFromStatus, exclude ); + } + + return pathsFromStatus; + } + + /* */ + + function pathsProduceFromMessage( msg ) + { + const files = msg.split( '\n' ); + for( let i = 0 ; i < files.length ; i++ ) + files[ i ] = _.str.remove( files[ i ], /^\s*\w+\s+/ ); + return files; + } + + /* */ + + function pathsFilter( paths, selectors ) + { + selectors = _.array.as( selectors ); + const result = _.array.make(); + for( let i = 0 ; i < selectors.length ; i++ ) + { + const selector = _.str.removeBegin( selectors[ i ], './' ); + const filtered = _.path.globShortFilter({ src : paths, selector }); + _.arrayAppendArrayOnce( result, filtered ); + } + return result; + } + + /* */ + + function filesUnstage( exclude ) + { + shell({ execPath : `git restore --staged ${ exclude.join( ' ' ) }`, sync : 1 }); + shell({ execPath : `git clean -df`, sync : 1 }); + shell({ execPath : `git checkout ./`, sync : 1 }); + } + + /* */ + + function onCommitData_functor() + { + const Prompt = require( 'prompts' ); + const localLogger = logger ? logger : console; + + /* */ + + return async function onCommitData( value, key ) + { + localLogger.log( `Current commit ${ key } : "${ value }".` ); + const response = await Prompt + ({ + type : 'text', + name : 'data', + message : `Please, input new ${ key } :`, + }); + + return response.data || value; + } + } +} + +repositoryMigrate.defaults = +{ + srcBasePath : null, + dstBasePath : null, + srcState1 : null, + srcState2 : null, + srcBranch : null, + dstBranch : null, + srcDirPath : null, + dstDirPath : null, + but : null, + only : null, + + onCommitMessage : null, + onDate : null, + editMessage : 0, + editDate : 0, + + logger : 0, + dry : 0, +}; + +// + +function repositoryHistoryToJson( o ) +{ + _.assert( arguments.length === 1, 'Expects single argument.' ); + _.routine.options( repositoryHistoryToJson, o ); + _.assert( _.str.defined( o.localPath ) ); + + let state1 = _.git._stateParse( o.state1 ).value; + let state2 = _.git._stateParse( o.state2 ).value; + + const format = + '{%n' + + ' \\"author\\" : \\"%an\\",%n' + + ' \\"email\\" : \\"%ae\\",%n' + + ' \\"hash\\" : \\"%H\\",%n' + + ' \\"message\\" : \\"%s\\",%n' + + ` \\"date\\" : \\"%ai\\",%n` + + ` \\"commiterDate\\" : \\"%ci\\"%n` + + '},'; + + return _.process.start + ({ + currentPath : o.localPath, + execPath : `git log ${ state1 }~..${ state2 } --format="${ format }"`, + outputCollecting : 1, + throwingExitCode : 1, + inputMirroring : 0, + outputPiping : 0, + }) + .then( ( log ) => + { + let commits = log.output; + if( process.platform === 'win32' ) + commits = _.str.replace( commits, /\\/, '\\\\' ); + commits = _.str.replaceBegin( commits, '', '[\n' ); + commits = _.str.replaceEnd( commits, ',\n', '\n]' ); + return JSON.parse( commits ); + }); +} + +repositoryHistoryToJson.defaults = +{ + localPath : null, + state1 : null, + state2 : null, +}; + +// -- +// config +// -- + +function configRead( filePath ) +{ + const fileProvider = _.fileProvider; + const path = _.git.path; + // const path = fileProvider.path; + + _.assert( arguments.length === 1 ); + _.assert( _.strIs( filePath ) ); + + let configPath = path.join( filePath, '.git/config' ); + + if( !fileProvider.fileExists( configPath ) ) + return null; + + if( !Ini ) + Ini = require( 'ini' ); + + let read = fileProvider.fileRead( configPath ); + let config = Ini.parse( read ); + + return config; +} + +// + +function configSave( filePath, config ) +{ + const fileProvider = _.fileProvider; + const path = _.git.path; + // const path = fileProvider.path; + + _.assert( arguments.length === 2 ); + _.assert( _.strDefined( filePath ) ); + _.assert( _.object.isBasic( config ) ); + + if( !Ini ) + Ini = require( 'ini' ); + + let data = Ini.stringify( config, { whitespace : true } ); + fileProvider.fileWrite( path.join( filePath, '.git/config' ), data ); +} + +// + +function configReset( o ) /* aaa : implement */ /* Dmytro : implemented */ +{ + _.assert( arguments.length === 1, 'Expects single options map {-o-}' ); + _.routine.options_( configReset, o ); + if( o.preset === 'recommended' ) + { + _.assert( _.strDefined( o.userName ), 'Expects user name {-o.userName-}' ); + _.assert( _.strDefined( o.userMail ), 'Expects user email {-o.userMail-}' ); + } + else + { + _.assert( o.preset === 'standard' ); + } + + /* */ + + const ready = _.take( null ); + const start = _.process.starter + ({ + currentPath : o.localPath, + mode : 'shell', + outputCollecting : 1, + throwingExitCode : 1, + inputMirroring : 0, + sync : 0, + ready, + }); + + /* */ + + if( o.withLocal ) + { + _.assert( _.git.isRepository({ localPath : o.localPath }), 'Expects git repository' ); + + stadardLocalConfigSet(); + if( o.preset === 'recommended' ) + recommendedConfigSet( 'local' ); + } + + if( o.withGlobal ) + { + standardGlobalConfigSet(); + if( o.preset === 'recommended' ) + recommendedConfigSet( 'global' ); + } + + ready.catch( ( err ) => + { + _.errAttend( err ); + throw _.err( err ); + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + + /* */ + + function recommendedConfigSet( scope ) + { + return start + ({ + execPath : + [ + `git config --${ scope } core.autocrlf false`, + `git config --${ scope } core.ignorecase false`, + `git config --${ scope } core.fileMode false`, + `git config --${ scope } credential.helper store`, + `git config --${ scope } user.name "${ o.userName }"`, + `git config --${ scope } user.email "${ o.userMail }"`, + `git config --${ scope } url."https://${ o.userName }@github.com".insteadOf "https://github.com"`, + `git config --${ scope } url."https://${ o.userName }@bitbucket.org".insteadOf "https://bitbucket.org"`, + ], + }); + } + + /* */ + + function stadardLocalConfigSet() + { + /* clean sections core and user */ + start + ({ + throwingExitCode : 0, + execPath : + [ + 'git config --local --remove-section core', + 'git config --local --remove-section user', + ], + }); + + return start + ({ + execPath : + [ + 'git config --local core.repositoryformatversion 0', + 'git config --local core.filemode true', + 'git config --local core.bare false', + 'git config --local core.logallrefupdates true', + ], + }); + } + + /* */ + + function standardGlobalConfigSet() + { + const provider = _.fileProvider; + const path = provider.path; /* Dmytro : should be provider path */ + + const globalConfigPath = path.nativize( path.join( process.env.HOME, '.gitconfig' ) ); + /* by default global config has no settings */ + provider.fileWrite( globalConfigPath, '' ); + } +} + +configReset.defaults = +{ + localPath : null, + sync : 0, + preset : 'recommended', /* [ recommended, standard ] */ + withGlobal : 0, + withLocal : 1, + userName : null, + userMail : null, +}; + +// + +/* qqq : implement routine to find out does exist version/tag */ +/* qqq : implement routine to convert one kind of version/tag to one another */ + +/* qqq : aaa:fixed + + = Message of Error#1 + Unexpected change type: "u", filePath: "revision" fatal: ambiguous argument 'alhpa': unknown revision or path not in the working tree. + Use '--' to separate paths from revisions, like this: + 'git [...] -- [...]' + + = Beautified calls stack + at detailingHandle (/pro/builder/proto/wtools/amid/l3/git/l1/Tools.s:3556:15) + at wConsequence.handleOutput (/pro/builder/proto/wtools/amid/l3/git/l1/Tools.s:3505:5) + +*/ + +function _stateParse( state ) +{ + let statesBegin = [ '#', '!' ]; + let statesSpecial = [ 'working', 'staging', 'committed' ]; + /* + https://neurathsboat.blog/post/git-intro/ + https://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F + */ + + let result = + { + original : state, + value : state, + isSpecial : false + }; + + /* aaa : for Dmytro : should be no such special states */ /* Dmytro : done */ + + // if( _.strBegins( state, 'HEAD' ) ) + // { + // result.isSpecial = true; + // return result; + // } + + if( _.strBegins( state, statesBegin ) ) + { + result.isVersion = _.git.stateIsHash( state ); + result.isTag = _.git.stateIsTag( state ); + result.value = _.strRemoveBegin( state, statesBegin ); + + if( !result.isTag ) + return result; + + if( _.strEnds( result.value, '/' ) ) + { + result.isTag = false; + result.value = _.strRemoveEnd( result.value, '/' ); + } + else if( _.strHas( result.value, '/' ) ) + { + result.isRemoteTag = true; + let r = _.strIsolateLeftOrNone( result.value, '/' ); + _.sure + ( + _.strDefined( r[ 0 ] ) && _.strDefined( r[ 2 ] ), + `Failed to parse state: ${result.original}, expects remote tag in format: "!remote/tag".` + ); + result.remotePath = `:///${r[ 0 ]}`; + result.remote = `!${r[ 2 ]}`; + } + + return result; + } + + if( !_.longHas( statesSpecial, state ) ) + throw _.err( `Expects one of special states: ${statesSpecial}, but got: ${state}` ); + + result.isSpecial = true; + + return result; +} + +// + +function diff( o ) +{ + let self = this; + + o = _.routine.options_( diff, o ); + + _.assert( arguments.length === 1 ); + _.assert( _.strDefined( o.state1 ) || o.state1 === null ); + _.assert( _.strDefined( o.state2 ) ); + _.assert( _.strDefined( o.localPath ) ); + _.assert( o.linesOfContext === null || _.numberIs( o.linesOfContext ) ); + + if( o.state1 === null ) /* qqq : discuss */ + o.state1 = 'HEAD'; + + let ready = _.take( null ); + let result = Object.create( null ); + let state1 = self._stateParse( o.state1 ); + let state2 = self._stateParse( o.state2 ); /* qqq : ! aaa: special tags now work in both states */ + + let start = _.process.starter + ({ + sync : 0, + deasync : 0, + outputCollecting : 1, + mode : 'spawn', + currentPath : o.localPath, + throwingExitCode : 0, + inputMirroring : 0, + outputPiping : 0, + ready + }); + + if( o.fetchTags ) + start( `git fetch --tags` ) + + ready.then( checkStates ); + ready.then( runDiff ); + ready.then( handleResult ); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + + /* - */ + + function checkStates() + { + let ready = _.take( null ) + ready.then( () => checkState( state1 ) ) + ready.then( () => checkState( state2 ) ) + ready.then( () => + { + if( !o.throwingDoesNotExist ) + return null; + + if( !state1.exists ) + throw _.err( `State::${state1.original} {-o.state1-} doesn't exist in repository at ${o.localPath}` ); + + if( !state2.exists ) + throw _.err( `State::${state2.original} {-o.state2-} doesn't exist in repository at ${o.localPath}` ); + + return null; + }) + return ready; + } + + /* - */ + + function checkState( state ) + { + state.exists = true; + + if( state.isSpecial ) + return null; + + let con = _.take( null ) + + if( state.isVersion || state.isTag ) + { + let o2 = + { + localPath : o.localPath, + remotePath : null, + local : 0, + remote : 0, + sync : o.sync, + } + + if( state.isRemoteTag ) + { + o2.remotePath = state.remotePath; + o2.remote = state.remote; + o2.returnVersion = true; + } + else + { + o2.local = state.original; + } + + con.then( () => self.exists( o2 ) ); + } + else + { + start({ execPath : `git rev-parse ${state.value}`, ready : con }) + } + + con.then( ( got ) => + { + if( _.boolIs( got ) ) + state.exists = got; + else if( _.object.isBasic( got ) ) + state.exists = got.exitCode === 0; + else + { + _.assert( _.strDefined( got ) ); + state.value = got; + state.exists = true; + } + + return null; + }) + + return con; + } + + /* - */ + + function runDiff() + { + if( !state1.exists || !state2.exists ) + return null; + + if( state1.isSpecial && state2.isSpecial ) + if( state1.value === state2.value ) + { + result.status = o.explaining ? '' : false; + return null; + } + + let ready = _.take( null ); + + let op = + { + execPath : 'git', + ready + } + + diffArgsForm(); + + start( op ) + + ready.then( handleOutput ); + + return ready; + + /* */ + + function diffArgsForm() + { + op.args = [ 'diff', '--exit-code' ] + + if( o.detailing ) + op.args.push( '--raw' ) + else + op.args.push( '--stat' ) + + if( o.generatingPatch ) + op.args.push( '--patch' ) + + if( _.numberIs( o.linesOfContext ) ) + op.args.push( `--unified=${o.linesOfContext}` ) + + if( o.coloredPatch ) + op.args.push( '--color=always' ) + else + op.args.push( '--color=never' ) + + argsForStateForm( state1 ); + argsForStateForm( state2 ); + } + + /* */ + + function argsForStateForm( state ) + { + if( !state.isSpecial ) + op.args.push( state.value ); + else if( state.value === 'staging' ) + op.args.push( '--staged' ) + else if( state.value === 'committed' ) + op.args.push( 'HEAD' ) + else if( _.strBegins( state.value, 'HEAD' ) ) + op.args.push( state.value ); + } + + /* + if( state1.value === 'working' ) + start({ execPath : `git diff ${diffMode} --exit-code ${state2.value}`, ready }) + else if( state1.value === 'staging' ) + start({ execPath : `git diff --staged ${diffMode} --exit-code ${state2.value}`, ready }) + else if( state1.value === 'committed' ) + start({ execPath : `git diff ${diffMode} --exit-code HEAD ${state2.value}`, ready }) + else + start({ execPath : `git diff ${diffMode} --exit-code ${state1.value} ${state2.value}`, ready }) */ + } + + /* */ + + function handleOutput( got ) + { + result.modifiedFiles = ''; + result.deletedFiles = ''; + result.addedFiles = ''; + result.renamedFiles = ''; + result.copiedFiles = ''; + result.typechangedFiles = ''; + result.unmergedFiles = ''; + + let status = ''; + + if( o.detailing ) + detailingHandle( got ); + + for( var k in result ) + { + if( !o.detailing ) + result[ k ] = got.exitCode === 1 ? _.maybe : false; + else if( !o.explaining ) + result[ k ] = !!result[ k ]; + else if( result[ k ] ) + { + _.assert( _.strDefined( result[ k ] ) ); + status += status ? '\n' + k : k; + status += ':\n ' + _.strLinesIndentation( result[ k ], ' ' ); + } + } + + if( o.generatingPatch ) + result.patch = got.output; + + if( o.explaining && !o.detailing ) + status = got.output; + + result.status = o.explaining ? status : got.exitCode === 1; + + return result; + } + + /* */ + + function detailingHandle( got ) + { + let statusToPropertyMap = + { + 'A' : 'addedFiles', + // 'C' : 'copiedFiles', + 'C' : 'copiedFiles', /* aaa : ? */ /* Dmytro : fixed, not me, the task resolved in conversation */ + 'D' : 'deletedFiles', + 'M' : 'modifiedFiles', + 'R' : 'renamedFiles', + 'T' : 'typechangedFiles', + 'U' : 'unmergedFiles', + } + let lines = _.strSplitNonPreserving + ({ + src : got.output, + delimeter : '\n', + stripping : 1, + preservingEmpty : 1, + }); + let endOfRawOutput = _.longLeftIndex( lines, '' ); + endOfRawOutput = endOfRawOutput >= 0 ? endOfRawOutput : lines.length; + + for( let i = 0; i < endOfRawOutput; i++ ) + { + lines[ i ] = _.strSplitNonPreserving({ src : lines[ i ], delimeter : /\s+/, stripping : 1 }) + let type = lines[ i ][ 4 ].charAt( 0 ); + let path = lines[ i ][ 5 ]; + let pName = statusToPropertyMap[ type ]; + if( !pName ) + throw _.err( `Unexpected change type: ${_.strQuote( type )}, filePath: ${_.strQuote( path )}`, got.output ); + if( o.explaining ) + result[ pName ] += result[ pName ] ? '\n' + path : path; + else + result[ pName ] = true; + } + } + + /* - */ + + function handleResult() + { + result.state1 = state1; + result.state2 = state2; + if( !state1.exists || !state2.exists ) + result.status = _.maybe; + return result; + } +} + +diff.defaults = +{ + state1 : 'working', + state2 : 'committed', + localPath : null, + detailing : 1, + explaining : 1, + generatingPatch : 0, // https://git-scm.com/docs/git-diff.html#Documentation/git-diff.txt---patch + throwingDoesNotExist : 0, + linesOfContext : null, // https://git-scm.com/docs/git-diff.html#Documentation/git-diff.txt---unifiedltngt + coloredPatch : 0, // https://git-scm.com/docs/git-diff.html#Documentation/git-diff.txt---colorltwhengt + fetchTags : 0, + sync : 1 +} + +// + +function pull( o ) +{ + let ready = _.take( null ); + + _.assert( arguments.length === 1 ); + _.routine.options_( pull, arguments ); + _.assert( _.strDefined( o.localPath ) ); + + if( o.dry ) + return; + + let start = _.process.starter + ({ + sync : 0, + deasync : 0, + outputCollecting : 1, + mode : 'shell', + currentPath : o.localPath, + throwingExitCode : o.throwing, + inputMirroring : 1, + outputPiping : 1, + logger : o.logger, + ready, + }); + + start( `git pull` ); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + return ready; +} + +pull.defaults = +{ + localPath : null, + dry : 0, + sync : 1, + logger : null, + throwing : 0, +}; + +// + +function push( o ) +{ + _.assert( arguments.length === 1 ); + _.routine.options_( push, arguments ); + _.assert( _.strDefined( o.localPath ) ); + + let ready = _.take( null ); + + let start = _.process.starter + ({ + sync : 0, + deasync : 0, + outputCollecting : 1, + mode : 'shell', + currentPath : o.localPath, + throwingExitCode : o.throwing, + inputMirroring : 1, + outputPiping : 1, + logger : o.logger, + ready, + }); + + let dryRun = o.dry ? ' --dry-run' : ''; + let force = o.force ? ' --force' : ''; + + if( o.withHistory ) + start( `git push ${ dryRun } -u origin --all ${ force }` ); + if( o.withTags ) + { + verifyRemoteRepositoryHasCommitHistory(); + if( !o.force ) + verifyRemoteRepositoryHasNoTag(); + start( `git push ${ dryRun } --tags ${ force }` ); + } + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + return ready; + + /* */ + + function verifyRemoteRepositoryHasCommitHistory() + { + let unpushedTags = tagsUnpushedGet(); + + if( unpushedTags.length === 0 ) + return true; + + let commits = tagsCommitsGet( unpushedTags ); + + if( _.any( commits, remoteCommitNotExists ) ) + throw _.err + ( + `Repository at ${ o.localPath } has different commit history on remote server. `, + `Please, push history manually or enable option {-o.withHistory-}` + ); + return true; + } + + /* */ + + function tagsUnpushedGet() + { + let output = start + ({ + execPath : 'git push --tags --dry-run', + sync : 1, + outputPiping : 0, + inputMirroring : 0, + throwingExitCode : 0, + }).output; + let tags = output.match( /(\S+)\s->/gm ); + if( !tags ) + return []; + for( let i = 0 ; i < tags.length ; i++ ) + tags[ i ] = tags[ i ].split( ' ' )[ 0 ]; + return tags; + } + + /* */ + + function tagsCommitsGet( tags ) + { + let result = _.array.make( tags ); + for( let i = 0 ; i < tags.length ; i++ ) + { + let commit = start({ execPath : `git show-ref -s ${ tags[ i ] }`, sync : 1 }).output; + result[ i ] = commit.trim(); + } + return result; + } + + /* */ + + function remoteCommitNotExists( commit ) + { + let exists =_.git.repositoryHasVersion + ({ + localPath : o.localPath, + version : commit.trim(), + local : 0, + remote : 1, + }); + return !exists; + } + + /* */ + + function verifyRemoteRepositoryHasNoTag() + { + let currentTag = start({ execPath : 'git describe --abbrev=0 --tags', sync : 1 }).output; + let repoHasTag = _.git.repositoryHasTag + ({ + localPath : o.localPath, + tag : currentTag.trim(), + local : 0, + remote : 1, + }); + + if( repoHasTag ) + throw _.err + ( + `Remote repository of ${ o.localPath } has the same tags as local repository.`, + `Please, push tags manually or enable option {-o.force-} to rewrite tags` + ); + + return true; + } +} + +push.defaults = +{ + localPath : null, + withHistory : 1, + withTags : 0, + force : 0, + dry : 0, + sync : 1, + throwing : 0, + logger : null +}; + +// + +function reset_head( routine, args ) +{ + _.assert( arguments.length === 2 ); + + let o = args[ 0 ]; + _.assert( args.length === 1 ); + _.routine.options( routine, o ); + _.assert( _.strDefined( o.state1 ) ); + _.assert( _.strDefined( o.state2 ) ); + _.assert( _.strDefined( o.localPath ) ); + _.assert( _.longHas( [ null, 'all' ], o.preset ) ); + + o.logger = _.logger.maybe( o.logger ); + + if( o.preset === 'all' ) + { + _.assert( o.state2 === 'committed', 'Preset `all` resets all changes to latest commit' ); + + let o2 = + { + removingUntracked : 1, + removingSubrepositories : 1, + removingIgnored : 1, + }; + _.mapSupplementNulls( o, o2 ); + } + else + { + let o2 = + { + removingUntracked : 1, + removingSubrepositories : 1, + removingIgnored : 0, + }; + _.mapSupplementNulls( o, o2 ); + } + return o; +} + +// + +/* aaa : for Dmytro : use _.routine.unite */ /* Dmytro : done */ + +function reset_body( o ) +{ + let self = this; + + // _.assert( arguments.length === 1 ); + // _.routineOptions( reset, arguments ); + // _.assert( _.strDefined( o.state1 ) ); + // _.assert( _.strDefined( o.state2 ) ); + // _.assert( _.strDefined( o.localPath ) ); + // _.assert( _.longHas( [ null, 'all' ], o.preset ) ); + // + // o.logger = _.logger.maybe( o.logger ); + // + // if( o.preset === 'all' ) + // { + // _.assert( o.state2 === 'committed', 'Preset `all` resets all changes to latest commit' ); + // + // let o2 = + // { + // removingUntracked : 1, + // removingSubrepositories : 1, + // removingIgnored : 1, + // }; + // // _.mapExtend( o, o2 ); /* aaa : for Dmytro : should supplement */ /* Dmytro : done */ + // _.mapSupplement( o, o2 ); + // } + + /* */ + + let ready = _.take( null ); + + let start = _.process.starter + ({ + sync : 0, + deasync : 0, + outputCollecting : 1, + mode : 'shell', + currentPath : o.localPath, + throwingExitCode : 0, + inputMirroring : 0, + outputPiping : 0, + logger : o.logger, + ready + }); + + /* */ + + let state1 = self._stateParse( o.state1 ); + let state2 = self._stateParse( o.state2 ); + + if( o.dry ) + return resetDry(); + + if( state2.value === 'working' || state2.value === 'staged' ) + return; + + /* */ + + let commands = []; + + if( state1.isVersion || state1.isTag ) + commands.push( `git checkout ${ state1.value }` ); + // start( `git checkout ${ state1.value }` ); + /* aaa : for Dmytro : ? */ /* Dmytro : state1 define start point for resetting. If state is not tag or hash, then repository should not change this state */ + + if( state2.value === 'committed' ) + commands.push( `git reset --hard` ); + else if( state2.isVersion || state2.isTag ) + commands.push( `git reset --hard ${ state2.value }` ); + // if( state2.value === 'committed' ) + // start( `git reset --hard` ); + // else if( state2.isVersion || state2.isTag ) + // start( `git reset --hard ${ state2.value }` ); + + if( o.removingUntracked ) + { + let command = `git clean -df` + if( o.removingSubrepositories ) + command += 'f'; + if( o.removingIgnored ) + command += 'x'; + + commands.push( command ); + // start( command ); + } + + start( commands ); + + /* aaa : should be "git clean -dffx", but not by default */ /* Dmytro : implemented */ + /* aaa : cover each option */ /* Dmytro : covered */ + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + return ready; + + /* */ + + function resetDry() + { + let shouldReset = state2.isVersion || state2.isTag || state2.value === 'committed'; + let o2 = + { + localPath : o.localPath, + uncommitted : 0, + uncommittedUntracked : o.removingUntracked, + uncommittedAdded : o.removingUntracked, + uncommittedChanged : shouldReset, + uncommittedDeleted : shouldReset, + uncommittedRenamed : shouldReset, + uncommittedCopied : o.removingUntracked, + uncommittedIgnored : o.removingUntracked && o.removingIgnored, + unpushed : 0, + unpushedCommits : 0, + unpushedTags : 0, + unpushedBranches : 0, + explaining : 1, + detailing : 1, + sync : 1 + }; + let status = _.git.statusLocal( o2 ); + + /* */ + + let msgReset = `Uncommitted changes, would be reseted :`; + msgReset += status.uncommittedChanged ? `\n${ status.uncommittedChanged }` : ``; + msgReset += status.uncommittedDeleted ? `\n${ status.uncommittedDeleted }` : ``; + msgReset += status.uncommittedRenamed ? `\n${ status.uncommittedRenamed }` : ``; + o.logger.log( msgReset ); + + let msgClean = `Uncommitted changes, would be cleaned :`; + msgClean += status.uncommittedUntracked ? `\n${ status.uncommittedUntracked }` : ``; + msgClean += status.uncommittedAdded ? `\n${ status.uncommittedAdded }` : ``; + msgClean += status.uncommittedCopied ? `\n${ status.uncommittedCopied }` : ``; + msgClean += status.uncommittedIgnored ? `\n${ status.uncommittedIgnored }` : ``; + o.logger.log( msgClean ); + return true; + } +} + +reset_body.defaults = +{ + // logger : 1, + state1 : 'working', /* 'working', 'staged', 'committed' some commit or tag */ + state2 : 'committed', /* 'working', 'staged', 'committed' some commit or tag */ + localPath : null, + preset : null, /*[ null, 'all' ]*/ /* aaa : implement and cover option */ /* Dmytro : implemented, preset supplement options in reset_head */ + // removingUntracked : 1, + // removingIgnored : 0, /* aaa : implement and cover option */ /* Dmytro : implemented, covered */ + // removingSubrepositories : 1, /* aaa : implement and cover option. option -ffx of git command clean */ /* Dmytro : implemented, covered */ + removingUntracked : null, + removingIgnored : null, + removingSubrepositories : null, + dry : 0, /* aaa : implement and cover option */ /* Dmytro : implemented, covered */ + sync : 1, + logger : null +}; + +// + +const reset = _.routine.unite( reset_head, reset_body ); + +// + +let millisecondsConvert = null; + +function _getDelta( src ) +{ + if( _.number.is( src ) ) + return src; + + const negative = _.str.begins( src, '-' ); + if( negative ) + src = _.str.removeBegin( src, '-' ); + + let parts = src.trim().split( ':' ); + + if( parts.length === 3 ) + { + const hours = _.number.from( parts[ 0 ] ); + const days = Math.trunc( hours / 24 ); + let baseDelta = 86400000 * days; + parts[ 0 ] = hours - ( days * 24 ); + return ( baseDelta + Date.parse( `01 Jan 1970 ${ parts.join( ':' ) } GMT` ) ) * ( negative ? -1 : 1 ); + } + + _.assert( parts.length <= 1 ); + + if( millisecondsConvert === null ) + { + const unitsBaseRatio = + { + default : 'ms', + ms : 1, + s : 1000, + m : 60 * 1000, + h : 60 * 60 * 1000, + d : 24 * 60 * 60 * 1000, + }; + millisecondsConvert = _.units.unitsConvert_functor({ unitsBaseRatio }); + } + + parts = parts[ 0 ].split( /\s+/ ); + let result = 0; + for( let i = 0 ; i < parts.length ; i++ ) + result += millisecondsConvert({ src : parts[ i ] }); + return result * ( negative ? -1 : 1 ); +} + +// + +function _onDate_functor( o ) +{ + _.assert( arguments.length === 1 ); + _.mapSupplementNulls( o, _onDate_functor.defaults ); + _.assert + ( + _.longHas( [ 'now', 'commit', 'fromFirst' ], o.relative ), + () => 'Expects option {-o.relative-} with value "now" or "commit".' + ); + _.assert( _.number.intIs( o.delta ) || _.str.is( o.delta ) ); + _.assert( _.number.intIs( o.periodic ) || _.str.is( o.periodic ) ); + _.assert( _.number.intIs( o.deviation ) || _.str.is( o.deviation ) ); + + const delta = _getDelta( o.delta ); + + if( o.periodic ) + { + return onDatePeriodic_functor(); + } + else + { + if( o.relative === 'now' ) + { + if( delta === 0 ) + return dateNow; + else + return dateNowWithDelta; + } + + if( o.relative === 'commit' || o.relative === 'fromFirst' ) + { + if( delta === 0 ) + return dateCommit; + else + return dateCommitWithDelta; + } + } + + /* */ + + function dateNow( date ) + { + return new Date().toString(); + } + + /* */ + + function dateCommit( date ) + { + return date; + } + + /* */ + + function dateNowWithDelta( date ) + { + const time = Date.now(); + const dateObject = new Date( time + delta ); + return dateObject.toString(); + } + + /* */ + + function dateCommitWithDelta( date ) + { + const time = Date.parse( date ); + const dateObject = new Date( time + delta ); + return dateObject.toString(); + } + + /* */ + + function onDatePeriodic_functor() + { + let startTime; + if( o.relative === 'now' ) + startTime = _.time.now() + delta; + let counter = 0; + const period = _getDelta( o.periodic ); + _.assert( period >= 0 ); + const deviation = _getDelta( o.deviation ); + _.assert( deviation >= 0 ); + _.assert( deviation <= period, 'Deviation cannot be bigger than period.' ); + + if( o.relative === 'now' ) + return datePeriodicNow; + if( o.relative === 'fromFirst' ) + return datePeriodicCommitStrict; + return datePeriodicCommit; + + function datePeriodicNow( date ) + { + let result = startTime + ( counter * period ) + ( Math.random() * 2 * deviation - deviation ); + counter++; + return new Date( result ).toString(); + } + + function datePeriodicCommit( date ) + { + const time = Date.parse( date ) + delta; + let result = time + ( counter * period ) + ( Math.random() * 2 * deviation - deviation ); + counter++; + return new Date( result ).toString(); + } + + function datePeriodicCommitStrict( date ) + { + if( startTime === undefined ) + startTime = Date.parse( date ) + delta; + + let result = startTime + ( counter * period ) + ( Math.random() * 2 * deviation - deviation ); + counter++; + return new Date( result ).toString(); + } + } +} + +_onDate_functor.defaults = +{ + relative : 'now', // [ 'now', 'commit', 'fromFirst' ] + delta : null, + periodic : 0, + deviation : 0, +}; + +// + +function commitsDates( o ) +{ + _.assert( arguments.length === 1 ); + _.routine.options( commitsDates, o ); + _.assert( _.git.path.isAbsolute( o.localPath ), 'Expects absolute path to repository {-o.localPath-}.' ); + _.assert( _.str.defined( o.state1 ), 'Expects start commit to modify dates {-o.state1-}.' ); + + if( o.relative === 'commit' && o.delta === 0 && o.periodic === 0 ) + return true; + + const parsed = _.git.path.parse( o.localPath ); + + const localParsed = _.map.extend( null, parsed ); + delete localParsed.tag; + const localPath = _.git.path.str( localParsed ); + const ready = _.take( null ); + const start = _.process.starter + ({ + currentPath : localPath, + mode : 'shell', + outputCollecting : 1, + throwingExitCode : 1, + inputMirroring : 0, + sync : 0, + }); + + /* */ + + const onDate = _.git._onDate_functor( o ); + + const tempBranch = `_temp-${ _.idWithGuid() }`; + + if( !o.state2 ) + o.state2 = `!${ tempBranch }`; + const state1 = _.git._stateParse( o.state1 ).value; + const state2 = _.git._stateParse( o.state2 ).value; + + let descriptors; + ready.then( () => start( `git checkout ${ state1 }~` ) ); + ready.then( () => start( `git checkout -b ${ tempBranch }` ) ); + ready.then( () => start( `git merge ${ parsed.tag } ${ tempBranch }` ) ); + ready.then( () => start( `git checkout ${ parsed.tag }` ) ); + ready.then( () => _.git.repositoryHistoryToJson({ localPath, state1 : o.state1, state2 : `!${ tempBranch }` }) ); + ready.then( ( commits ) => descriptors = commits ); + ready.then( () => start( `git reset --hard ${ state1 }~` ) ); + ready.then( () => writeCommits( descriptors ) ); + ready.finally( () => + { + delete process.env.GIT_COMMITTER_DATE; + return start( `git branch --delete --force ${ tempBranch }` ) + }); + ready.finally( ( err, arg ) => + { + if( err ) + throw _.err( err ); + return true; + }); + + return ready; + + /* */ + + function writeCommits( commits ) + { + const con = _.take( null ); + let shouldUpdate = true; + for( let i = commits.length - 1 ; i >= 0 ; i-- ) + start({ execPath : `git cherry-pick --strategy=recursive -X theirs -n -m 1 ${ commits[ i ].hash }`, ready : con }) + .then( () => + { + let date = commits[ i ].date; + if( shouldUpdate ) + date = onDate( commits[ i ].date ); + if( commits[ i ].hash === state2 ) + shouldUpdate = false; + if( date.length ) + { + process.env.GIT_COMMITTER_DATE = date; + date = `--date="${ date }"`; + } + const author = `--author="${ commits[ i ].author } <${ commits[ i ].email }>"` + return start( `git commit --allow-empty -m "${ commits[ i ].message }" ${ author } ${ date }` ); + }); + return con; + } +} + +commitsDates.defaults = +{ + localPath : null, + state1 : null, + state2 : null, + relative : 'now', // [ 'now', 'commit' ] + delta : null, + periodic : 0, + deviation : 0, +}; + +// + +function tagList( o ) +{ + _.assert( arguments.length === 1, 'Expects options map {-o-}' ); + _.routine.options( tagList, o ); + _.assert( _.strDefined( o.localPath ), 'Expects local path to git repository {-o.localPath-}' ); + _.assert( _.numberIs( o.lines ), 'Expects number of lines {-o.lines-}' ); + + let start = _.process.starter + ({ + currentPath : o.localPath, + sync : 1, + mode : 'spawn', + outputCollecting : 1, + throwingExitCode : 1, + inputMirroring : 0, + outputPiping : 0, + }); + + let listOptions = o.withDescription ? '-ln' : `-l`; + let lines = o.withDescription ? o.lines : ''; + let result = start( `git tag ${ listOptions }${ lines }` ); + + return result.output; +} + +tagList.defaults = +{ + localPath : null, + withDescription : 1, + lines : 1, +}; + +// + +/* aaa : for Dmytro : implement tagDelete* - 2 routines for branch and ref tag, cover */ /* Dmytro : implemented and covered */ + +function tagDeleteBranch( o ) +{ + _.assert( arguments.length === 1, 'Expects options map {-o-}' ); + _.routine.options( tagDeleteBranch, o ); + _.assert( _.strDefined( o.localPath ), 'Expects local path to git repository {-o.localPath-}' ); + _.assert( _.strDefined( o.tag ), 'Expects tag {-o.tag-} to delete' ); + _.assert( !!o.local || !!o.remote ); + + let ready = _.take( null ); + let start = _.process.starter + ({ + currentPath : o.localPath, + sync : o.sync, + mode : 'shell', + ready, + outputCollecting : 1, + throwingExitCode : o.throwing, + inputMirroring : 0, + outputPiping : 0, + }); + + let force = o.force ? '--force' : ''; + + let commands = []; + if( o.local ) + commands.push( `git branch --delete ${ force } ${ o.tag }` ); + + if( o.remote ) + { + let remotePath = _.git.remotePathFromLocal( o.localPath ); + let tagExistsremote = _.git.repositoryHasTag + ({ + remotePath, + localPath : o.localPath, + tag : o.tag, + remote : 1, + local : 0 + }); + if( tagExistsremote ) + commands.push( `git push --delete ${ force } origin ${ o.tag }` ); + } + + start( commands ); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +tagDeleteBranch.defaults = +{ + localPath : null, + tag : null, + force : 1, + local : 1, + remote : 1, + throwing : 1, + sync : 0, +}; + +// + +function tagDeleteTag( o ) +{ + _.assert( arguments.length === 1, 'Expects options map {-o-}' ); + _.routine.options( tagDeleteTag, o ); + _.assert( _.strDefined( o.localPath ), 'Expects local path to git repository {-o.localPath-}' ); + _.assert( _.strDefined( o.tag ), 'Expects tag {-o.tag-} to delete' ); + _.assert( !!o.local || !!o.remote ); + + let ready = _.take( null ); + let start = _.process.starter + ({ + currentPath : o.localPath, + sync : o.sync, + mode : 'shell', + ready, + outputCollecting : 1, + throwingExitCode : o.throwing, + inputMirroring : 0, + outputPiping : 0, + }); + + let commands = []; + if( o.local ) + commands.push( `git tag --delete ${ o.tag }` ); + + if( o.remote ) + { + let remotePath = _.git.remotePathFromLocal( o.localPath ); + let tagExistsremote = _.git.repositoryHasTag + ({ + remotePath, + localPath : o.localPath, + tag : o.tag, + remote : 1, + local : 0 + }); + if( tagExistsremote ) + commands.push( `git push --delete ${ o.force ? '--force' : '' } origin refs/tags/${ o.tag }` ); + } + + start( commands ); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +tagDeleteTag.defaults = +{ + localPath : null, + tag : null, + force : 1, + local : 1, + remote : 1, + throwing : 1, + sync : 0, +}; + +// + +/** + * Routine tagMake() makes tag for some commit version of repository {-o.toVersion-}. + * If {-o.toVersion-} is not defined, then tag adds to current HEAD commit. + * + * @example + * // make tag `v0.1` if script run in git repository + * let tag = _.git.tagMake + * ({ + * localPath : _.path.current(), + * tag : 'v0.1', + * description : 'version 0.1', + * }); + * + * @param { Aux } o - Options map. + * @param { String } o.localPath - Path to git repository on hard drive. + * @param { String } o.tag - Name of tag. + * @param { String } o.description - Description of tag. + * @param { String } o.toVersion - Commit version to add tag. Default is current HEAD commit. + * @param { BoolLike } o.light - Enable lightweight tags. Default is 0. + * @param { BoolLike } o.force - Enable force creation of tags, it allows to rewrite tags with same name. Default is 1. + * @param { BoolLike } o.sync - Enable synchronous execution of code. Default is 1. + * @returns { Consequence|Aux } - Returns map like object with results of Process execution. + * or Consequence that handle such Process. + * @function tagMake + * @throws { Error } If arguments.length is not equal to 1. + * @throws { Error } If options map {-o-} has extra options. + * @throws { Error } If {-o.localPath-} is not a String with defined length. + * @throws { Error } If {-o.tag-} is not a String with defined length. + * @throws { Error } If added two tags with identical names to single commit and {-o.deleting-} is false. + * @namespace wTools.git + * @module Tools/mid/GitTools + */ + +function tagMake( o ) +{ + _.assert( arguments.length === 1, 'Expects options map {-o-}' ); + _.routine.options( tagMake, o ); + + let ready = _.take( null ); + let start = _.process.starter + ({ + currentPath : o.localPath, + deasync : 0, + sync : 0, + mode : 'shell', + ready, + outputCollecting : 1, + throwingExitCode : 1, + inputMirroring : 0, + outputPiping : 0, + logger : o.logger + }); + + // if( o.deleting ) + // { + // + // ready = _.git.repositoryHasTag + // ({ + // localPath : o.localPath, + // tag : o.tag, + // local : 1, + // remote : 0, + // sync : 0, + // }); + // + // ready.then( ( has ) => + // { + // if( has ) + // return start( `git tag -d ${o.tag}` ); + // return has; + // }) + // + // } + // else + // { + // ready = _.take( null ); + // } + // + // ready.then( () => + // { + + // let command = 'git tag'; + // if( o.force ) + // command += ' -f'; + // if( !o.toVersion ) + // o.toVersion = ''; + + // if( o.light ) + // return start( `git tag ${o.tag}` ); + // else + // return start( `git tag -a ${o.tag} -m "${o.description}"` ); + + let provider = _.fileProvider; /* Dmytro : should be hard drive provider */ + let path = provider.path; + let tag = o.tag; + let tempPath, description; + if( !o.light ) + { + tag = `-a ${ o.tag } -m "${ o.description }"`; + if( process.platform === 'win32' ) + { + let lines = _.strCount( o.description, '\n' ); + if( lines ) + { + tempPath = path.tempOpen( o.description ); + let descriptionPath = path.join( tempPath, 'description' ); + provider.fileWrite( descriptionPath, o.description ); + tag = `-a ${ o.tag } -F ${ path.nativize( descriptionPath ) }`; + } + } + } + let force = o.force ? '-f' : ''; + let toVersion = o.toVersion ? o.toVersion : ''; + + start( `git tag ${ force } ${ tag } ${ toVersion }` ); + + ready.finally( ( err, arg ) => + { + if( tempPath ) + path.tempClose( tempPath ); + + if( err ) + throw _.err( err ); + return arg; + }); + + // }); + // + // if( got.exitCode !== 0 || got.output && _.strHas( got.output, 'refs/' ) ) + // return false; + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +tagMake.defaults = +{ + localPath : null, + tag : null, + toVersion : null, /* aaa : for Dmytro : implement option, cover */ /* Dmytro : implemented and covered */ + force : 1, /* aaa : for Dmytro : implement option and use it instead of option deleting, cover */ /* Dmytro : implemented and covered */ + description : '', + light : 0, + // deleting : 1, + sync : 1, + logger : null +}; + +// + +function renormalize( o ) +{ + let localProvider = _.fileProvider; + let path = _.git.path; + // let path = localProvider.path; + + if( !_.mapIs( o ) ) + o = { localPath : o } + + _.routine.options_( renormalize, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( o.localPath ), 'Expects local path' ); + + let ready = new _.Consequence(); + + if( _.git.isRepository({ localPath : o.localPath }) ) + ready.take( null ); + else + ready.error( _.err( `Provided path is not a git repository:${o.localPath}` ) ); + + // if( !_.git.isRepository({ localPath : o.localPath }) ) + // ready.error( _.err( `Provided path is not a git repository:${o.localPath}` ) ); + // else + // ready.take( null ); + + if( o.safe ) + ready.then( () => + { + return _.git.statusLocal + ({ + localPath : o.localPath, + uncommitted : 1, + detailing : 0, + unpushed : 1, + explaining : 0, + sync : 0, + }); + }) + + ready.then( ( status ) => + { + if( _.object.isBasic( status ) && status.status ) + return true; + + let config = _.git.configRead( o.localPath ); + + if( !o.force ) + if( config.core.autocrlf === false ) + return true; + + if( o.audit ) + { + audit(); + } + + config.core.autocrlf = false; + + _.git.configSave( o.localPath, config ); + + return null; + }) + + ready.then( ( skip ) => + { + if( skip ) + return true; + + let con = _.take( null ) + let start = _.process.starter + ({ + // verbosity : o.verbosity - 1, + logger : _.logger.relativeMaybe( o.logger, -1 ), + verbosity : o.logger ? o.logger.verbosity - 1 : 0, + outputCollecting : 1, + currentPath : o.localPath, + ready : con + }); + + start( 'git rm --cached -r .' ) + start( 'git reset --hard' ) + + return con; + }) + + ready.catch( ( err ) => + { + if( !o.throwing ) + { + _.errAttend( err ); + return null; + } + + throw _.err( `Failed to renormalize repository at: ${o.localPath}\nReason:`, err ); + }) + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + + /* */ + + function audit() + { + let attributesPath = path.join( o.localPath, '.gitattributes' ); + if( !localProvider.fileExists( attributesPath ) ) + return; + let attributes = localProvider.fileRead( attributesPath ); + attributes = _.strSplitNonPreserving( attributes, '\n' ); + attributes = attributes.map( ( e ) => _.strSplitNonPreserving( e, /\s+/ ) ); + + attributes = attributes.filter( ( e ) => + { + if( _.longHasAny( e, [ 'text', 'text=auto' ] ) ) + if( !_.longHasAny( e, [ 'eol=crlf', 'eol=lf' ] ) ) + return true; + return false; + }) + + if( !attributes.length ) + return; + + attributes = attributes.map( ( e ) => e.join( ' ' ) ); + + logger.warn( `File .gitattributes from the repository at ${o.localPath} contains lines that can affect the result of EOL normalization.\nThese lines are:\n ${attributes.join('\n')}` ); + } +} + +renormalize.defaults = +{ + logger : 0, + localPath : null, + sync : 0, + safe : 1, + force : 0, + throwing : 0, + audit : 0 +} + +// -- +// relations +// -- + +var KnownHooks = +[ + 'applypatch-msg', + 'head-applypatch', + 'post-applypatch', + 'pre-commit', + 'prepare-commit-msg', + 'commit-msg', + 'post-commit', + 'head-rebase', + 'post-checkout', + 'post-merge', + 'head-push', + 'head-receive', + 'update', + 'post-receive', + 'post-update', + 'head-auto-gc', + 'post-rewrite', +] + +// -- +// declare +// -- + +let Extension = +{ + + protocols : [ 'git', 'git+http', 'git+https', 'git+ssh', 'git+hd', 'git+file' ], + + // dichotomy + + stateIsHash, + stateIsTag, + + // path + + // objectsParse, + // pathParse, + // pathIsFixated, + // pathFixate, + // remotePathNormalize /* aaa : for Dmytro : ?? */, /* Dmytro : commented, not used in module */ + // remotePathNativize, /* aaa : for Dmytro : ?? */ /* Dmytro : commented, not used in module */ + + remotePathFromLocal, + insideRepository, + localPathFromInside, + + // tag + + tagLocalChange, + tagLocalRetrive, + tagExplain, + + // version + + versionLocalChange, + localVersion, + remoteVersionLatest, + remoteVersionCurrent, + versionIsCommitHash, + versionsRemoteRetrive, + versionsPull, + + // dichotomy + + isUpToDate, + hasFiles, + hasRemote, + isRepository, + isHead, + sureHasOrigin, + + // status + + statusLocal, + statusRemote, + status, + statusFull, + + hasLocalChanges, /* xxx : use instead of _.git.status* in git commands */ + hasRemoteChanges, + hasChanges, + + // tag and version + + repositoryHasTag, + repositoryHasVersion, + repositoryTagToVersion, /* aaa : cover */ /* Dmytro : covered */ + repositoryVersionToTag, /* aaa : cover */ /* Dmytro : covered */ + exists, + + // hook + + hookRegister, + hookUnregister, + hookPreservingHardLinksRegister, + hookPreservingHardLinksUnregister, + + // ignore + + ignoreAdd, + ignoreRemove, + ignoreRemoveAll, + + // top + + repositoryInit, + repositoryDelete, /* qqq : cover */ /* Dmytro : base coverage for remote repository added */ + repositoryClone, + repositoryCheckout, + repositoryStash, + repositoryMerge, + + repositoryAgree, + repositoryMigrate, + + repositoryHistoryToJson, + + // config + + configRead, + configSave, + configReset, /* aaa : implement routine _.git.configReset() */ /* Dmytro : implemented and covered */ + + // + + _stateParse, + diff, + pull, + push, + reset, + + _onDate_functor, + commitsDates, + + // tag + + tagList, + tagDeleteBranch, + tagDeleteTag, + tagMake, /* aaa : cover */ /* Dmytro : covered */ + + renormalize, + +} + +/* _.props.extend */Object.assign( _.git, Extension ); + +// + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _global_.wTools; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgittools/proto/wtools/amid/l3/git/l1/Git.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgittools/proto/wtools/amid/l3/git/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Git_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Git_ss */ })(); + +/* */ /* begin of file Md_s */ ( function Md_s() { function Md_s_naked() { ( function _Md_s_() +{ + +'use strict'; + +const _ = _global_.wTools; +_.md = _.md || Object.create( null ); + +/* xxx : move out */ + +// -- +// implementation +// -- + +function parse_head( routine, args ) +{ + let o = args[ 0 ]; + if( _.str.is( o ) ) + o = { src : args[ 0 ] } + + _.assert( args.length === 1 ); + _.assert( arguments.length === 2 ); + + o = _.routine.options( routine, o ); + + return o; +} + +// + +function parse_body( o ) +{ + o.sectionArray = o.sectionArray || []; + o.sectionMap = o.sectionMap || Object.create( null ); + + let section = sectionOpen({ lineIndex : 0, charInterval : [ 0, 0 ] }); + let first = _.str.lines.at( o.src, 0 ); + let fromIndex = 0; + if( lineIsSectionHead( first.line ) ) + { + sectionHead( section, first ); + fromIndex += 1; + } + + let it = _.str.lines.each( o.src, [ fromIndex, Infinity ], ( it ) => + { + lineAnalyze( it ) + }); + + sectionClose( section, it ); + + return o; + + /* */ + + function lineAnalyze( it ) + { + if( lineIsSectionHead( it.line ) ) + { + sectionClose( section, it ); + section = sectionOpen( it ); + sectionHead( section, it ); + } + } + + /* */ + + function lineIsSectionHead( line ) + { + if( _.strBegins( line.trimStart(), o.headToken ) ) + return true; + return false; + } + + /* */ + + function sectionOpen( it ) + { + let section = Object.create( null ); + o.sectionArray.push( section ); + section.head = Object.create( null ); + section.head.text = null; + section.head.raw = null; + section.body = Object.create( null ); + section.body.text = null; + section.level = 0; + section.lineInterval = [ it.lineIndex ]; + section.charInterval = [ it.charInterval[ 0 ] ]; + return section; + } + + /* */ + + function sectionClose( section, it ) + { + section.lineInterval[ 1 ] = it.lineIndex - 1; + section.charInterval[ 1 ] = it.charInterval[ 0 ] - 1; + + section.body.lineInterval = section.lineInterval.slice(); + section.body.charInterval = section.charInterval.slice(); + if( section.head.charInterval ) + { + section.body.lineInterval[ 0 ] = section.head.lineIndex + 1; + section.body.charInterval[ 0 ] = section.head.charInterval[ 1 ] + 1; + } + + section.body.text = it.src.slice( section.body.charInterval[ 0 ], section.body.charInterval[ 1 ]+1 ); + section.text = it.src.slice( section.charInterval[ 0 ], section.charInterval[ 1 ]+1 ); + + } + + /* */ + + function sectionHead( section, it ) + { + let line = it.line.trimStart(); + let level = 0; + while( line[ 0 ] === o.headToken ) + { + level += 1; + line = line.slice( 1 ); + } + section.level = level; + section.head.raw = line; + section.head.text = line.trim(); + section.head.charInterval = it.charInterval.slice(); + section.head.lineIndex = it.lineIndex; + if( section.head.text !== null ) + { + o.sectionMap[ section.head.text ] = o.sectionMap[ section.head.text ] || []; + o.sectionMap[ section.head.text ].push( section ); + } + } + + /* */ + + function sectionAdopt( section, it ) + { + section.text += line; + } + + /* */ + +} + +parse_body.defaults = +{ + headToken : '#', + src : null, + withText : true, /* qqq : implement and cover */ +} + +let parse = _.routine.unite( parse_head, parse_body ); + +// + +function sectionArrayStr_body( o ) +{ + + o.sectionArray.forEach( ( section ) => + { + o.result += section.text; + }); + + return o.result; +} + +sectionArrayStr_body.defaults = +{ + headToken : '#', + sectionArray : null, + result : '', +} + +let sectionArrayStr = _.routine.unite( null, sectionArrayStr_body ); + +// + +function sectionStr_body( o ) +{ + +} + +sectionStr_body.defaults = +{ + headToken : '#', + section : null, +} + +let sectionStr = _.routine.unite( null, sectionStr_body ); + +// + +function _sectionReplace_head( routine, args ) +{ + let o = args[ 0 ]; + + if( args.length === 3 ) + { + o = { dst : args[ 0 ], name : args[ 1 ], section : args[ 2 ] } + } + + _.assert( args.length === 1 || args.length === 3 ); + _.assert( arguments.length === 2 ); + + o = _.routine.options( routine, o ); + + return o; +} + +// + +function structureSectionReplace_body( o ) +{ + + _.assert( _.str.is( o.section ) ); + _.assert( _.str.is( o.name ) ); + + if( !_.strEnds( o.section, [ '\n', '\n\r' ] ) ) + o.section = o.section + '\n'; + + if( _.str.is( o.dst ) ) + o.dst = _.md.parse( o.dst ); + + if( !o.dst.sectionMap[ o.name ] ) + { + o.replaced = false; + return o; + } + + o.dst.sectionMap[ o.name ].forEach( ( section ) => + { + section.text = o.section; + }); + + o.replaced = true; + return o; +} + +structureSectionReplace_body.defaults = +{ + dst : null, + name : null, + section : null, +} + +let structureSectionReplace = _.routine.unite( _sectionReplace_head, structureSectionReplace_body ); + +// + +function textSectionReplace_body( o ) +{ + + this.structureSectionReplace.body.call( this, o ); + + o.dst = this.sectionArrayStr( _.mapOnly_( null, o.dst, this.sectionArrayStr.defaults ) ); + + return o; +} + +textSectionReplace_body.defaults = +{ + ... structureSectionReplace.defaults, +} + +let textSectionReplace = _.routine.unite( _sectionReplace_head, textSectionReplace_body ); + +// -- +// declaretion +// -- + +let Extension = +{ + + parse, + + str : sectionArrayStr, + sectionArrayStr, + sectionStr, + + structureSectionReplace, + textSectionReplace, + +} + +/* _.props.extend */Object.assign( _.md, Extension ); + +// + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _global_.wTools; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgittools/proto/wtools/amid/l3/git/l1/Md.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wgittools/proto/wtools/amid/l3/git/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Md_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Md_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorbasic/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorbasic/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wintrospectorbasic */ ( function wintrospectorbasic() { function wintrospectorbasic_naked() { +module.exports = require( '../wtools/abase/l2_introspector/Include.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wIntrospectorBasic', 'wintrospectorbasic' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorbasic/proto/node_modules/wintrospectorbasic' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorbasic/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wintrospectorbasic_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wintrospectorbasic */ })(); + +/* */ /* begin of file Include_s */ ( function Include_s() { function Include_s_naked() { ( function _Include_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to generate functions, manage execution of such and analyze them. + @module Tools/base/IntrospectorBasic +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../node_modules/Tools' ); + + _.include( 'wStringer' ); + _.include( 'wPathBasic' ); + _.include( 'wConsequence' ); + + require( './l3/Introspector.s' ); + require( './l3/Node.s' ); + require( './l3/Tools.s' ); + + module[ 'exports' ] = wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorbasic/proto/wtools/abase/l2_introspector/Include.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorbasic/proto/wtools/abase/l2_introspector' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Include_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Include_s */ })(); + +/* */ /* begin of file Introspector_s */ ( function Introspector_s() { function Introspector_s_naked() { ( function _Introspector_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to generate functions. + @namespace Tools.instrospector + @extends Tools + @module Tools/base/IntrospectorBasic +*/ + +const _global = _global_; +const _ = _global_.wTools; + +// -- +// introspector +// -- + +function _visitedPush( o, element ) +{ + if( o.visited === null ) + o.visited = new Set; + _.assert( !o.visited.has( element ) ); + o.visited.add( element ); +} + +// + +function _visitedPop( o, element ) +{ + o.visited.delete( element ); +} + +// + +function _exportNodeHead( routine, args ) +{ + let o = args[ 0 ]; + + _.routine.options( routine, o ); + + if( o.locality === null ) + o.locality = o.namespacePath === null ? 'local' : 'global'; + + if( o.dstNode ) + { + _.assert( o.locals === null || o.locals === o.dstNode.locals ); + } + else + { + o.dstNode = _.introspector.node.namespace(); + if( o.locals ) + o.dstNode.locals = o.locals; + } + _.assert( o.dstNode.type === 'namespace' ); + + return o; +} + +// + +function elementsExportNode_head( routine, args ) +{ + let o = args[ 0 ]; + if( !_.aux.is( o ) || args.length > 1 ) + o = { srcContainer : args[ 0 ], namespacePath : args[ 1 ] === undefined ? null : args[ 1 ] } + return _.introspector._exportNodeHead( routine, [ o ] ); +} + +// + +function elementsExportNode_body( o ) +{ + + _.map.assertHasAll( o, elementsExportNode.defaults ); + _.introspector._visitedPush( o, o.srcContainer ); + + _.each( o.srcContainer, ( e, k ) => + { + _.introspector.elementExportNode + ({ + ... o, + name : k, + element : e, + }) + }); + + _.introspector._visitedPop( o, o.srcContainer ); + + return o; +} + +elementsExportNode_body.defaults = +{ + srcContainer : null, + namespacePath : null, + dstNode : null, + visited : null, + locality : null, + locals : null, +} + +const elementsExportNode = _.routine.unite( elementsExportNode_head, elementsExportNode_body ); + +// + +function elementExportNode_head( routine, args ) +{ + let o = args[ 0 ]; + if( !_.aux.is( o ) || args.length > 1 ) + o = + { + srcContainer : args[ 0 ], + namespacePath : args[ 1 ] === undefined ? null : args[ 1 ], + name : args[ 2 ] === undefined ? null : args[ 2 ], + } + + return _.introspector._exportNodeHead( routine, [ o ] ); +} + +// + +function elementExportNode_body( o ) +{ + let wrote = 0; + + verify(); + + _.introspector._visitedPush( o, o.element ); + + /* */ + + if( _.routineIs( o.element ) ) + { + + if( o.element.meta ) + { + if( o.element.meta.locals ) + localsExport( o.element.meta.locals ); + } + + if( o.element.vectorized ) + assign( [ o.name ], vectorizedExport( o.element ) ); + else if( o.element.head || o.element.body || o.element.tail ) + assign( [ o.name ], routineUnitedExport( o.element ) ); + else if( o.element.functor ) + assign( [ o.name ], routineFunctorExport( o.element ) ); + else if( o.element.composed ) + assign( [ o.name ], routineComposedExport( o.element ) ); + else + assign( [ o.name ], routineExport( o.element ) ); + + if( o.element.defaults ) + { + write( '\n' ); + assign( [ o.name, 'defaults' ], routineDefaultsExport( o.element ) ); + } + + if( o.element.meta ) + { + if( o.element.meta.globals ) + _.assert( 0, 'not implemented' ); + } + + } + else + { + assign( [ o.name ], _.entity.exportJs( o.element ) ); + write( ';' ); + } + + if( wrote > 0 ) + write( '\n\n//\n\n' ); + + /* */ + + _.introspector._visitedPop( o, o.element ); + + return o; + + /* */ + + function verify() + { + if( !Config.debug ) + return; + + _.map.assertHasAll( o, elementExportNode.defaults ); + + _.assert( o.dstNode.type === 'namespace' ); + _.assert( o.locality !== 'local' || o.namespacePath === null ); + _.assert + ( + _.strDefined( o.name ), + () => `Cant export, expects defined {-o.name-}, but got ${_.entity.strType( o.name )}` + ); + _.assert + ( + _.routine.is( o.element ) || _.primitive.is( o.element ) || _.regexp.is( o.element ) + || _.set.is( o.element ) || _.map.is( o.element ) || _.array.is( o.element ) || _.hashMap.is( o.element ) + , () => `Cant export ${o.name} is ${_.entity.strType( o.element )}` + ); + + } + + /* */ + + function write( src ) + { + _.assert( _.str.is( src ) ); + o.dstNode.elements.push( src ); + wrote += 1; + } + + /* */ + + function assign( path, right ) + { + + let left = assigningPathFor( ... path ); + if( o.locality === 'local' ) + { + if( o.dstNode.locals[ left.path ] !== undefined ) + { + if( _.introspector.node.exportString( o.dstNode.locals[ left.path ] ) === _.introspector.node.exportString( right ) ) + return; + throw _.err( `Duplication of local variable "${left.path}"` ); + } + } + + let node = Object.create( null ); + node.type = 'assign'; + node.locality = o.locality; + node.left = left; + node.right = right; + node.exportString = _.introspector.node._assignExportString; + wrote += 1; + o.dstNode.elements.push( node ); + if( node.left.path.length === 1 ) + o.dstNode.locals[ node.left.path ] = right; + } + + /* */ + + function strLinesIndentation( src, indent ) + { + if( indent === undefined ) + indent = ' '; + if( !src ) + return src; + return indent + _.strLinesIndentation( src, indent, false ); + } + + /* */ + + function assigningPathFor() + { + let node = Object.create( null ); + + node.type = 'assign.left'; + if( o.locality === 'local' ) + node.path = [ ... arguments ]; + else + node.path = [ o.namespacePath, ... arguments ]; + + node.prefix = ''; + if( o.locality === 'local' && node.path.length <= 1 ) + node.prefix = 'var '; + // node.prefix = 'const '; /* xxx : uncomment after refactoring of starter */ + + node.exportString = _.introspector.node._assignLeftExportString; + + return node; + } + + /* */ + + function routineDefaultsExport( routine ) + { + let r = '\n'; + let defaults = _.props.of( routine.defaults, { onlyEnumerable : 1, onlyOwn : 0 } ); + r += _.entity.exportJs( defaults ); + return r; + } + + /* */ + + function routineProperties( namespacePath, routine ) + { + let r = '' + routine = routineOriginal( routine ); + let c = 0; + for( const k in routine ) + { + if( c > 0 ) + r += '\n'; + r += `${namespacePath}.${k} = ` + _.entity.exportJs( routine[ k ] ); + c += 1; + } + + if( r ) + r = _.strLinesIndentation( r, ' ' ) + '\n'; + + return r; + } + + /* */ + + function routineExport( routine ) + { + if( routine.locals ) + localsExport( routine.locals ); + return routineOriginal( routine ).toString(); + } + + /* */ + + function routineOriginal( routine ) + { + _.assert( _.routineIs( routine ) ); + while( routine.original || routine.originalRoutine ) + routine = routine.original || routine.originalRoutine; + return routine; + } + + /* */ + + function routineUnitedExport( element ) + { + let result = +`( function() { +` + + if( element.head && element.head.composed ) + result += +` + ${_.strLinesIndentation( routineComposedExportBodies( element.head.composed.bodies, `_${element.name}_head` ), ' ' )} +` + + if( element.head && !element.head.composed ) + result += +` + const _${element.name}_head = ${_.strLinesIndentation( routineExport( element.head ), ' ' )} +${strLinesIndentation( routineProperties( `_${element.name}_head`, element.head ) )}` + + if( element.body ) + result += +` + const _${element.name}_body = ${_.strLinesIndentation( routineExport( element.body ), ' ' )} +${strLinesIndentation( routineProperties( `_${element.name}_body`, element.body ) )}` + + if( element.tail ) + result += +` + const _${element.name}_tail = ${_.strLinesIndentation( routineExport( element.tail ), ' ' )} +${strLinesIndentation( routineProperties( `_${element.name}_tail`, element.tail ) )}` + + if( !element.body || _.longHas( [ 'routine.unite', 'routine.uniteCloning_replaceByUnite' ], o.name ) ) + { + + result += +` + const _${element.name}_ = ${_.strLinesIndentation( routineExport( element ), ' ' )} + ${_.strLinesIndentation( routineProperties( `_${element.name}_`, element ), ' ' )};` + + if( element.head ) + result += `\n_${element.name}_.head = ` + `_${element.name}_head;`; + if( element.body ) + result += `\n_${element.name}_.body = ` + `_${element.name}_body;`; + if( element.tail ) + result += `\n_${element.name}_.tail = ` + `_${element.name}_tail;`; + } + else + { + result += +`\n const _${element.name}_ = _.routine.unite + ({ +` + if( element.head ) + result += +` head : _${element.name}_head,\n` + if( element.body ) + result += +` body : _${element.name}_body,\n` + if( element.tail ) + result += +` tail : _${element.name}_tail,\n` + result += +` });\n` + } + + result += +` + return _${element.name}_; +})();`; + + return result; + } + + /* */ + + function routineFunctorExport( element ) + { + let result = ''; + + if( element.functor.length === 0 ) + { + if( element.functor.functor ) + result += routineFunctorExport( element.functor ); + else + result += '( ' + routineExport( element.functor ) + ' )();'; + } + else + { + result += +`( function() +{ + const ${o.name} = ${routineExport( element )}; + ${o.name}.functor = ${element.functor.functor ? routineFunctorExport( element.functor ) : routineExport( element.functor )}; + return ${o.name}; +})();`; + } + return result; + } + + /* */ + + function vectorizedExport( element ) + { + let toVectorize = _.introspector.elementsExportNode + ({ + srcContainer : element.vectorized, + namespacePath : 'toVectorize', + }); + let functor = +` +(function() +{ + let toVectorize = Object.create( null ); + ${toVectorize.dstNode.exportString()} + return _.vectorize( toVectorize ); +})(); +` + return functor; + } + + /* */ + + function routineComposedExportBodies( bodies, dstContainerName ) + { + if( dstContainerName === undefined ) + dstContainerName = 'bodies'; + + let result = `const ${dstContainerName} = [];`; + + bodies.forEach( ( body, i ) => + { + let name = `_body_${i}`; + let bodyExported = _.introspector.elementExportNode + ({ + srcContainer : bodies, + element : body, + name, + locality : 'local' + }) + result += `\n ${bodyExported.dstNode.exportString()}`; + result += `\n ${dstContainerName}.push( ${name} );`; + }) + + return result; + } + + /* */ + + function routineComposedExport( routine ) + { + let bodies = routine.composed.bodies; + + let result = +`( function() { +` + result += `\n ${routineComposedExportBodies( bodies )}`; + + let chainerExported = _.introspector.elementExportNode + ({ + srcContainer : routine.composed, + element : routine.composed.chainer, + name : 'chainer', + locality : 'local' + }) + + let tailExported = _.introspector.elementExportNode + ({ + srcContainer : routine.composed, + element : routine.composed.tail, + name : 'tail', + locality : 'local' + }) + + result += `\n ${chainerExported.dstNode.exportString()}`; + result += `\n ${tailExported.dstNode.exportString()}`; + + result += `\n const _${o.name}_ = _.routine.s.compose({ bodies, chainer, tail });` + + result += +` + return _${o.name}_; +})(); +` + return result; + } + + /* */ + + function localsExport( locals ) + { + let o2 = _.mapOnly_( null, o, _.introspector.elementsExportNode.defaults ); + o2.srcContainer = locals; + o2.namespacePath = null; + o2.locality = 'local'; + _.introspector.elementsExportNode.body.call( _.introspector, o2 ); + } + + /* */ + +} + +elementExportNode_body.defaults = +{ + ... elementsExportNode.defaults, + name : null, + element : _.nothing, +} + +const elementExportNode = _.routine.unite( elementExportNode_head, elementExportNode_body ); + +// + +function selectAndExportString( srcContainer, namespacePath, name ) +{ + let element = _.select({ src : srcContainer, selector : name, upToken : '.' }); + return _.introspector.elementExportNode + ({ + srcContainer, + namespacePath, + element, + name, + }); +} + +// + +function field( namesapce, name ) +{ + if( arguments.length === 2 ) + { + return _.introspector.selectAndExportString( _[ namesapce ], `_.${namesapce}`, name ).dstNode.exportString(); + } + else + { + name = arguments[ 0 ]; + return _.introspector.selectAndExportString( _, '_', name ).dstNode.exportString(); + } +} + +// + +function rou( namesapce, name ) +{ + if( arguments.length === 2 ) + { + return _.introspector.selectAndExportString( _[ namesapce ], `_.${namesapce}`, name ).dstNode.exportString(); + } + else + { + name = arguments[ 0 ]; + return _.introspector.selectAndExportString( _, '_', name ).dstNode.exportString(); + } +} + +// + +function fields( namespace ) +{ + let result = []; + _.assert( _.object.isBasic( _[ namespace ] ) ); + for( let f in _[ namespace ] ) + { + let e = _[ namespace ][ f ]; + if( _.strIs( e ) || _.regexpIs( e ) ) + result.push( rou( namespace, f ) ); + } + return result.join( ' ' ); +} + +// + +function cls( namesapce, name ) +{ + let r; + if( arguments.length === 2 ) + { + r = _.introspector.selectAndExportString( _[ namesapce ], `_.${namesapce}`, name ).dstNode.exportString(); + } + else + { + name = arguments[ 0 ]; + r = _.introspector.selectAndExportString( _, '_', name ).dstNode.exportString(); + } + r = +` +(function() +{ + +const Self = ${r} + +})(); +` + return r; +} + +// + +function clr( cls, method ) +{ + let result = ''; + if( _[ cls ][ method ] ) + result = _.introspector.selectAndExportString( _[ cls ], `_.${cls}`, method ).dstNode.exportString(); + if( _[ cls ][ 'prototype' ][ method ] ) + result += '\n' + _.introspector.selectAndExportString( _[ cls ][ 'prototype' ], `_.${cls}.prototype`, method ).dstNode.exportString(); + return result; +} + +// -- +// introspector extension +// -- + +let IntrospectorExtension = +{ + + _visitedPush, + _visitedPop, + _exportNodeHead, + + elementsExportNode, + elementExportNode, + selectAndExportString, + + field, + rou, + fields, + cls, + clr, + +} + +Object.assign( _.introspector, IntrospectorExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorbasic/proto/wtools/abase/l2_introspector/l3/Introspector.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorbasic/proto/wtools/abase/l2_introspector/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Introspector_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Introspector_s */ })(); + +/* */ /* begin of file Node_s */ ( function Node_s() { function Node_s_naked() { ( function _Node_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to generate functions. + @namespace Tools.instrospector.node + @extends Tools + @module Tools/base/IntrospectorBasic +*/ + +const _global = _global_; +const _ = _global_.wTools; + +_.introspector.node = _.introspector.node || Object.create( null ); + +// -- +// +// -- + +function namespace() +{ + let node = Object.create( null ); + node.type = 'namespace'; + node.locals = Object.create( null ); + node.elements = []; + node.exportString = _.introspector.node._namespaceExportString; + return node +} + +// + +function exportString( src ) +{ + let result = ''; + if( _.str.is( src ) ) + result += src; + else + { + _.assert( _.routine.is( src.exportString ) ); + result += src.exportString(); + } + return result; +} + +// + +function _namespaceExportString() +{ + let result = ''; + this.elements.forEach( ( element ) => + { + result += _.introspector.node.exportString( element ) + }); + return result; +} + +// + +function _assignExportString() +{ + let result = ''; + let l = _.introspector.node.exportString( this.left ); + let r = _.introspector.node.exportString( this.right ); + if( r[ 0 ] === '\n' ) + result += l + ' =' + r; + else + result += l + ' = ' + r; + return result; +} + +// + +function _assignLeftExportString() +{ + let result = this.prefix + this.path.join( '.' ); + return result; +} + +// -- +// introspector extension +// -- + +let NodeExtension = +{ + + namespace, + + exportString, + + _namespaceExportString, + _assignExportString, + _assignLeftExportString, + +} + +Object.assign( _.introspector.node, NodeExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorbasic/proto/wtools/abase/l2_introspector/l3/Node.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorbasic/proto/wtools/abase/l2_introspector/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Node_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Node_s */ })(); + +/* */ /* begin of file Tools_s */ ( function Tools_s() { function Tools_s_naked() { ( function _Tools_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +let Esprima; + +// -- +// routine +// -- + +/** + * Return function that will call passed routine function with delay. + * @param {number} delay delay in milliseconds + * @param {Function} routine function that will be called with delay. + * @returns {Function} result function + * @throws {Error} If arguments less then 2 + * @throws {Error} If `delay` is not a number + * @throws {Error} If `routine` is not a function + * @function routineDelayed + * @namespace Tools.program + */ + +function routineDelayed( delay, routine ) +{ + + _.assert( arguments.length >= 2, 'Expects at least two arguments' ); + _.assert( _.numberIs( delay ) ); + _.assert( _.routineIs( routine ) ); + + if( arguments.length > 2 ) + { + _.assert( arguments.length <= 4 ); + routine = _.routineJoin.call( _, arguments[ 1 ], arguments[ 2 ], arguments[ 3 ] ); + } + + return function delayed() + { + _.time.out( delay, this, routine, arguments ); + } + +} + +// + +/** + * Calls function( routine ) with custom context( context ) and arguments( args ). + * @param {Object} context custom context + * @param {Function} routine function that will be called + * @param {Array} args arrat of arguments + * @function routineCall + * @namespace Tools.program + */ + +function routineCall( context, routine, args ) +{ + let result; + + _.assert( 1 <= arguments.length && arguments.length <= 3 ); + + /* */ + + if( arguments.length === 1 ) + { + let routine = arguments[ 0 ]; + result = routine(); + } + else if( arguments.length === 2 ) + { + let context = arguments[ 0 ]; + let routine = arguments[ 1 ]; + result = routine.call( context ); + } + else if( arguments.length === 3 ) + { + let context = arguments[ 0 ]; + let routine = arguments[ 1 ]; + let args = arguments[ 2 ]; + _.assert( _.longIs( args ) ); + result = routine.apply( context, args ); + } + else _.assert( 0, 'unexpected' ); + + return result; +} + +// + +/** + * Calls function with custom context and options. + * Takes only options that are supported by provided routines. + * + * @param {Object} context custom context + * @param {Function} routine function that will be called + * @param {Object} options options map + * @function routineTolerantCall + * @namespace Tools.program + */ + +function routineTolerantCall( context, routine, options ) +{ + + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + _.assert( _.routineIs( routine ) ); + _.assert( _.object.isBasic( routine.defaults ) ); + _.assert( _.object.isBasic( options ) ); + + options = _.mapOnly_( null, options, routine.defaults ); + let result = routine.call( context, options ); + + return result; +} + +// + +function routinesJoin() +{ + let result, routines, index; + let args = _.longSlice( arguments ); + + _.assert( arguments.length >= 1 && arguments.length <= 3 ); + + /* */ + + function makeResult() + { + + _.assert( _.object.isBasic( routines ) || _.arrayIs( routines ) || _.routineIs( routines ) ); + + if( _.routineIs( routines ) ) + routines = [ routines ]; + + result = _.entity.cloneShallow( routines ); + + } + + /* */ + + if( arguments.length === 1 ) + { + routines = arguments[ 0 ]; + index = 0; + makeResult(); + } + else if( arguments.length === 2 ) + { + routines = arguments[ 1 ]; + index = 1; + makeResult(); + } + else if( arguments.length === 3 ) + { + routines = arguments[ 1 ]; + index = 1; + makeResult(); + } + else _.assert( 0, 'unexpected' ); + + /* */ + + if( _.arrayIs( routines ) ) + for( let r = 0 ; r < routines.length ; r++ ) + { + args[ index ] = routines[ r ]; + result[ r ] = _.routineJoin.apply( this, args ); + } + else + for( let r in routines ) + { + args[ index ] = routines[ r ]; + result[ r ] = _.routineJoin.apply( this, args ); + } + + /* */ + + return result; +} + +// + +function _routinesCall( o ) +{ + let result, context, routines, args; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( o.args.length >= 1 && o.args.length <= 3 ); + + /* */ + + if( o.args.length === 1 ) + { + routines = o.args[ 0 ]; + + makeResult(); + + if( _.arrayIs( routines ) ) + for( let r = 0 ; r < routines.length ; r++ ) + { + result[ r ] = routines[ r ](); + if( o.whileTrue && result[ r ] === false ) + { + result = false; + break; + } + } + else + for( let r in routines ) + { + result[ r ] = routines[ r ](); + if( o.whileTrue && result[ r ] === false ) + { + result = false; + break; + } + } + + } + else if( o.args.length === 2 ) + { + context = o.args[ 0 ]; + routines = o.args[ 1 ]; + + makeResult(); + + if( _.arrayIs( routines ) ) + for( let r = 0 ; r < routines.length ; r++ ) + { + result[ r ] = routines[ r ].call( context ); + if( o.whileTrue && result[ r ] === false ) + { + result = false; + break; + } + } + else + for( let r in routines ) + { + result[ r ] = routines[ r ].call( context ); + if( o.whileTrue && result[ r ] === false ) + { + result = false; + break; + } + } + + } + else if( o.args.length === 3 ) + { + context = o.args[ 0 ]; + routines = o.args[ 1 ]; + args = o.args[ 2 ]; + + _.assert( _.longIs( args ) ); + + makeResult(); + + if( _.arrayIs( routines ) ) + for( let r = 0 ; r < routines.length ; r++ ) + { + result[ r ] = routines[ r ].apply( context, args ); + if( o.whileTrue && result[ r ] === false ) + { + result = false; + break; + } + } + else + for( let r in routines ) + { + result[ r ] = routines[ r ].apply( context, args ); + if( o.whileTrue && result[ r ] === false ) + { + result = false; + break; + } + } + + } + else _.assert( 0, 'unexpected' ); + + return result; + + /* */ + + function makeResult() + { + + _.assert + ( + _.object.isBasic( routines ) || _.arrayIs( routines ) || _.routineIs( routines ), + 'Expects object, array or routine (-routines-), but got', _.entity.strType( routines ) + ); + + if( _.routineIs( routines ) ) + routines = [ routines ]; + + result = _.entity.cloneShallow( routines ); + + } + +} + +_routinesCall.defaults = +{ + args : null, + whileTrue : 0, +} + +// + +/** +* Call each routines in array with passed context and arguments. + The context and arguments are same for each called functions. + Can accept only routines without context and args. + Can accept single routine instead array. +* @example + let x = 2, y = 3, + o { z : 6 }; + + function sum( x, y ) + { + return x + y + this.z; + }, + prod = function( x, y ) + { + return x * y * this.z; + }, + routines = [ sum, prod ]; + let res = wTools.routinesCall( o, routines, [ x, y ] ); // [ 11, 36 ] +* +* @param {Object} [context] Context in which calls each function. +* @param {Function} routines Array of called function +* @param {Array} [args] Arguments that will be passed to each functions. +* @returns {Array} Array with results of functions invocation. +* @function routinesCall +* @namespace Tools.program +*/ + +function routinesCall() +{ + let result; + + result = _routinesCall + ({ + args : arguments, + whileTrue : 0, + }); + + return result; +} + +// + +function routinesCallEvery() +{ + let result; + + result = _routinesCall + ({ + args : arguments, + whileTrue : 1, + }); + + return result; +} + +// + +/** + * @summary Calls provided methods with custom context and arguments. + * @description + * Each method is called with onlyOwn context. Arguments are common. Saves result of each call into array. + * @param {Array} contexts array of contexts + * @param {Function} methods methods that will be called + * @param {Array} [args] arguments array + * @throws {Error} If context for the method doesn't exist or vise versa. + * @returns {Array} Returns results of methods call as array. + * @function methodsCall + * @namespace Tools.program + */ + +function methodsCall( contexts, methods, args ) +{ + let result = []; + + if( args === undefined ) + args = []; + + let isContextsArray = _.longIs( contexts ); + let isMethodsArray = _.longIs( methods ); + let l1 = isContextsArray ? contexts.length : 1; + let l2 = isMethodsArray ? methods.length : 1; + let l = Math.max( l1, l2 ); + + _.assert( l >= 0 ); + _.assert( arguments.length === 2 || arguments.length === 3, 'Expects two or three arguments' ); + + if( !l ) + return result; + + let contextGet; + if( isContextsArray ) + contextGet = ( i ) => contexts[ i ]; + else + contextGet = ( i ) => contexts; + + let methodGet; + if( isMethodsArray ) + methodGet = ( i ) => methods[ i ]; + else + methodGet = ( i ) => methods; + + for( let i = 0 ; i < l ; i++ ) + { + let context = contextGet( i ); + let routine = context[ methodGet( i ) ]; + _.assert( _.routineIs( routine ) ); + result[ i ] = routine.apply( context, args ) + } + + return result; +} + +// -- +// +// -- + +/** + * @summary Extracts routine's source code. + * @description + * Accepts options map or routine as single argument. + * @param {Object} o options map + * @param {Function} o.routine source function + * @param {Boolean} o.wrap=1 + * @param {Boolean} o.withWrap=1 wraps source code with routine definition + * @param {Boolean} o.usingInline=1 + * @param {Object} o.toJsOptions=null options for {@link module:Tools/base/Stringer.Stringer.toJs} routine + * + * @example //source code and definition + * _.routineSourceGet( _.routineDelayed ); + * + * @example //only source code + * _.routineSourceGet({ routine : _.routineDelayed, withWrap : 0 }); + * + * @returns {String} Returns routine's source code as string. + * @function routineSourceGet + * @namespace Tools.program + */ + +function routineSourceGet( o ) +{ + if( _.routineIs( o ) ) + o = { routine : o }; + + _.routine.options_( routineSourceGet, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.routineIs( o.routine ) ); + _.assert( _.routineIs( o.routine.toSource ) || _.routineIs( o.routine.toString ) ); + + let result = o.routine.toSource ? o.routine.toSource() : o.routine.toString(); + + if( !o.withWrap ) + result = unwrap( result )[ 1 ]; + + if( o.usingInline && o.routine.inlines ) + { + let prefix = '\n'; + for( let i in o.routine.inlines ) + { + let inline = o.routine.inlines[ i ]; + prefix += ' let ' + i + ' = ' + _.entity.exportJs( inline, o.toJsOptions || Object.create( null ) ) + ';\n'; + } + let splits = unwrap( result ); + splits[ 1 ] = prefix + '\n' + splits[ 1 ]; + result = splits.join( '' ); + } + + return result; + + function unwrap( code ) + { + + let reg1 = /^\s*function\s*\w*\s*\([^\)]*\)\s*\{/; + let reg2 = /\}\s*$/; + + let before = reg1.exec( code ); + let after = reg2.exec( code ); + + if( before && after ) + { + code = code.replace( reg1, '' ); + code = code.replace( reg2, '' ); + } + + return [ before[ 0 ], code, after[ 0 ] ]; + } + +} + +routineSourceGet.defaults = +{ + routine : null, + wrap : 1, + withWrap : 1, + usingInline : 1, + toJsOptions : null, +} + +// + +/** + * @summary Makes routine from source code. + * @description + * Accepts options map or routine's source code as single argument. + * @param {Object} o options map + * @param {Boolean} o.debug=0 prepends `debugger` prefix + * @param {String} o.code=null source code + * @param {String} o.filePath=null path to source file, will be inserted as comment + * @param {Boolean} o.prependingReturn=0 prepends `return` statement before source code + * @param {Boolean} o.fallingBack=1 tries to make routine without `return` prefix if first attempt with `o.prependingReturn:1` fails. + * @param {Boolean} o.usingStrict=0 enables strict mode + * @param {Object} o.externals=null map with external properties that are needed for routine + * @param {String} o.name=null name of the routine + * + * @example //source code and definition + * let src = 'return 1' + * let routine = _.routineMake( src ); + * routine(); //1 + * + * @example //filePath + * let src = 'return 1' + * let routine = _.routineMake({ code : src, filePath : '/path/to/source.js' }); + * routine.toString(); + * + * @example //prependingReturn + * let src = '1' + * let routine = _.routineMake({ code : src, prependingReturn : 1 }); + * routine(); //1 + * + * @example //using externals option + * let src = 'return a'; + * let routine = _.routineMake({ code : src, externals : { a : 1 } }); + * routine(); + * + * @returns {Function} Returns created function. + * @function routineSourceGet + * @namespace Tools.program + */ + +function routineMake( o ) +{ + let result; + + if( _.strIs( o ) ) + o = { code : o }; + + _.routine.options_( routineMake, o ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.object.isBasic( o.externals ) || o.externals === null ); + _.assert( !!_realGlobal_ ); + + /* prefix */ + + let prefix = '\n'; + + if( o.usingStrict ) + prefix += `'use strict';\n`; + if( o.debug ) + prefix += 'debugger;\n'; + if( o.filePath ) + prefix += '// ' + o.filePath + '\n'; + + if( o.externals ) + { + if( !_realGlobal_.__wTools__externals__ ) + _realGlobal_.__wTools__externals__ = []; + _realGlobal_.__wTools__externals__.push( o.externals ); + prefix += '\n'; + for( let e in o.externals ) + prefix += 'let ' + e + ' = ' + '_realGlobal_.__wTools__externals__[ ' + String( _realGlobal_.__wTools__externals__.length-1 ) + ' ].' + e + ';\n'; + prefix += '\n'; + } + + /* */ + + let code; + try + { + + if( o.prependingReturn ) + try + { + code = prefix + 'return ' + o.code.trimLeft(); + result = make( code ); + } + catch( err ) + { + if( o.fallingBack ) + { + code = prefix + o.code; + result = make( code ); + } + else throw err; + } + else + { + code = prefix + o.code; + result = make( code ); + } + + } + catch( err ) + { + + // err = _.err( 'Cant parse the routine\n', _.strLinesNumber( '\n' + code ), '\n', err ); + err = _.err( err, `\nCant parse the routine ${o.name || ''}` ); + + if( _global.document ) + { + let e = document.createElement( 'script' ); + e.type = 'text/javascript'; + e.src = 'data:text/javascript;charset=utf-8,' + escape( o.code ); + document.head.appendChild( e ); + } + else if( _global.Blob && _global.Worker ) + { + let worker = _.makeWorker( code ); + } + else handleErrorWithEsprima( err ) + err = _.err( _.strLinesNumber( code ), '\n', err ); + + // throw _.err( err, '\n', 'More information about error is comming asynchronously..' ); + throw err; + return null; + } + + return result; + + /* */ + + function handleErrorWithEsprima( err ) + { + + if( !Esprima && !_global.esprima ) + try + { + Esprima = require( 'esprima' ); + } + catch( err ) + { + } + + if( Esprima || _global.esprima ) + { + let esprima = Esprima || _global.esprima; + try + { + let parsed = esprima.parse( '(function(){\n' + code + '\n})();' ); + } + catch( err2 ) + { + if( err2.lineNumber !== undefined ) + code = _.strLinesSelect + ({ + src : code, + nearestLines : 5, + line : err2.lineNumber + }); + throw _._err + ({ + args : [ err, err2 ], + level : 1, + sourceCode : code, + }); + } + return true; + } + + return false; + } + + /* */ + + function make( code ) + { + try + { + if( o.name ) + code = 'return function ' + o.name + '()\n{\n' + code + '\n}'; + let result = new Function( code ); + if( o.name ) + result = result(); + return result; + } + catch( err ) + { + throw _.err( err ); + } + } + +} + +routineMake.defaults = +{ + debug : 0, + code : null, + filePath : null, + // prependingReturn : 1, + prependingReturn : 0, + fallingBack : 1, + usingStrict : 0, + externals : null, + name : null, +} + +// + +/** + * @summary Makes routine from source code and executes it. + * @description + * Accepts options map or routine's source code as single argument. + * @param {Object} o options map + * @param {Boolean} o.debug=0 prepends `debugger` prefix + * @param {String} o.code=null source code + * @param {String} o.filePath=null path to source file, will be inserted as comment + * @param {Boolean} o.prependingReturn=0 prepends `return` statement before source code + * @param {Boolean} o.fallingBack=1 tries to make routine without `return` prefix if first attempt with `o.prependingReturn:1` fails. + * @param {Boolean} o.usingStrict=0 enables strict mode + * @param {Object} o.externals=null map with external properties that are needed for routine + * @param {String} o.name=null name of the routine + * @param {Object} o.context=null executes routine with provided context + * + * @example + * let src = 'return 1' + * let r = _.routineExec( src ); + * console.log( r.result ); //1 + * + * @example //execute with custom context + * let src = 'return this.a' + * let r = _.routineExec({ code : src, context : { a : 1 } }); + * console.log( r.result ); //1 + * + * @returns {Object} Returns options map with result of execution in `result` property. + * @function routineExec + * @namespace Tools.program + */ + +function routineExec( o ) +{ + let result = Object.create( null ); + + if( _.strIs( o ) ) + o = { code : o }; + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options_( routineExec, o ); + + o.routine = _.routineMake + ({ + code : o.code, + debug : o.debug, + filePath : o.filePath, + prependingReturn : o.prependingReturn, + externals : o.externals, + }); + + /* */ + + try + { + if( o.context ) + o.result = o.routine.apply( o.context ); + else + o.result = o.routine.call( _global ); + } + catch( err ) + { + throw _._err + ({ + args : [ err ], + level : 1, + sourceCode : { code : o.routine.toString() }, + throwLocation : { filePath : o.filePath }, + }); + } + + /* */ + + return o; +} + +var defaults = routineExec.defaults = Object.create( routineMake.defaults ); + +defaults.context = null; + +// + +/** + * @summary Short-cut for {@link module:Tools/base/IntrospectorBasic.IntrospectorBasic.routineExec} routine. + * Returns result of routine execution instead of options map. + * @param {Object} o options map + * @param {Boolean} o.debug=0 prepends `debugger` prefix + * @param {String} o.code=null source code + * @param {String} o.filePath=null path to source file, will be inserted as comment + * @param {Boolean} o.prependingReturn=0 prepends `return` statement before source code + * @param {Boolean} o.fallingBack=1 tries to make routine without `return` prefix if first attempt with `o.prependingReturn:1` fails. + * @param {Boolean} o.usingStrict=0 enables strict mode + * @param {Object} o.externals=null map with external properties that are needed for routine + * @param {String} o.name=null name of the routine + * @param {Object} o.context=null executes routine with provided context + * + * @example + * let src = 'return 1' + * let r = _.exec( src ); + * console.log( r); //1 + * + * @example //execute with custom context + * let src = 'return this.a' + * let r = _.exec({ code : src, context : { a : 1 } }); + * console.log( r ); //1 + * + * @returns {} Returns result of routine execution. + * @function exec + * @namespace Tools.program + */ + +function exec( o ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + if( _.strIs( o ) ) + o = { code : o }; + _.routineExec( o ); + return o.result; +} + +var defaults = exec.defaults = Object.create( routineExec.defaults ); + +// + +function execInWorker( o ) +{ + let result; + + if( _.strIs( o ) ) + o = { code : o }; + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options_( execInWorker, o ); + + let blob = new Blob( [ o.code ], { type : 'text/javascript' } ); + let worker = new Worker( URL.createObjectURL( blob ) ); + + throw _.err( 'not implemented' ); + +} + +execInWorker.defaults = +{ + code : null, +} + +// + +function makeWorker( o ) +{ + let result; + + if( _.strIs( o ) ) + o = { code : o }; + _.assert( arguments.length === 1, 'Expects single argument' ); + _.routine.options_( makeWorker, o ); + + let blob = new Blob( [ o.code ], { type : 'text/javascript' } ); + let worker = new Worker( URL.createObjectURL( blob ) ); + + return worker; +} + +makeWorker.defaults = +{ + code : null, +} + +// -- +// +// -- + +function routineNew( routine, name, usingExtendtype ) +{ + _.assert( _.routineIs( routine ), 'creating routine from string is not implemented' ); + + if( usingExtendtype === undefined ) usingExtendtype = true; + if( name === undefined ) name = '_noname_'; + + let f = new Function( 'let _' + name + ' = arguments[ 0 ];\nreturn function ' + name + ' ()\n{\n return ' + '_' + name + '(this, arguments) \n};' ); + let result = f( Function.prototype.apply.bind( routine ) ); + + result._name = name; + + if( usingExtendtype ) + result.prototype = routine.prototype; + + return result; +} + +// + +function routineInfo( routine ) +{ + + _.assert( _.routineIs( routine ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + let result = _routineInfo + ({ + routine, + tab : '', + }); + + return result; +} + +// + +function _routineInfo( o ) +{ + let result = ''; + let assets = _.mapOnly_( null, o.routine, _routineAssets ); + + result += o.routine.name || 'noname'; + result += '\n'; + result += _.entity.exportString( assets, { levels : 2, tab : o.tab, prependTab : 1, wrap : 0 }); + result += '\n----------------\n'; + + o.tab += ' '; + + for( let i in o.routine.inline ) + { + result += o.tab + i + ' : '; + let opt = _.props.extend( null, o ); + o.routine = o.routine.inline[ i ]; + result += _routineInfo( o ); + } + + return result; +} + +// + +function routineCollectAssets( dst, routine ) +{ + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.routineIs( routine ) ); + + return _routineCollectAssets( dst, routine, [] ); +} + +// + +function _routineCollectAssets( dst, routine, visited ) +{ + + _.assert( _.routineIs( routine ) ); + _.assert( visited.indexOf( routine ) === -1 ); + visited.push( routine ); + + for( let a in _routineAssets ) + { + + if( !routine[ a ] ) + continue; + + dst[ a ] = dst[ a ] || Object.create( null ); + _.map.assertHasNone( dst[ a ], routine[ a ] ); + dst[ a ] = _.mapsFlatten + ({ + src : [ dst[ a ], routine[ a ] ], + allowingCollision : 0, + }); + + } + + if( dst.inline ) + for( let i in dst.inline ) + { + + if( visited.indexOf( dst.inline[ i ] ) === -1 ) + _routineCollectAssets( dst, dst.inline[ i ], visited ); + + } + +} + +// + +_global_._routineIsolate = []; +function routineIsolate( o ) +{ + + if( _.routineIs( o ) ) + o = { routine : o }; + _.assert( o.routine ); + _.map.assertHasOnly( o, routineIsolate.defaults ); + + let name = o.name || o.routine.name; + _.assert( _.strIs( name ) && name.length ); + + _.routineCollectAssets( o, o.routine ); + + /* */ + + let parsed; + + if( o.inline || o.routine.inline ) + { + + parsed = _.routineInline + ({ + routine : o.routine, + inline : o.inline, + }); + + } + else + { + + parsed = { source : o.routine.toString() }; + + } + + /* */ + + let sconstant = ''; + if( o.constant ) + for( let s in o.constant ) + { + sconstant += 'const ' + s + ' = ' + _.entity.exportString( o.constant[ s ], { levels : 99, escaping : 1 } ) + ';\n'; + } + + /* */ + + let sexternal = ''; + if( o.external ) + { + + let descriptor = Object.create( null ); + _routineIsolate.push( descriptor ); + descriptor.external = o.external; + + for( let s in o.external ) + { + sexternal += 'const ' + s + ' = ' + '_routineIsolate[ ' + ( _routineIsolate.length-1 ) + ' ].external.' + s + '' + ';\n'; + } + + } + + /* */ + + let source = + sconstant + '\n' + + sexternal + '\n' + + ( o.debug ? 'debugger;\n' : '' ) + + 'return ( ' + parsed.source + ' );'; + + let result = new Function + ( + o.args || [], + source + )(); + + result.inline = o.inline; + result.external = o.external; + result.constant = o.constant; + + return result; +} + +routineIsolate.defaults = +{ + routine : null, + constant : null, + external : null, + inline : null, + debug : 0, + name : null, +} + +// + +function routineInline( o ) +{ + + if( _.routineIs( o ) ) + o = { routine : o }; + _.assert( _.routineIs( o.routine ) ); + _.assert( arguments.length === 1 ); + _.routine.options_( routineInline, o ); + + // if( _.routineIs( o ) ) + // o = { routine : o }; + // _.assert( o.routine ); + // + // if( o.routine.debugParse ) + // debugger; + + let source = o.routine.toString(); + let result = Object.create( null ); + result.source = source; + + // + + if( o.routine.inline ) + { + o.inline = o.inline || Object.create( null ); + _.map.assertHasNone( o.inline, o.routine.inline ); + o.inline = _.mapsFlatten + ({ + src : [ o.inline, o.routine.inline ], + allowingCollision : 0, + }); + } + + // + + if( !o.inline || !Object.keys( o.inline ).length ) + return _.routineParse( o.routine ); + + let inlined = 0; + + if( !inlines() ) + return _.routineParse( o.routine ); + + if( !inlines() ) + return _.routineParse( o.routine ); + + while( inlines() ); + + return _.routineParse( o.routine ); + // return parse(); + + // // + // + // function parse() + // { + // + // let r = /function\s+(\w*)\s*\(([^\)]*)\)(\s*{[^]*})$/; + // + // let parsed = r.exec( source ); + // + // result.name = parsed[ 1 ]; + // result.args = _.strSplitNonPreserving + // ({ + // src : parsed[ 2 ], + // delimeter : ',', + // preservingDelimeters : 0, + // }); + // result.body = parsed[ 3 ]; + // + // result.reproduceSource = function() + // { + // return 'function ' + result.name + '( ' + result.args.join( ', ' ) + ' )\n' + result.body; + // } + // + // return result; + // } + + // + + function inlineFull( ins, sub ) + { + + let regexp = new RegExp( '(((let\\s+)?(\\w+)\\s*=\\s*)?|(\\W))(' + ins + ')\\s*\\.call\\s*\\(([^)]*)\\)', 'gm' ); + let rreturn = /return(\s+([^;}]+))?([;}]?)/mg; + result.source = result.source.replace( regexp, function( original ) + { + + _.assert( sub.name ); + + /* let */ + + let r = ''; + let variableName = arguments[ 4 ]; + let body = sub.body; + + /* args */ + + let args = _.strSplitNonPreserving + ({ + src : arguments[ 7 ], + delimeter : ',', + preservingDelimeters : 0, + }); + + _.assert( args.length - 1 === sub.args.length ); + + let renamedArgs = _.strJoin([ '_' + sub.name + '_', sub.args, '_' ]); + /*let renamedArgs = _.strStick( sub.args.slice(),'_' + sub.name + '_', '_' );*/ + body = _.strReplaceWords( body, sub.args, renamedArgs ); + + for( let a = 0 ; a < renamedArgs.length ; a++ ) + { + r += ' let ' + renamedArgs[ a ] + ' = ' + args[ a+1 ] + ';'; + } + + /* return */ + + if( variableName ) + r += 'let ' + variableName + ';\n'; + + body = body.replace( rreturn, function() + { + throw _.err( 'not tested' ); + + let rep = '{ '; + rep += variableName; + rep += ' = '; + rep += _.strStrip( arguments[ 2 ] || '' ) ? arguments[ 2 ] : 'undefined'; + rep += arguments[ 3 ]; + rep += ' }'; + return rep; + }); + + /* body */ + + r += body; + + r = '\n/* _inlineFull_' + ins + '_ */\n{\n' + r + '\n}\n/* _inlineFull_' + ins + '_ */\n'; + + /* validation */ + + if( Config.debug ) + if( r.indexOf( 'return' ) !== -1 ) + { + throw _.err( 'not expected' ); + } + + inlined += 1; + + return r; + }); + + } + + // + + function inlineCall( ins, sub ) + { + + let regexp = new RegExp( '(\\W)(' + ins + ')\\s*\\.', 'gm' ); + result.source = result.source.replace( regexp, function( b ) /* Yevhen : was : a, b, c, d, e, removed unused a, c, d, e */ + { + inlined += 1; + return b + '/* _inlineCall_' + ins + '_ */' + '( ' + sub.source + ' ).' + '/* _inlineCall_' + ins + '_ */'; + }); + + } + + // + + function inlineRegular( ins, sub ) + { + + let regexp = new RegExp( '(\\W)(' + ins + ')(\\W)', 'gm' ); + result.source = result.source.replace( regexp, function( b, d ) /* Yevhen : was : a, b, c, d, e, removed unused a, c, e */ + { + inlined += 1; + return b + '/* _inlineRegular_' + ins + '_ */( ' + sub.source + ' )/* _inlineRegular_' + ins + '_ */' + d; + }); + + } + + // + + function inline( ins, sub ) + { + + inlined = 0; + + if( !_.routineIs( sub ) ) + throw _.err( 'not tested' ); + + /* + if( _.routineIs( sub ) ) + { + sub = _.routineInline( sub ); + } + else + { + let sub = { source : sub }; + throw _.err( 'not tested' ); + } + */ + + sub = _.routineInline( sub ); + + let regexp = new RegExp( 'function\\s+' + ins + '\\s*\\(', 'gm' ); + sub.source = sub.source.replace( regexp, 'function _' + ins + '_(' ); + + /**/ + + let returnCount = _.strCount( sub.source, 'return' ); + if( returnCount === 0 && sub.body ) + { + + inlineFull( ins, sub ); + + } + + inlineCall( ins, sub ); + inlineRegular( ins, sub ); + + /**/ + + return inlined; + } + + // + + function inlines() + { + let r = 0; + + for( let i in o.inline ) + { + r += inline( i, o.inline[ i ] ); + } + + return r; + } + +} + +routineInline.defaults = +{ + routine : null, + inline : null, +} + +// + +/** + * @summary Gets information about routine( routine ). + * Result contains such information: + * * routine's name + * * arguments + * * full source code( including definition ) + * * routine's body( code inside square brackets ) + * @param {Function} routine source routine + * + * @returns {Object} Returns map with information about provided routine. + * @function routineParse + * @namespace Tools.program + */ + +function routineParse( o ) +{ + + if( _.routineIs( o ) ) + o = { routine : o }; + _.assert( _.routineIs( o.routine ) ); + _.assert( arguments.length === 1 ); + _.routine.options_( routineParse, o ); + + let source = o.routine.toString(); + let result = Object.create( null ); + result.source = source; + + return parse(); + + /* */ + + function parse() + { + + let r = /function\s+(\w*)\s*\(([^\)]*)\)(\s*{[^]*})$/; + let parsed = r.exec( source ); + + result.name = parsed[ 1 ]; + result.args = _.strSplitNonPreserving + ({ + src : parsed[ 2 ], + delimeter : ',', + preservingDelimeters : 0, + preservingEmpty : 0, + stripping : 1, + quoting : 0, + }); + result.body = parsed[ 3 ]; + result.bodyUnwrapped = _.strRemove( result.body, /(?:^\s*{)|(?:}\s*$)/g ); + + result.reproduceSource = function() + { + return 'function ' + result.name + '( ' + result.args.join( ', ' ) + ' )\n' + result.body; + } + + return result; + } + +} + +routineParse.defaults = +{ + routine : null, +} + +// -- +// declare +// -- + +let _routineAssets = +{ + inline : 'inline', + external : 'external', + constant : 'constant', +} + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + routineDelayed, + + routineCall, + routineTolerantCall, + + routinesJoin, + _routinesCall, + routinesCall, + routinesCallEvery, + methodsCall, + + // + + routineSourceGet, + + routineMake, /* xxx : review */ + routineExec, + + exec, + + execInWorker, + makeWorker, + + // + + routineNew, + routineInfo, + + routineCollectAssets, + _routineCollectAssets, + routineIsolate, + routineInline, + + routineParse, + + _routineAssets, + +} + +Object.assign( _, ToolsExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorbasic/proto/wtools/abase/l2_introspector/l3/Tools.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorbasic/proto/wtools/abase/l2_introspector/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorextra/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorextra/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wintrospectorextra */ ( function wintrospectorextra() { function wintrospectorextra_naked() { +module.exports = require( '../wtools/abase/l2_introspector/entry/IntrospectorExtra.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wIntrospectorExtra', 'wintrospectorextra' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorextra/proto/node_modules/wintrospectorextra' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorextra/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wintrospectorextra_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wintrospectorextra */ })(); + +/* */ /* begin of file IntrospectorExtra_s */ ( function IntrospectorExtra_s() { function IntrospectorExtra_s_naked() { ( function _IntrospectorExtra_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to write programs on drive. + * @module Tools/base/IntrospectorExtra +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + require( '../include/Mid.s' ); + module[ 'exports' ] = _; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorextra/proto/wtools/abase/l2_introspector/entry/IntrospectorExtra.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorextra/proto/wtools/abase/l2_introspector/entry' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, IntrospectorExtra_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file IntrospectorExtra_s */ })(); + +/* */ /* begin of file Base_s */ ( function Base_s() { function Base_s_naked() { ( function _Base_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + + _.include( 'wIntrospectorBasic' ); + _.include( 'wFilesBasic' ); + + module[ 'exports' ] = wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorextra/proto/wtools/abase/l2_introspector/include/Base.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorextra/proto/wtools/abase/l2_introspector/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Base_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Base_s */ })(); + +/* */ /* begin of file Mid_s */ ( function Mid_s() { function Mid_s_naked() { ( function _Mid_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( './Base.s' ); + + require( '../l3/Program.s' ); + + module[ 'exports' ] = wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorextra/proto/wtools/abase/l2_introspector/include/Mid.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorextra/proto/wtools/abase/l2_introspector/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Mid_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Mid_s */ })(); + +/* */ /* begin of file Program_s */ ( function Program_s() { function Program_s_naked() { ( function _Program_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to generate functions. + * @namespace Tools.program + * @extends Tools + * @module Tools/base/IntrospectorExtra + */ + +const _global = _global_; +const _ = _global_.wTools; +_.program = _.program || Object.create( null ); + +// -- +// program +// -- + +function groupPreformLocals_body( o ) +{ + + _.map.assertHasAll( o, groupPreformLocals_body.defaults ); + + if( o.locals === null ) + { + o.locals = Object.create( null ); + o.locals.toolsPath = _.path.nativize( _.module.toolsPathGet() ); + } + + if( o.withSubmodules ) + { + o.locals.pathAmend_body = _.module.filePathAmend.body; + } + + return o.locals; +} + +groupPreformLocals_body.defaults = +{ + locals : null, + withSubmodules : true, +}; + +let groupPreformLocals = _.routine.unite( null, groupPreformLocals_body ); + +// + +function filePreform( o ) +{ + + _.routine.options( filePreform, o ); + _.assert( !o.routine || !o.routine.name || o.name === o.routine.name ); + _.assert( _.strDefined( o.name ), 'Program should have name' ); + _.assert + ( + _.routineIs( o.routine ) || _.strIs( o.routineCode ) || o.routineCode === null, + 'Expects either option::routine or option:routineCode' + ); + + o.codeLocals = o.codeLocals || Object.create( null ); + + if( o.routineCode === null ) + { + if( _.routineIs( o.routine ) ) + { + let r = _.introspector.elementExportNode({ element : o.routine, name : o.name, locals : o.codeLocals }); + o.routineCode = r.dstNode.exportString(); + } + else + { + o.routineCode = o.routine; + } + } + + _.assert( _.str.is( o.routineCode ) !== _.str.is( o.fullCode ) ); + + if( o.fullCode === null ) + if( o.group.locals || o.locals ) + if( o.localsCode === undefined || o.localsCode === null ) + { + o.localsCode = ''; + if( o.group.locals ) + { + let exported = _.introspector.elementsExportNode({ srcContainer : o.group.locals, locals : o.codeLocals }); + o.localsCode += exported.dstNode.exportString(); + } + if( o.locals ) + { + let exported = _.introspector.elementsExportNode({ srcContainer : o.locals, locals : o.codeLocals }); + o.localsCode += exported.dstNode.exportString(); + } + } + + if( o.fullCode === null ) + if( !o.startCode ) + { + + if( o.group.withSubmodules ) + { + let paths = _.module.filePathGet + ({ + locally : 1, + globally : 0, + moduleFile : o.group.moduleFile, + }).local; + _.assert( paths.length > 0 ); + _.assert( _.arrayIs( paths ) ); + o.startCode += +` + pathAmend_body + ({ + moduleFile : module, + paths : ${_.entity.exportJs( paths )}, + permanent : 0, + globally : 0, + locally : 1, + recursive : 2, + amending : 'prepend', + }); +`; + } + + o.startCode += +` +${o.name}(); +` + } + + if( o.fullCode === null ) + { + o.fullCode = ''; + + add( o.group.prefixCode, 'group prefix code' ); + add( o.prefixCode, 'prefix code' ); + + add( o.routineCode ); + add( o.localsCode, 'locals code' ); + add( o.group.beforeStartCode, 'group before start code' ); + add( o.beforeStartCode, 'before start code' ); + add( o.startCode, 'start code' ); + add( o.afterStartCode, 'after start code' ); + add( o.group.afterStartCode, 'group after start code' ); + + add( o.postfixCode, 'postfix code' ); + add( o.group.postfixCode, 'group postfix code' ); + + } + + if( o.group.logger && o.group.logger.verbosity ) + { + o.group.logger.log( o.filePath/*programPath*/ ); + if( o.routineCode !== null ) + if( o.group.logger.verbosity >= 2 ) + o.group.logger.log( _.strLinesNumber( o.routineCode ) ); + } + + return o; + + function add( code, name ) + { + if( !code ) + return; + if( name ) + o.fullCode += `\n/* -- ${name} -- */\n`; + o.fullCode += code; + } + +} + +filePreform.defaults = +{ + + routine : null, + name : null, + + prefixCode : '', + routineCode : null, + postfixCode : '', + beforeStartCode : '', + startCode : '', + afterStartCode : '', + fullCode : null, + + filePath : null, + dirPath : null, + namePrefix : null, + namePostfix : null, + + group : null, + locals : null, + codeLocals : null, + localsCode : null, + +} + +// + +function groupPreform_body( o ) +{ + + _.map.assertHasAll( o, groupPreform_body.defaults ); + _.map.assertHasOnly( o, groupPreform_body.defaults ); + + /* locals */ + + _.program.groupPreformLocals.body.call( _.program, o ); + o.entry.codeLocals = o.entry.codeLocals || Object.create( null ); + + /* files */ + + o.files = o.files || Object.create( null ); + _.assert( _.aux.is( o.files ) ); + + _.assert( _.aux.is( o.entry ) ); + if( !o.entry.name && o.entry.routine ) + o.entry.name = o.entry.routine.name; + _.assert( !o.entry.routine || !o.entry.routine.name || o.entry.name === o.entry.routine.name ); + _.assert( _.strDefined( o.entry.name ), 'Program should have name' ); + + _.assert( o.files[ o.entry.name ] === undefined || o.files[ o.entry.name ] === o.entry ); + o.files[ o.entry.name ] = o.entry.routine; + + o.files = o.files || Object.create( null ); + o.files[ o.entry.name ] = o.entry; + + for( let name in o.files ) + { + if( name === o.entry.name ) + continue; + let program = o.files[ name ]; + if( _.routine.is( program ) ) + { + let routine = program; + program = o.files[ name ] = _.map.extend( null, o.entry ); + program.routine = routine; + program.name = name; + delete program.codeLocals; + } + else + { + _.map.supplement( program, _.mapBut_( null, o.entry, [ 'codeLocals' ] ) ); + program.name = name; + } + } + + for( let name in o.files ) + { + let file = o.files[ name ]; + _.assert( name === file.name ); + _.assert( !file.routine || !file.routine.name || file.name === file.routine.name ); + _.program.filePreform( o.files[ name ] ); + } + + return o; +} + +groupPreform_body.defaults = +{ + entry : null, + files : null, + locals : null, + withSubmodules : true, + moduleFile : null, + prefixCode : '', + beforeStartCode : '', + afterStartCode : '', + postfixCode : '', +} + +let groupPreform = _.routine.unite( null, groupPreform_body ); + +// + +function preform_head( routine, args ) +{ + let o = args[ 0 ]; + if( !_.mapIs( o ) ) + o = { entry : o } + _.routine.options( routine, o ); + _.assert( args.length === 1 ); + _.assert( arguments.length === 2 ); + + if( o.logger !== undefined ) + o.logger = _.logger.maybe( o.logger ); + + if( o.moduleFile === null ) + { + let moduleFile = _.module.fileNativeWith( 2 ); + if( moduleFile ) + o.moduleFile = moduleFile; + } + + return o; +} + +// + +function preform_body( o ) +{ + + _.map.assertHasAll( o, preform_body.defaults ); + _.assert( o.group === null ); + _.assert( o.localsCode === undefined ); + _.assert + ( + _.routine.is( o.entry ) || _.str.is( o.entry ) || _.aux.is( o.entry ) || o.entry === null, + () => `Expects entry which is any of [ routine, string, aux, null ], but it is ${_.strType( o.entry )}` + ); + _.assert( ( o.entry === null ) === ( _.strDefined( o.routineCode ) ) ); + + o.group = Object.create( null ); + o.group.files = o.files; + o.group.locals = o.locals; + o.group.withSubmodules = o.withSubmodules; + o.group.moduleFile = o.moduleFile; + o.group.files = o.files = o.files || Object.create( null ); + o.group.prefixCode = o.prefixCode; + o.group.postfixCode = o.postfixCode; + o.group.beforeStartCode = o.beforeStartCode; + o.group.afterStartCode = o.afterStartCode; + delete o.files; + delete o.locals; + delete o.withSubmodules; + delete o.moduleFile; + delete o.prefixCode; + delete o.postfixCode; + delete o.beforeStartCode; + delete o.afterStartCode; + + filesPreform(); + + if( _.strDefined( o.routineCode ) ) + entryFromRoutineCode(); + else if( _.routine.is( o.entry ) ) + entryFromRoutine(); + else + entryFromAux(); + + o.group.entry.name = o.group.entry.name || o.name; + o.group.entry.routineCode = o.group.entry.routineCode || o.routineCode; + o.group.entry.startCode = o.group.entry.startCode || o.startCode; + o.group.entry.fullCode = o.group.entry.fullCode || o.fullCode; + o.group.entry.group = o.group; + delete o.name; + delete o.routineCode; + delete o.startCode; + delete o.fullCode; + + _.program.groupPreform.body.call( _.program, o.group ); + o.files = o.group.files; + + return o; + + /* */ + + function filesPreform() + { + if( _.str.is( o.entry ) ) + o.entry = o.group.files[ o.entry ]; + + let matchedEntry; + let entryIsFile = _.aux.is( o.entry ); + let entryIsRoutine = _.routine.is( o.entry ); + + for( let name in o.group.files ) + { + let file = o.group.files[ name ]; + let fileIsRoutine = _.routine.is( file ); + let routine; + + if( fileIsRoutine ) + routine = file; + else + routine = file.routine; + + if( entryIsFile ) + { + if( eq( entryIsRoutine, fileIsRoutine, o.entry, file ) ) + { + _.assert( fileIsRoutine || file === o.entry ); + matchedEntry = file = o.entry; + } + else if( fileIsRoutine ) + { + file = { routine }; + } + } + else + { + if( eq( entryIsRoutine, fileIsRoutine, o.entry, file ) ) + { + file = { routine }; + matchedEntry = o.entry = file; + } + else if( fileIsRoutine ) + { + file = { routine } + } + } + + _.assert( _.aux.is( file ) ); + _.assert( file.name === undefined || file.name === name ); + _.assert( !file.routine || !file.routine.name || file.routine.name === name ); + + file.name = name; + o.group.files[ name ] = file; + } + + if( o.entry !== null ) + { + + if( !matchedEntry ) + { + if( _.routine.is( o.entry ) ) + o.entry = { routine : o.entry } + if( o.entry.name === undefined ) + o.entry.name = o.entry.routine.name; + _.assert( _.strDefined( o.entry.name ) ); + _.assert( !o.group.files[ o.entry.name ] ); + o.group.files[ o.entry.name ] = o.entry; + } + + _.assert( _.aux.is( o.entry ) ); + _.assert( o.entry === o.group.files[ o.entry.name ] ); + + } + + } + + /* */ + + function eq( /* entryIsRoutine, fileIsRoutine, entry, file */ ) + { + let entryIsRoutine = arguments[ 0 ]; + let fileIsRoutine = arguments[ 1 ]; + let entry = arguments[ 2 ]; + let file = arguments[ 3 ]; + + if( entryIsRoutine === fileIsRoutine ) + return entry === file; + else if( entryIsRoutine ) + return entry === file.routine; + else + return entry.routine === file; + } + + /* */ + + function entryFromFiles( name ) + { + if( o.group.files ) + { + let entry2 = o.group.files[ name ]; + if( entry2 ) + { + if( _.aux.is( entry2 ) ) + { + _.assert( entry2.name === undefined || entry2.name === name ); + entry2.name = name; + return entry2; + } + else + { + _.assert( _.routine.is( entry2 ) ); + let entry = Object.create( null ); + entry.routine = entry2; + entry.name = name; + o.group.files[ name ] = entry; + return entry + } + } + } + } + + /* */ + + function entryFromRoutineCode() + { + let entry; + + _.assert( o.entry === null ); + _.assert( _.strDefined( o.routineCode ) ); + _.assert( _.strDefined( o.name ) ); + + if( o.group.files ) + { + entry = entryFromFiles( o.name ); + } + + if( !entry ) + { + entry = Object.create( null ); + entry.name = o.name; + } + + entry.routineCode = o.routineCode; + o.entry = o.group.entry = entry; + } + + /* */ + + function entryFromRoutine() + { + let entry; + let routine = o.entry; + let name = o.name || o.entry.name; + _.assert( _.strDefined( name ) ); + if( o.group.files ) + { + let entry2 = entryFromFiles( name ); + if( entry2 ) + { + _.assert( !entry2.routine || entry2.routine === routine ); + entry2.routine = routine; + entry = o.entry = o.group.entry = entry2; + } + } + if( !entry ) + { + entry = o.entry = o.group.entry = Object.create( null ); + entry.routine = routine; + entry.name = name; + if( o.group.files ) + o.group.files[ name ] = entry; + } + } + + /* */ + + function entryFromAux() + { + _.assert( _.aux.is( o.entry ) ); + let entry = o.group.entry = o.entry; + let name = o.name || o.entry.name || o.entry.routine.name; + _.assert( _.strDefined( name ) ); + + if( o.group.files ) + { + let entry2 = o.group.files[ name ]; + if( entry2 ) + { + if( _.aux.is( entry2 ) ) + { + _.assert( entry2 === entry ); + } + else + { + _.assert( _.routine.is( o.group.files[ name ] ) ); + _.assert( o.group.files[ name ] === entry.routine ); + } + } + o.group.files[ name ] = entry; + } + } + + /* */ + +} + +preform_body.defaults = +{ + ... _.mapBut_( null, filePreform.defaults, [ 'group', 'codeLocals', 'localsCode', 'routine' ] ), + entry : null, + files : null, + group : null, + locals : null, + withSubmodules : true, + moduleFile : null, +} + +let preform = _.routine.unite( preform_head, preform_body ); + +// + +function fileWrite( o ) +{ + _.routine.options( fileWrite, o ); + + if( o.filePath === null ) + { + o.dirPath = o.dirPath === null ? o.group.dirPath : o.dirPath; + o.namePrefix = o.namePrefix === null ? o.group.namePrefix : o.namePrefix; + o.namePostfix = o.namePostfix === null ? o.group.namePostfix : o.namePostfix; + if( !o.group.tempPath ) + { + o.group.tempObject = _.program._tempOpen(); + o.group.tempPath = o.group.tempObject.tempPath; + } + _.assert( _.strIs( o.group.tempPath ), 'Expects temp path {- o.tempPath -}' ); + _.assert( _.strIs( o.dirPath ), 'Expects dir path {- o.dirPath -}' ); + _.assert( _.strIs( o.namePrefix ), 'Expects name prefix {- o.namePrefix -}' ); + _.assert( _.strIs( o.namePostfix ), 'Expects name postfix {- o.namePostfix -}' ); + o.filePath = _.path.join( o.group.tempPath, o.group.dirPath, o.group.namePrefix + o.name + o.group.namePostfix ); + } + + if( !o.group.rewriting ) + _.sure( !_.fileProvider.fileExists( o.filePath ), `Prgoram ${o.filePath/*programPath*/} already exists!` ); + + _.fileProvider.fileWrite( o.filePath, o.fullCode ); + console.log( _.strLinesNumber( o.fullCode ) ); + + return o; +} + +fileWrite.defaults = +{ + ... filePreform.defaults, + fullCode : null, + filePath/*programPath*/ : null, + + dirPath : null, + namePrefix : null, + namePostfix : null, +} + +// + +function groupWrite_body( o ) +{ + + _.map.assertHasAll( o, groupWrite_body.defaults ); + _.map.assertHasOnly( o, groupWrite_body.defaults ); + + for( let name in o.files ) + { + let file = o.files[ name ]; + if( file.filePath/*programPath*/ === undefined ) + file.filePath/*programPath*/ = null; + _.program.fileWrite( file ); + } + + return o; +} + +groupWrite_body.defaults = +{ + ... groupPreform.defaults, + tempPath : null, + dirPath : '.', + namePrefix : '', + namePostfix : '', + rewriting : 0, + logger : 0, + entry : null, + files : null, +} + +let groupWrite = _.routine.unite( null, groupWrite_body ); + +// + +function write_body( o ) +{ + + _.map.assertHasAll( o, write_body.defaults ); + _.map.assertHasOnly( o, write_body.defaults ); + + o.group.tempPath = o.tempPath; + o.group.dirPath = o.dirPath; + o.group.namePrefix = o.namePrefix; + o.group.namePostfix = o.namePostfix; + o.group.rewriting = o.rewriting; + o.group.logger = o.logger; + delete o.tempPath; + delete o.dirPath; + delete o.namePrefix; + delete o.namePostfix; + delete o.rewriting; + delete o.logger; + + _.assert( o.group.entry.filePath !== undefined ); + if( o.group.entry.filePath === null ) + o.group.entry.filePath/*programPath*/ = o.filePath/*programPath*/; + delete o.filePath/*programPath*/; + + _.program.groupWrite.body.call( _.program, o.group ); + + return o; +} + +write_body.defaults = +{ + group : null, + + tempPath : null, + dirPath : '.', + namePrefix : '', + namePostfix : '', + rewriting : 0, + logger : 0, + filePath/*programPath*/ : null, + entry : null, + files : null, +}; + +const write = _.routine.unite( preform_head, write_body ); + +// + +function starterAdd( o ) +{ + if( _.process && _.process.starter ) + { + for( let key in o.files ) + { + const entry = o.files[ key ]; + entry.start = _.process.starter + ({ + execPath : entry.filePath, + currentPath : _.path.dir( entry.filePath ), + outputCollecting : 1, + outputPiping : 1, + inputMirroring : 1, + throwingExitCode : 1, + logger : entry.group.logger, + mode : 'fork', + }); + } + } + else + { + for( let key in o.files ) + { + const entry = o.files[ key ]; + entry.start = dinamicStartMaybe.bind( entry ); + } + } + + o.filePath = o.group.entry.filePath; + o.start = o.group.entry.start; + + return o; + + /* */ + + function dinamicStartMaybe( options ) + { + const self = this; + options = options || Object.create( null ); + + let result; + try + { + result = _.process.start + ({ + execPath : this.filePath, + currentPath : _.path.dir( this.filePath ), + outputCollecting : 1, + outputPiping : 1, + inputMirroring : 1, + throwingExitCode : 1, + logger : this.group.logger, + mode : 'fork', + ... options, + }); + } + catch( err ) + { + _.error.attend( err ); + throw _.err + ( + 'Feature with starting of process by routine `start` is pluggable.', + '\nPlease, add dependency `wProcess` manually to enable feature.' + ); + } + return result; + } +} + +// + +function make_body( o ) +{ + _.map.assertHasAll( o, make_body.defaults ); + _.map.assertHasOnly( o, make_body.defaults ); + + this.preform.body.call( this, o ); + this.write.body.call( this, o ); + this.starterAdd.call( this, o ); + + return o; +} + +make_body.defaults = +{ + ... preform_body.defaults, + ... write_body.defaults, +}; + +let make = _.routine.unite( preform_head, make_body ); + +// + +function _tempOpen() +{ + return _.fileProvider.tempOpen( ... arguments ); +} + +// -- +// program extension +// -- + +let ProgramExtension = +{ + groupPreformLocals, + filePreform, + groupPreform, + preform, + + fileWrite, + groupWrite, + write, + + starterAdd, + + make, + + _tempOpen, +}; + +Object.assign( _.program, ProgramExtension ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorextra/proto/wtools/abase/l2_introspector/l3/Program.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wintrospectorextra/proto/wtools/abase/l2_introspector/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Program_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Program_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wlooker/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wlooker/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wlooker */ ( function wlooker() { function wlooker_naked() { +module.exports = require( '../wtools/abase/l2/Looker.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wLooker', 'wlooker' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wlooker/proto/node_modules/wlooker' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wlooker/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wlooker_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wlooker */ })(); + +/* */ /* begin of file Looker_s */ ( function Looker_s() { function Looker_s_naked() { ( function _Looker_s_() +{ + +'use strict'; + +/** + * Collection of routines to traverse complex data structure. The module takes care of cycles in a data structure( recursions ) and can be used for comparison, cloning, serialization or operation on several similar data structures. Many other modules based on this to traverse abstract data structures. + @module Tools/base/Looker +*/ + +/** + * Collection of light-weight routines to traverse complex data structure. + * @namespace Tools.Seeker + * @module Tools/base/Looker + */ + +/** + * Collection of light-weight routines to traverse complex data structure. + * @class Tools.Seeker + * @module Tools/base/Looker + */ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + +} + +const _global = _global_; +const _ = _global_.wTools; +const _ObjectHasOwnProperty = Object.hasOwnProperty; + +_.looker = _.looker || Object.create( null ); + +_.assert( !!_realGlobal_ ); + +// -- +// relations +// -- + +/** + * Default options for {@link module:Tools/base/Looker.Seeker.look} routine. + * @typedef {Object} Prime + * @property {Function} onUp + * @property {Function} onDown + * @property {Function} onTerminal + * @property {Function} ascend + * @property {Function} onIterable + * @property {Number} recursive = Infinity + * @property {Boolean} trackingVisits = 1 + * @property {String} upToken = '/' + * @property {String} path = '/' + * @property {Number} level = 0 + * @property {*} src = null + * @property {*} root = null + * @property {*} context = null + * @property {Object} Looker = null + * @property {Object} it = null + * @class Tools.Seeker + */ + +let Prime = Object.create( null ); + +Prime.src = undefined; +Prime.root = undefined; +Prime.onUp = onUp; +Prime.onDown = onDown; +Prime.onTerminal = onTerminal; +Prime.pathJoin = pathJoin; +Prime.fast = 0; +Prime.recursive = Infinity; +Prime.revisiting = 0; +Prime.withCountable = 'array'; +Prime.withImplicit = 'aux'; +Prime.upToken = '/'; +Prime.defaultUpToken = null; +Prime.path = '/'; +Prime.level = 0; +Prime.context = null; + +// -- +// iterator +// -- + +function iteratorRetype( iterator ) +{ + + _.assert( arguments.length === 1 ); + _.assert( _.mapIs( iterator ) ); + _.assert( _.object.isBasic( this.Iterator ) ); + _.assert( _.object.isBasic( this.Iteration ) ); + _.assert( _.object.isBasic( iterator.Seeker ) ); + _.assert( iterator.Seeker === this ); + _.assert( iterator.looker === undefined ); + _.assert( iterator.iterableEval !== null ); + _.assert( iterator.iterator === undefined ); + _.assert( iterator.Seeker.Seeker === iterator.Seeker, 'Default of a routine and its default Looker are not in agreement' ); + _.assert( _.prototype.has( iterator.Seeker, iterator.Seeker.OriginalSeeker ) ); + + Object.setPrototypeOf( iterator, iterator.Seeker ); + + _.assert( iterator.it === undefined ); + + return iterator; +} + +// + +function iteratorInitBegin( iterator ) +{ + + _.assert( arguments.length === 1 ); + _.assert( !_.mapIs( iterator ) ); + _.assert( _.object.isBasic( this.Iterator ) ); + _.assert( _.object.isBasic( this.Iteration ) ); + _.assert( _.object.isBasic( iterator.Seeker ) ); + _.assert( iterator.Seeker === this ); + _.assert( iterator.looker === undefined ); + _.assert( _.routineIs( iterator.iterableEval ) ); + _.assert( _.prototype.has( iterator.Seeker, iterator.Seeker.OriginalSeeker ) ); + _.assert( iterator.iterator === null ); + + iterator.iterator = iterator; + + return iterator; +} + +// + +function iteratorInitEnd( iterator ) +{ + + /* */ + + if( _.boolLike( iterator.withCountable ) ) + { + if( iterator.withCountable ) + iterator.withCountable = 'countable'; + else + iterator.withCountable = ''; + } + if( _.boolLike( iterator.withImplicit ) ) + { + if( iterator.withImplicit ) + iterator.withImplicit = 'aux'; + else + iterator.withImplicit = ''; + } + + if( _.boolIs( iterator.recursive ) ) + iterator.recursive = iterator.recursive ? Infinity : 1; + + _.assert( iterator.iteratorProper( iterator ) ); + _.assert( iterator.Seeker.Seeker === iterator.Seeker, 'Default of a routine and its default Looker are not in agreement' ); + _.assert( iterator.looker === undefined ); + _.assert + ( + !Reflect.has( iterator, 'onUp' ) || iterator.onUp === null || iterator.onUp.length === 0 || iterator.onUp.length === 3, + 'onUp should expect exactly three arguments' + ); + _.assert + ( + !Reflect.has( iterator, 'onDown' ) || iterator.onDown === null || iterator.onDown.length === 0 || iterator.onDown.length === 3, + 'onDown should expect exactly three arguments' + ); + _.assert( _.numberIsNotNan( iterator.recursive ), 'Expects number {- iterator.recursive -}' ); + _.assert( 0 <= iterator.revisiting && iterator.revisiting <= 2 ); + _.assert + ( + this.WithCountable[ iterator.withCountable ] !== undefined, + 'Unexpected value of option::withCountable' + ); + _.assert + ( + this.WithImplicict[ iterator.withImplicit ] !== undefined, + 'Unexpected value of option::withImplicit' + ); + + if( iterator.Seeker === null ) + iterator.Seeker = Looker; + + /* */ + + iterator.isCountable = iterator.WithCountableToIsElementalFunctionMap[ iterator.withCountable ]; + iterator.hasImplicit = iterator.WithImplicitToHasImplicitFunctionMap[ iterator.withImplicit ]; + + if( iterator.revisiting < 2 ) + { + if( iterator.revisiting === 0 ) + iterator.visitedContainer = _.containerAdapter.from( new Set ); + else + iterator.visitedContainer = _.containerAdapter.from( new Array ); + } + + if( iterator.root === undefined ) + iterator.root = iterator.src; + + if( iterator.defaultUpToken === null ) + iterator.defaultUpToken = _.strsShortest( iterator.upToken ); + + _.seeker.Seeker.iteratorInitEnd.call( this, iterator ); + + if( iterator.fast ) + { + delete iterator.childrenCounter; + delete iterator.level; + delete iterator.path; + delete iterator.lastPath; + delete iterator.lastIt; + delete iterator.upToken; + delete iterator.defaultUpToken; + delete iterator.context; + } + else + { + if( iterator.path === null ) + iterator.path = iterator.defaultUpToken; + iterator.lastPath = iterator.path; + } + + /* + important assert, otherwise copying options from iteration could cause problem + */ + _.assert( iterator.it === undefined ); + + if( !iterator.fast ) + { + _.assert( _.numberIs( iterator.level ) ); + _.assert( _.strIs( iterator.defaultUpToken ) ); + _.assert( _.strIs( iterator.path ) ); + _.assert( _.strIs( iterator.lastPath ) ); + _.assert( _.routineIs( iterator.iterableEval ) ); + _.assert( iterator.iterationPrototype.constructor === iterator.constructor ); + _.assert( iterator.iterationPrototype.constructor === iterator.Seeker.constructor ); + } + + return iterator; +} + +// + +function iteratorCopy( o ) +{ + let it = this; + + _.assert( arguments.length === 1 ); + _.assert( _.object.isBasic( o ) ) + + for( let k in o ) + { + if( it[ k ] === null && o[ k ] !== null && o[ k ] !== undefined ) + { + it[ k ] = o[ k ]; + } + } + + return it; +} + +// -- +// iteration +// -- + +/** + * @function iterationMake + * @class Tools.Seeker + */ + +function iterationMake() +{ + let it = this; + + // _.assert( arguments.length === 0, 'Expects no arguments' ); + // _.assert( it.level >= 0 ); + // _.assert( _.object.isBasic( it.iterator ) ); + // _.assert( _.object.isBasic( it.Seeker ) ); + // _.assert( it.looker === undefined ); + // _.assert( _.numberIs( it.level ) && it.level >= 0 ); + // _.assert( !!it.iterationPrototype ); + + let newIt = Object.create( it.iterationPrototype ); + + if( it.Seeker === Self ) /* zzz : achieve such optimization automatically */ + { + newIt.level = it.level; + newIt.path = it.path; + newIt.src = it.src; + } + else + { + for( let k in it.Seeker.IterationPreserve ) + newIt[ k ] = it[ k ]; + } + + newIt.down = it; + + return newIt; +} + +// -- +// perform +// -- + +function reperform( src ) +{ + let it = this; + _.assert( arguments.length === 1 ); + _.assert( it.iterationProper( it ) ); + it.src = src; + it.iterable = null; + return it.perform(); +} + +// + +function perform() +{ + let it = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + it.performBegin(); + it.iterate(); + it.performEnd(); + return it; +} + +// + +function performBegin() +{ + let it = this; + _.assert( arguments.length === 0 ); + _.assert( it.iterationProper( it ) ); + _.assert( _.strDefined( it.path ) ); + it.chooseRoot(); + _.assert( _.strDefined( it.path ) ); + return it; +} + +// + +function performEnd() +{ + let it = this; + _.assert( it.iterationProper( it ) ); + return it; +} + +// -- +// choose +// -- + +/** + * @function elementGet + * @class Tools.Seeker + */ + +function elementGet( e, k, c ) +{ + let it = this; + let result; + _.assert( arguments.length === 3, 'Expects two argument' ); + result = _.container.elementWithImplicit( e, k ); + if( c === null ) + c = _.container.cardinalWithKey( e, k ); + return [ result[ 0 ], result[ 1 ], c, result[ 2 ] ]; +} + +// + +/** + * @function choose + * @class Tools.Seeker + */ + +function choose() +{ + let it = this; + let e = arguments[ 0 ]; + let k = arguments[ 1 ]; + let c = arguments[ 2 ]; + let exists = arguments[ 3 ]; + + [ e, k, c, exists ] = it.chooseBegin( e, k, c, exists ); + + _.assert( arguments.length === 4 ); + _.assert( _.boolIs( exists ) || exists === null ); + + if( exists !== true ) + [ e, k, c, exists ] = it.elementGet( it.src, k, c ); + + it.chooseEnd( e, k, c, exists ); + + _.assert( arguments.length === 4, 'Expects three argument' ); + _.assert( _.object.is( it.down ) ); + _.assert( _.boolIs( exists ) ); + _.assert( it.fast || it.level >= 0 ); + + return it; +} + +// + +function chooseBegin() +{ + let it = this; + let e = arguments[ 0 ]; + let k = arguments[ 1 ]; + let c = arguments[ 2 ]; + let exists = arguments[ 3 ]; + + // _.assert( _.object.is( it.down ) ); + // _.assert( it.fast || it.level >= 0 ); + // _.assert( it.originalKey === null ); + // _.assert( arguments.length === 4 ); + + if( it.originalKey === null ) + it.originalKey = k; + + return [ e, k, c, exists ]; +} + +// + +function chooseEnd() +{ + let it = this; + let e = arguments[ 0 ]; + let k = arguments[ 1 ]; + let c = arguments[ 2 ]; + let exists = arguments[ 3 ]; + + // _.assert( arguments.length === 4, 'Expects three argument' ); + // _.assert( _.object.isBasic( it.down ) ); + // _.assert( _.boolIs( exists ) ); + // _.assert( it.fast || it.level >= 0 ); + + /* + assigning of key and src should goes first + */ + + it.key = k; + it.cardinal = c; + it.src = e; + it.originalSrc = e; + + if( it.fast ) + return it; + + it.level = it.level+1; + + let k2 = k; + if( k2 === null ) + k2 = e; + if( _.strIs( k2 ) ) + { + /* zzz : test escaped path + .!not-prototype + .#not-cardinal + */ + if( k2 === '' ) + k2 = '""'; + } + else if( _.props.implicit.is( k2 ) ) + { + k2 = `!${Symbol.keyFor( k2.val )}`; + } + else + { + _.assert( c >= 0 ); + k2 = `#${c}`; + } + _.assert( k2.length > 0 ); + let hasUp = _.strHasAny( k2, it.upToken ); + if( hasUp ) + k2 = '"' + k2 + '"'; + + it.index = it.down.childrenCounter; + it.path = it.pathJoin( it.path, k2 ); + it.iterator.lastPath = it.path; + it.iterator.lastIt = it; + + it.srcChanged(); + it.revisitedEval( it.originalSrc ); + + return [ e, k, c, exists ]; +} + +// + +function chooseRoot() +{ + let it = this; + + _.assert( arguments.length === 0 ); + + it.originalSrc = it.src; + + it.srcChanged(); + it.revisitedEval( it.originalSrc ); + + it.iterator.lastPath = it.path; + it.iterator.lastIt = it; + + return it; +} + +// -- +// eval +// -- + +function srcChanged() +{ + let it = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + it.iterableEval(); +} + +// + +function iterableEval() +{ + let it = this; + + _.assert( it.iterable === null ); + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( _.aux.is( it.src ) ) + { + it.iterable = it.ContainerType.aux; + } + else if( _.hashMap.like( it.src ) ) + { + it.iterable = it.ContainerType.hashMap; + } + else if( _.set.like( it.src ) ) + { + it.iterable = it.ContainerType.set; + } + else if( _.object.is( it.src ) && _.class.methodAscendOf( it.src ) ) + { + it.iterable = it.ContainerType.custom; + } + else if( it.isCountable( it.src ) ) + { + it.iterable = it.ContainerType.countable; + } + else + { + it.iterable = 0; + } + + _.assert( it.iterable >= 0 ); +} + +// + +function revisitedEval( src ) +{ + let it = this; + + _.assert( arguments.length === 1 ); + + if( it.iterator.visitedContainer ) + if( it.iterable ) + { + if( it.iterator.visitedContainer.has( src ) ) + it.revisited = true; + } + +} + +// + +function isImplicit() +{ + let it = this; + _.assert( it.iterationProper( it ) ); + return _.props.implicit.is( it.key ); +} + +// -- +// iterate +// -- + +/** + * @function look + * @class Tools.Seeker + */ + +function iterate() +{ + let it = this; + + it.visiting = it.canVisit(); + if( !it.visiting ) + return it; + + it.visitUp(); + + it.ascending = it.canAscend(); + if( it.ascending ) + { + it.ascend(); + } + + it.visitDown(); + + return it; +} + +// + +/** + * @function visitUp + * @class Tools.Seeker + */ + +function visitUp() +{ + let it = this; + + it.visitUpBegin(); + + _.assert( _.routineIs( it.onUp ) ); + let r = it.onUp.call( it, it.src, it.key, it ); + _.assert( r === undefined, 'Callback should not return something' ); + _.assert( _.boolIs( it.continue ), () => 'Expects boolean it.continue, but got ' + _.entity.strType( it.continue ) ); + + it.visitUpEnd(); + +} + +// + +/** + * @function visitUpBegin + * @class Tools.Seeker + */ + +function visitUpBegin() +{ + let it = this; + + it.ascending = true; + + _.assert( it.visiting ); + + if( !it.fast ) + if( it.down ) + it.down.childrenCounter += 1; + +} + +// + +/** + * @function visitUpEnd + * @class Tools.Seeker + */ + +function visitUpEnd() +{ + let it = this; + + it.visitPush(); + +} + +// + +function onUp( e, k, it ) +{ +} + +// + +/** + * @function visitDown + * @class Tools.Seeker + */ + +function visitDown() +{ + let it = this; + + it.visitDownBegin(); + + _.assert( it.visiting ); + + if( it.onDown ) + { + let r = it.onDown.call( it, it.src, it.key, it ); + _.assert( r === undefined ); + } + + it.visitDownEnd(); + + return it; +} + +// + +/** + * @function visitDownBegin + * @class Tools.Seeker + */ + +function visitDownBegin() +{ + let it = this; + + it.ascending = false; + + _.assert( it.visiting ); + + it.visitPop(); + +} + +// + +/** + * @function visitDownEnd + * @class Tools.Seeker + */ + +function visitDownEnd() +{ + let it = this; +} + +// + +function onDown( e, k, it ) +{ +} + +// + +function visitPush() +{ + let it = this; + + if( it.iterator.visitedContainer ) + if( it.visitCounting && it.iterable ) + { + it.iterator.visitedContainer.push( it.originalSrc ); + it.visitCounting = true; + } + +} + +// + +function visitPop() +{ + let it = this; + + if( it.iterator.visitedContainer && it.iterator.revisiting !== 0 ) + if( it.visitCounting && it.iterable ) + if( _.arrayIs( it.iterator.visitedContainer.original ) || !it.revisited ) + { + if( _.arrayIs( it.iterator.visitedContainer.original ) ) + _.assert + ( + Object.is( it.iterator.visitedContainer.original[ it.iterator.visitedContainer.original.length-1 ], it.originalSrc ), + () => `Top-most visit ${it.path} does not match` + + `\n${it.originalSrc} <> ${ it.iterator.visitedContainer.original[ it.iterator.visitedContainer.original.length-1 ]}` + ); + it.iterator.visitedContainer.pop( it.originalSrc ); + it.visitCounting = false; + } + +} + +// + +/** + * @function canVisit + * @class Tools.Seeker + */ + +function canVisit() +{ + let it = this; + + if( !it.recursive && it.down ) + return false; + + return true; +} + +// + +/** + * @function canAscend + * @class Tools.Seeker + */ + +function canAscend() +{ + let it = this; + + _.assert( _.boolIs( it.continue ) ); + _.assert( _.boolIs( it.iterator.continue ) ); + + if( !it.ascending ) + return false; + + if( it.continue === false ) + return false; + else if( it.iterator.continue === false ) + return false; + else if( it.revisited ) + return false; + + _.assert( _.numberIs( it.recursive ) ); + // if( it.recursive > 0 ) + if( !( it.level < it.recursive ) ) + return false; + + return true; +} + +// + +function canSibling() +{ + let it = this; + + if( !it.continue || it.continue === _.dont ) + return false; + + if( !it.iterator.continue || it.iterator.continue === _.dont ) + return false; + + return true; +} + +// + +function ascendSrc( src ) +{ + let it = this; + it.src = src; + it.iterable = null; + it.srcChanged(); + it.ascend(); +} + +// + +function ascend() +{ + let it = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( it.iterable !== null && it.iterable !== undefined ); + _.assert( !!it.continue ); + _.assert( !!it.iterator.continue ); + + return it.Ascend[ it.iterable ].call( it, it.src ); +} + +// -- +// ascend +// -- + +function _termianlAscend( src ) +{ + let it = this; + + _.assert( arguments.length === 1 ); + + it.onTerminal( src ); + +} + +// + +function onTerminal() +{ + let it = this; + return it; +} + +// + +function _countableAscend( src ) +{ + let it = this; + + if( _.class.methodIteratorOf( src ) ) + { + let k = 0; + for( let e of src ) + { + let eit = it.iterationMake().choose( e, k, k, true ); + eit.iterate(); + if( !it.canSibling() ) + break; + k += 1; + } + } + else + { + for( let k = 0 ; k < src.length ; k++ ) + { + let e = src[ k ]; + let eit = it.iterationMake().choose( e, k, k, true ); + eit.iterate(); + if( !it.canSibling() ) + break; + } + } + +} + +// + +function _auxAscend( src ) +{ + let it = this; + let canSibling = true; + + _.assert( arguments.length === 1 ); + + let c = 0; + for( let k in src ) + { + let e = src[ k ]; + let eit = it.iterationMake().choose( e, k, c, true ); + eit.iterate(); + canSibling = it.canSibling(); + c += 1; + if( !canSibling ) + break; + } + + if( canSibling ) + if( it.hasImplicit( src ) ) + { + var props = _.props.onlyImplicit( src ); + + for( var [ k, e ] of props ) + { + let eit = it.iterationMake().choose( e, k, -1, true ); + eit.iterate(); + canSibling = it.canSibling(); + if( !canSibling ) + break; + } + + } + +} + +// + +function _hashMapAscend( src ) +{ + let it = this; + + _.assert( arguments.length === 1 ); + + let c = 0; + for( var [ k, e ] of src ) + { + let eit = it.iterationMake().choose( e, k, c, true ); + eit.iterate(); + c += 1; + if( !it.canSibling() ) + break; + } + +} + +// + +function _setAscend( src ) +{ + let it = this; + + _.assert( arguments.length === 1 ); + + let c = 0; + for( let e of src ) + { + let eit = it.iterationMake().choose( e, e, c, true ); + eit.iterate(); + c += 1; + if( !it.canSibling() ) + break; + } + +} + +// + +function _customAscend( src ) +{ + let it = this; + let method = _.class.methodAscendOf( it.src ) + method.call( src, it ); +} + +// -- +// dichotomy +// -- + +function _isCountable( src ) +{ + return _.countableIs( src ); +} + +// + +function _isVector( src ) +{ + return _.vectorIs( src ); +} + +// + +function _isLong( src ) +{ + return _.longIs( src ); +} + +// + +function _isArray( src ) +{ + return _.arrayIs( src ); +} + +// + +function _isConstructibleLike( src ) +{ + return _.constructibleLike( src ); +} + +// + +function _isAux( src ) +{ + return _.aux.isPrototyped( src ); +} + +// + +function _false( src ) +{ + return false; +} + +// -- +// etc +// -- + +function pathJoin( selectorPath, selectorName ) +{ + let it = this; + let result; + + _.assert( arguments.length === 2 ); + selectorPath = _.strRemoveEnd( selectorPath, it.upToken ); + result = selectorPath + it.defaultUpToken + selectorName; + + return result; +} + +// + +function errMake() +{ + let it = this; + let err = _.looker.SeekingError + ( + ... arguments + ); + // debugger; /* eslint-disable-line no-debugger */ + return err; +} + +// -- +// expose +// -- + +/** + * @function look + * @class Tools.Seeker + */ + +function exec_head( routine, args ) +{ + return routine.defaults.head( routine, args ); +} + +function exec_body( it ) +{ + return it.execIt.body.call( this, it ); +} + +function execIt_body( it ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.object.isBasic( it.Seeker ) ); + _.assert( _.prototype.isPrototypeFor( it.Seeker, it ) ); + _.assert( it.looker === undefined ); + it.perform(); + return it; +} + +// + +let _classDefine = _.seeker.classDefine; +_.routine.is( _classDefine ); +function classDefine( o ) +{ + + let looker = _classDefine.call( this, o ); + validate(); + return looker; + + function validate() + { + /* qqq : add explanation for each assert */ + _.assert( looker.Prime.Seeker === undefined ); + _.assert( _.routineIs( looker.iterableEval ) ); + _.assert( _.props.has( looker.IterationPreserve, 'src' ) && looker.IterationPreserve.src === undefined ); + _.assert( _.props.has( looker, 'src' ) && looker.src === undefined ); + _.assert( !_.props.has( looker.Iteration, 'root' ) && looker.Iteration.root === undefined ); + _.assert( _.props.has( looker, 'root' ) && looker.root === undefined ); + _.assert( !_.props.has( looker.Iteration, 'src' ) || looker.Iteration.src === undefined ); + + if( _.props.has( looker, 'dst' ) ) + { + _.assert( _.props.has( looker.Iteration, 'dst' ) && looker.Iteration.dst === undefined ); + _.assert( _.props.has( looker, 'dst' ) && looker.dst === undefined ); + } + if( _.props.has( looker, 'result' ) ) + { + _.assert( _.props.has( looker.Iterator, 'result' ) && looker.Iterator.result === undefined ); + _.assert( _.props.has( looker, 'result' ) && looker.result === undefined ); + } + } + +} + +classDefine.defaults = +{ + ... _.seeker.classDefine.defaults, +} + +// -- +// relations +// -- + +let SeekingError = _.error.error_functor( 'SeekingError' ); + +let ContainerType = +{ + 'terminal' : 0, + 'countable' : 1, + 'aux' : 2, + 'hashMap' : 3, + 'set' : 4, + 'custom' : 5, + 'last' : 5, +} + +let ContainerTypeToName = +[ + 'terminal', + 'countable', + 'aux', + 'hashMap', + 'set', + 'custom', +] + +let Ascend = +[ + _termianlAscend, + _countableAscend, + _auxAscend, + _hashMapAscend, + _setAscend, + _customAscend, +] + +let WithCountableToIsElementalFunctionMap = +{ + 'countable' : _isCountable, + 'vector' : _isVector, + 'long' : _isLong, + 'array' : _isArray, + '' : _false, +} + +let WithImplicitToHasImplicitFunctionMap = +{ + 'constructible.like' : _isConstructibleLike, + 'aux' : _isAux, + '' : _false, +} + +let WithCountable = +{ + 'countable' : 'countable', + 'vector' : 'vector', + 'long' : 'long', + 'array' : 'array', + '' : '', +} + +let WithImplicict = +{ + 'aux' : 'aux', + '' : '', +} + +// + +_.assert( !_.looker.Looker ); +_.assert( !!_.seeker.Seeker ); +_.assert( _.seeker.Seeker === _.seeker.Seeker.Seeker ); +_.assert( _.seeker.Seeker === _.seeker.Seeker.OriginalSeeker ); + +const LookerExtension = Object.create( null ); + +LookerExtension.constructor = function Looker() /* zzz : implement */ +{ + _.assert( 0, 'not implemented' ); + let prototype = _.prototype.of( this ); + _.assert( _.object.isBasic( prototype ) ); + _.assert( prototype.exec.defaults === prototype ); + let result = this.head( prototype.exec, arguments ); + _.assert( result === this ); + return this; +} +LookerExtension.constructor.prototype = Object.create( null ); + +// iterator + +LookerExtension.iteratorRetype = iteratorRetype; +LookerExtension.iteratorInitBegin = iteratorInitBegin; +LookerExtension.iteratorInitEnd = iteratorInitEnd; +LookerExtension.iteratorCopy = iteratorCopy; + +// iteration + +LookerExtension.iterationMake = iterationMake; + +// perform + +LookerExtension.reperform = reperform; +LookerExtension.perform = perform; +LookerExtension.performBegin = performBegin; +LookerExtension.performEnd = performEnd; + +// choose + +LookerExtension.elementGet = elementGet; +LookerExtension.choose = choose; +LookerExtension.chooseBegin = chooseBegin; +LookerExtension.chooseEnd = chooseEnd; +LookerExtension.chooseRoot = chooseRoot; + +// eval + +LookerExtension.srcChanged = srcChanged; +LookerExtension.iterableEval = iterableEval; +LookerExtension.revisitedEval = revisitedEval; +LookerExtension.isImplicit = isImplicit; + +// iterate + +LookerExtension.iterate = iterate; +LookerExtension.visitUp = visitUp; +LookerExtension.visitUpBegin = visitUpBegin; +LookerExtension.visitUpEnd = visitUpEnd; +LookerExtension.onUp = onUp; +LookerExtension.visitDown = visitDown; +LookerExtension.visitDownBegin = visitDownBegin; +LookerExtension.visitDownEnd = visitDownEnd; +LookerExtension.onDown = onDown; +LookerExtension.visitPush = visitPush; +LookerExtension.visitPop = visitPop; +LookerExtension.canVisit = canVisit; +LookerExtension.canAscend = canAscend; +LookerExtension.canSibling = canSibling; +LookerExtension.ascendSrc = ascendSrc; +LookerExtension.ascend = ascend; + +// ascend + +LookerExtension._termianlAscend = _termianlAscend; +LookerExtension.onTerminal = onTerminal; +LookerExtension._countableAscend = _countableAscend; +LookerExtension._auxAscend = _auxAscend; +LookerExtension._hashMapAscend = _hashMapAscend; +LookerExtension._setAscend = _setAscend; +LookerExtension._customAscend = _customAscend; + +// dichotomy + +LookerExtension._isCountable = _isCountable; +LookerExtension._isVector = _isVector; +LookerExtension._isLong = _isLong; +LookerExtension._isArray = _isArray; +LookerExtension._isConstructibleLike = _isConstructibleLike; +LookerExtension._isAux = _isAux; +LookerExtension._false = _false; + +// etc + +LookerExtension.pathJoin = pathJoin; +LookerExtension.errMake = errMake; + +// feilds + +LookerExtension.SeekingError = SeekingError; +LookerExtension.ContainerType = ContainerType; +LookerExtension.ContainerTypeToName = ContainerTypeToName; +LookerExtension.Ascend = Ascend; +LookerExtension.WithCountableToIsElementalFunctionMap = WithCountableToIsElementalFunctionMap; +LookerExtension.WithImplicitToHasImplicitFunctionMap = WithImplicitToHasImplicitFunctionMap; +LookerExtension.WithCountable = WithCountable; +LookerExtension.WithImplicict = WithImplicict; +LookerExtension.Prime = Prime; + +// + +/** + * @typedef {Object} Iterator + * @property {} iterator = null + * @property {} iterationMake = iterationMake + * @property {} choose = choose + * @property {} iterate = iterate + * @property {} visitUp = visitUp + * @property {} visitUpBegin = visitUpBegin + * @property {} visitUpEnd = visitUpEnd + * @property {} visitDown = visitDown + * @property {} visitDownBegin = visitDownBegin + * @property {} visitDownEnd = visitDownEnd + * @property {} canVisit = canVisit + * @property {} canAscend = canAscend + * @property {} path = '/' + * @property {} lastPath = null + * @property {} lastIt = null + * @property {} continue = true + * @property {} key = null + * @property {} error = null + * @property {} visitedContainer = null + * @class Tools.Seeker + */ + +let Iterator = LookerExtension.Iterator = Object.create( null ); + +Iterator.src = undefined; +Iterator.iterator = null; +Iterator.iterationPrototype = null; +Iterator.firstIterationPrototype = null; +Iterator.continue = true; +Iterator.error = null; +Iterator.visitedContainer = null; +Iterator.isCountable = null; +Iterator.hasImplicit = null; +Iterator.fast = 0; +Iterator.recursive = Infinity; +Iterator.revisiting = 0; +Iterator.withCountable = 'array'; +Iterator.withImplicit = 'aux'; +Iterator.upToken = '/'; +Iterator.defaultUpToken = null; +Iterator.lastIt = null; +Iterator.lastPath = null; +Iterator.path = '/'; +Iterator.level = 0; +Iterator.root = undefined; +Iterator.context = null; + +_.props.extend( LookerExtension, Iterator ); + +// + +/** + * @typedef {Object} Iteration + * @property {} childrenCounter = 0 + * @property {} level = 0 + * @property {} path = '/' + * @property {} key = null + * @property {} index = null + * @property {} src = null + * @property {} continue = true + * @property {} ascending = true + * @property {} revisited = false + * @property {} _ = null + * @property {} down = null + * @property {} visiting = false + * @property {} iterable = null + * @property {} visitCounted = 1 + * @class Tools.Seeker.Seeker + */ + +let Iteration = LookerExtension.Iteration = Object.create( null ); +_.assert( _.map.is( Iteration ) ); +Iteration.childrenCounter = 0; +Iteration.key = null; +Iteration.cardinal = null; +Iteration.originalKey = null; +Iteration.index = null; +Iteration.originalSrc = null; +Iteration.continue = true; +Iteration.ascending = true; +Iteration.revisited = false; +Iteration._ = null; +Iteration.down = null; +Iteration.visiting = false; +Iteration.iterable = null; +Iteration.visitCounting = true; + +// + +/** + * @typedef {Object} IterationPreserve + * @property {} level = null + * @property {} path = null + * @property {} src = null + * @class Tools.Seeker.Seeker + */ + +let IterationPreserve = LookerExtension.IterationPreserve = Object.create( null ); +_.assert( _.map.is( IterationPreserve ) ); +IterationPreserve.level = 0; +IterationPreserve.path = '/'; +IterationPreserve.src = undefined; + +_.assert( !_.props.has( LookerExtension.Iteration, 'src' ) && LookerExtension.Iteration.src === undefined ); +_.assert( _.props.has( LookerExtension.IterationPreserve, 'src' ) && LookerExtension.IterationPreserve.src === undefined ); +_.assert( _.props.has( LookerExtension, 'src' ) && LookerExtension.src === undefined ); +_.assert( !_.props.has( LookerExtension.Iteration, 'root' ) && LookerExtension.Iteration.root === undefined ); +_.assert( _.props.has( LookerExtension, 'root' ) && LookerExtension.root === undefined ); + +_.map.assertHasAll( LookerExtension, Prime ); + +// + +const Looker = _.seeker.classDefine +({ + name : 'Looker', + parent : _.seeker.Seeker, + prime : Prime, + seeker : LookerExtension, + iterator : Iterator, + iteration : Iteration, + iterationPreserve : IterationPreserve, +}); +const Self = Looker; + +exec_body.defaults = Looker; +let exec = _.routine.uniteReplacing( exec_head, exec_body ); +Looker.exec = exec; + +execIt_body.defaults = Looker; +let execIt = _.routine.uniteReplacing( exec_head, execIt_body ); +Looker.execIt = execIt; + +_.assert( _.routine.is( Looker.optionsToIteration ) ); +_.assert( _.routine.is( Looker.iteratorInit ) ); +_.assert( _.routine.is( Looker.iteratorIterationMake ) ); +_.assert( _.routine.is( Looker.iterationProper ) ); +_.assert( _.routine.is( Looker.head ) ); +_.assert( _.routine.is( Looker.optionsFromArguments ) ); +_.assert( _.routine.is( Looker.iteratorProper ) ); + +// -- +// declare +// -- + +let LookerNamespaceExtension = +{ + + name : 'looker', + Looker, + Seeker : Looker, + SeekingError, + + look : exec, + lookIt : execIt, + + is : _.seeker.is, + iteratorIs : _.seeker.iteratorIs, + iterationIs : _.seeker.iterationIs, + classDefine, /* qqq : cover please */ + +} + +Object.assign( _.looker, LookerNamespaceExtension ); + +// + +let ErrorExtension = +{ + + SeekingError, + +} + +Object.assign( _.error, ErrorExtension ); + +// + +let ToolsExtension = +{ + + look : exec, + +} + +_.props.extend( _, ToolsExtension ); + +// + +_.assert( _.looker.Looker === Looker ); +_.assert( _.looker.Looker === _.looker.Looker.Seeker ); +_.assert( _.looker.Looker === _.looker.Looker.OriginalSeeker ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wlooker/proto/wtools/abase/l2/Looker.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wlooker/proto/wtools/abase/l2' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Looker_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Looker_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathbasic/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathbasic/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wpathbasic */ ( function wpathbasic() { function wpathbasic_naked() { +module.exports = require( '../wtools/abase/l3/PathsBasic.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wPathBasic', 'wpathbasic' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathbasic/proto/node_modules/wpathbasic' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathbasic/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wpathbasic_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wpathbasic */ })(); + +/* */ /* begin of file PathBasic_s */ ( function PathBasic_s() { function PathBasic_s_naked() { ( function _PathBasic_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to operate paths reliably and consistently. Path leverages parsing, joining, extracting, normalizing, nativizing, resolving paths. Use the module to get uniform experience from playing with paths on different platforms. + * @module Tools/base/Path +*/ + +/** + * @summary Collection of cross-platform routines to operate paths reliably and consistently. + * @namespace wTools.path + * @extends Tools + * @module Tools/PathBasic + */ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + +} + +// + +const _global = _global_; +const _ = _global_.wTools; +_.assert( !!_.path ); +const Self = _.path = _.path || Object.create( null ); + +// -- +// dichotomy +// -- + +/* xxx qqq : make new version in module Files. ask */ +function like( path ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + if( this.is( path ) ) + return true; + // if( _.files.FileRecord ) /* Dmytro : extended version in module Files */ + // if( path instanceof _.files.FileRecord ) + // return true; + return false; +} + +// + +function isElement( pathElement ) +{ + let result = + ( + pathElement === null + || _.strIs( pathElement ) + || _.arrayIs( pathElement ) + || _.mapIs( pathElement ) + || _.boolLike( pathElement ) + || _.regexpIs( pathElement ) + ); + return result; +} + +// + +/** + * Checks if string is correct possible for current OS path and represent file/directory that is safe for modification + * (not hidden for example). + * @param {String} filePath Source path for check + * @returns {boolean} + * @function isSafe + * @namespace Tools.path + */ + +function isSafe( filePath, level ) +{ + filePath = this.normalize( filePath ); + + if( level === undefined ) + level = 1; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.numberIs( level ), 'Expects number {- level -}' ); + + if( level >= 1 ) + { + if( this.isAbsolute( filePath ) ) + { + let parts = filePath.split( this.upToken ).filter( ( p ) => p.trim() ); + if( process.platform === 'win32' && parts.length && parts[ 0 ].length === 1 ) + parts.splice( 0, 1 ); + if( parts.length <= 1 ) + return false; + if( level >= 2 && parts.length <= 2 ) + return false; + return true; + } + } + + if( level >= 2 && process.platform === 'win32' ) + { + if( _.strHas( filePath, 'Windows' ) ) + return false; + if( _.strHas( filePath, 'Program Files' ) ) + return false; + } + + if( level >= 2 ) + if( /(^|\/)\.(?!$|\/|\.)/.test( filePath ) ) + return false; + + if( level >= 3 ) + if( /(^|\/)node_modules($|\/)/.test( filePath ) ) + return false; + + return true; +} + +// + +function isGlob( src ) /* qqq2 : extend and implement perfect coverage taking into account escaping */ +{ + let self = this; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ) ); + + if( self.fileProvider && !self.fileProvider.globing ) + { + return false; + } + + if( !self._pathIsGlobRegexp ) + _setup(); + + return self._pathIsGlobRegexp.test( src ); + + function _setup() + { + let _pathIsGlobRegexpStr = ''; + _pathIsGlobRegexpStr += '(?:[?*]+)'; /* asterix, question mark */ + _pathIsGlobRegexpStr += '|(?:([!?*@+]*)\\((.*?(?:\\|(.*?))*)\\))'; /* parentheses */ + _pathIsGlobRegexpStr += '|(?:\\[(.+?)\\])'; /* square brackets */ + _pathIsGlobRegexpStr += '|(?:\\{(.*)\\})'; /* curly brackets */ + _pathIsGlobRegexpStr += '|(?:\0)'; /* zero */ + self._pathIsGlobRegexp = new RegExp( _pathIsGlobRegexpStr ); + } + +} + +// + +function hasSymbolBase( srcPath ) +{ + return _.strHasAny( srcPath, [ '\0', '()' ] ); +} + +// -- +// transformer +// -- + +/** + * Returns dirname + filename without extension + * @example + * _.path.prefixGet( '/foo/bar/baz.ext' ); // '/foo/bar/baz' + * @param {string} path Path string + * @returns {string} + * @throws {Error} If passed argument is not string. + * @function prefixGet + * @namespace Tools.path + */ + +function prefixGet( path ) +{ + + _.assert( _.strIs( path ), 'Expects string as path' ); + + let n = path.lastIndexOf( '/' ); + if( n === -1 ) n = 0; + + let parts = [ path.substr( 0, n ), path.substr( n ) ]; + + n = parts[ 1 ].indexOf( '.' ); + if( n === -1 ) + n = parts[ 1 ].length; + + let result = parts[ 0 ] + parts[ 1 ].substr( 0, n ); + + return result; +} + +// + +/** + * Return path without extension. + * @example + * wTools.withoutExt( '/foo/bar/baz.txt' ); // '/foo/bar/baz' + * @param {string} path String path + * @returns {string} + * @throws {Error} If passed argument is not string + * @function withoutExt + * @namespace Tools.path + */ + +function withoutExt( path ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( path ), 'Expects string' ); + + let name = _.strIsolateRightOrNone( path, '/' )[ 2 ] || path; + + let i = name.lastIndexOf( '.' ); + if( i === -1 || i === 0 ) + return path; + + let halfs = _.strIsolateRightOrNone( path, '.' ); + return halfs[ 0 ]; +} + +// + +/** + * Returns file extension of passed `path` string. + * If there is no '.' in the last portion of the path returns an empty string. + * @example + * _.path.ext( '/foo/bar/baz.ext' ); // 'ext' + * @param {string} path path string + * @returns {string} file extension + * @throws {Error} If passed argument is not string. + * @function ext + * @namespace Tools.path + */ + +function ext( path ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( path ), 'Expects string {-path-}, but got', _.entity.strType( path ) ); + + let index = path.lastIndexOf( '/' ); + if( index >= 0 ) + path = path.substr( index+1, path.length-index-1 ); + + index = path.lastIndexOf( '.' ); + if( index === -1 || index === 0 ) + return ''; + + index += 1; + + return path.substr( index, path.length-index ).toLowerCase(); +} + +// + +function exts( path ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( path ), 'Expects string {-path-}, but got', _.entity.strType( path ) ); + + path = this.name({ path, full : 1 }); + + let exts = path.split( '.' ); + exts.splice( 0, 1 ); + exts = _.filter_( null, exts, ( e ) => e ? e.toLowerCase() : undefined ); + + return exts; +} + +// + +/** + * Replaces existing path extension on passed in `ext` parameter. If path has no extension, adds passed extension + to path. + * @example + * wTools.changeExt( '/foo/bar/baz.txt', 'text' ); // '/foo/bar/baz.text' + * @param {string} path Path string + * @param {string} ext + * @returns {string} + * @throws {Error} If passed argument is not string + * @function changeExt + * @namespace Tools.path + */ + +function changeExt( path, ext ) +{ + + if( arguments.length === 2 ) + { + _.assert( _.strIs( ext ) ); + } + else if( arguments.length === 3 ) + { + let sub = arguments[ 1 ]; + // let ext = arguments[ 2 ]; // Dmytro : it's local variable, uses in assertion below and has no sense in routine + ext = arguments[ 2 ]; + + _.assert( _.strIs( sub ) ); + _.assert( _.strIs( ext ) ); + + let cext = this.ext( path ); + + if( cext !== sub ) + return path; + } + else + { + _.assert( 0, 'Expects 2 or 3 arguments' ); + } + + if( ext === '' ) + return this.withoutExt( path ); + else + return this.withoutExt( path ) + '.' + ext; + +} + +// + +function _pathsChangeExt( src ) +{ + _.assert( _.longIs( src ) ); + _.assert( src.length === 2 ); + + return changeExt.apply( this, src ); +} + +// -- +// joiner +// -- + +/** + * Joins filesystem paths fragments or urls fragment into one path/url. Uses '/' level delimeter. + * @param {Object} o join o. + * @param {String[]} p.paths - Array with paths to join. + * @param {boolean} [o.reroot=false] If this parameter set to false (by default), method joins all elements in + * `paths` array, starting from element that begins from '/' character, or '* :', where '*' is any drive name. If it + * is set to true, method will join all elements in array. Result + * @returns {string} + * @private + * @throws {Error} If missed arguments. + * @throws {Error} If elements of `paths` are not strings + * @throws {Error} If o has extra parameters. + * @function join_body + * @namespace Tools.path + */ + +/* xxx : implement routine _.path.joiner() */ + +function join_head( routine, args ) +{ + _.assert( args.length > 0, 'Expects argument' ) + let o = { paths : args }; + + _.routine.options_( routine, o ); + //_.assert( o.paths.length > 0 ); + _.assert( _.boolLike( o.reroot ) ); + _.assert( _.boolLike( o.allowingNull ) ); + _.assert( _.boolLike( o.raw ) ); + + return o; +} + +function join_body( o ) +{ + let self = this; + let result = null; + let prepending = true; + + /* */ + + if( Config.debug ) + for( let a = o.paths.length-1 ; a >= 0 ; a-- ) + { + let src = o.paths[ a ]; + _.assert + ( + _.strIs( src ) || src === null, () => `Expects strings as path arguments, but #${a} argument is ${_.entity.strType( src )}` + ); + } + + /* */ + + for( let a = o.paths.length-1 ; a >= 0 ; a-- ) + { + let src = o.paths[ a ]; + + if( o.allowingNull ) + if( src === null ) + break; + + if( result === null ) + result = ''; + + _.assert( _.strIs( src ), () => `Expects strings as path arguments, but #${a} argument is ${_.entity.strType( src )}` ); + + if( !prepend( src ) ) + break; + + } + + /* */ + + if( !o.raw && result !== null ) + result = self.normalize( result ); + + return result; + + /* */ + + function prepend( src ) + { + let trailed = false; + let endsWithUp = false; + + if( src ) + src = self.refine( src ); + + if( !src ) + return true; + + // src = src.replace( /\\/g, self.upToken ); + + // if( result ) + if( _.strEnds( src, self.upToken ) ) + // if( _.strEnds( src, self.upToken ) && !_.strEnds( src, self.upToken + self.upToken ) ) + // if( src.length > 1 || result[ 0 ] === self.upToken ) + { + if( src.length > 1 ) + { + if( result ) + src = src.substr( 0, src.length-1 ); + trailed = true; + + if( result === self.downToken ) + result = self.hereToken; + else if( result === self.downUpToken ) + result = self.hereUpToken; + else + result = _.strRemoveBegin( result, self.downUpToken ); + + } + else + { + endsWithUp = true; + } + } + + if( src && result ) + if( !endsWithUp && !_.strBegins( result, self.upToken ) ) + result = self.upToken + result; + + result = src + result; + + if( !o.reroot ) + { + if( _.strBegins( result, self.rootToken ) ) + return false; + } + + return true; + } + +} + +join_body.defaults = +{ + paths : null, + reroot : 0, + allowingNull : 1, + raw : 0, +} + +// + +/** + * Method joins all `paths` together, beginning from string that starts with '/', and normalize the resulting path. + * @example + * let res = wTools.join( '/foo', 'bar', 'baz', '.'); + * // '/foo/bar/baz' + * @param {...string} paths path strings + * @returns {string} Result path is the concatenation of all `paths` with '/' directory delimeter. + * @throws {Error} If one of passed arguments is not string + * @function join + * @namespace Tools.path + */ + +let join = _.routine.uniteCloning_replaceByUnite( join_head, join_body ); + +// + +let joinRaw = _.routine.uniteCloning_replaceByUnite( join_head, join_body ); +joinRaw.defaults.raw = 1; + +// function join() +// { +// +// let result = this.join_body +// ({ +// paths : arguments, +// reroot : 0, +// allowingNull : 1, +// raw : 0, +// }); +// +// return result; +// } + +// + +// function joinRaw_body( o ) +// { +// let result = this.join.body( o ); +// +// return result; +// } +// +// joinRaw_body.defaults = +// { +// paths : null, +// reroot : 0, +// allowingNull : 1, +// raw : 1, +// } + +// function joinRaw() +// { +// +// let result = this.join_body +// ({ +// paths : arguments, +// reroot : 0, +// allowingNull : 1, +// raw : 1, +// }); +// +// return result; +// } + +// + +function joinIfDefined() +{ + let args = _.filter_( null, arguments, ( arg ) => arg ); + if( !args.length ) + return; + return this.join.apply( this, args ); +} + +// + +function joinCross() +{ + + if( _.longHasDepth( arguments ) ) + { + let result = []; + + let samples = _.permutation.eachSample( arguments ); + for( var s = 0 ; s < samples.length ; s++ ) + result.push( this.join.apply( this, samples[ s ] ) ); + return result; + } + + return this.join.apply( this, arguments ); +} + +// + +/** + * Method joins all `paths` strings together. + * @example + * let res = wTools.reroot( '/foo', '/bar/', 'baz', '.'); + * // '/foo/bar/baz/.' + * @param {...string} paths path strings + * @returns {string} Result path is the concatenation of all `paths` with '/' directory delimeter. + * @throws {Error} If one of passed arguments is not string + * @function reroot + * @namespace Tools.path + */ + +let reroot = _.routine.uniteCloning_replaceByUnite( join_head, join_body ); +reroot.defaults = +{ + paths : null, + reroot : 1, + allowingNull : 1, + raw : 0, +} + +// function reroot() +// { +// let result = this.join_body +// ({ +// paths : arguments, +// reroot : 1, +// allowingNull : 1, +// raw : 0, +// }); +// return result; +// } + +// + +/** + * Method resolves a sequence of paths or path segments into an absolute path. + * The given sequence of paths is processed from right to left, with each subsequent path prepended until an absolute + * path is constructed. If after processing all given path segments an absolute path has not yet been generated, + * the current working directory is used. + * @example + * let absPath = wTools.resolve('work/wFiles'); // '/home/user/work/wFiles'; + * @param [...string] paths A sequence of paths or path segments + * @returns {string} + * @function resolve + * @namespace Tools.path + */ + +function resolve() +{ + _.assert( arguments.length > 0, 'Requires at least one argument' ); + let args = [] + let hasNull; + + for( let i = arguments.length - 1 ; i >= 0 ; i-- ) + { + let arg = arguments[ i ]; + + // if( _.strIs( arg ) && _.strHas( arg, '://' ) ) + // debugger; + + if( arg === null ) + { + hasNull = true; + break; + } + else + { + args.unshift( arg ); + } + } + + if( args.length === 0 ) + { + if( hasNull ) + return null; + return this.current(); + } + + let result = this.join.apply( this, args ); + if( hasNull || this.isAbsolute( result ) ) + return result; + + return this.join( this.current(), result ); +} + +// { +// let path; +// +// _.assert( arguments.length >= 0 ); +// +// let result = this.join( this.current(), ... arguments ); +// +// if( result !== null ) +// _.assert( result.length > 0 ); +// +// return result; +// } + +// function resolve() +// { +// let path; +// +// _.assert( arguments.length > 0 ); +// +// path = this.join.apply( this, arguments ); +// +// if( path === null ) +// return path; +// else if( !this.isAbsolute( path ) ) +// path = this.join( this.current(), path ); +// +// path = this.normalize( path ); +// +// _.assert( path.length > 0 ); +// +// return path; +// } + +// + +function joinNames() +{ + let self = this; + + // Variables + + let prefixs = []; // Prefixes array + let names = []; // Names array + let exts = []; // Extensions array + let extsBool = false; // Check if there are extensions + let prefixBool = false; // Check if there are prefixes + let start = -1; // Index of the starting prefix + let numStarts = 0; // Number of starting prefixes + let numNull = 0; // Number of null prefixes + let longerI = -1; // Index of the longest prefix + let maxPrefNum = 0; // Length of the longest prefix + + // Check input elements are strings + if( Config.debug ) + for( let a = arguments.length-1 ; a >= 0 ; a-- ) + { + let src = arguments[ a ]; + _.assert( _.strIs( src ) || src === null ); + } + + for( let a = arguments.length-1 ; a >= 0 ; a-- ) // Loop over the arguments ( starting by the end ) + { + let src = arguments[ a ]; + + if( src === null ) // Null arg, break loop + { + prefixs.splice( 0, a + 1 ); + numNull = numNull + a + 1; + break; + } + + src = self.normalize( src ); + + let prefix = self.prefixGet( src ); + + if( prefix.charAt( 0 ) === '/' ) // Starting prefix + { + prefixs[ a ] = src + '/'; + names[ a ] = ''; + exts[ a ] = ''; + start = a; + numStarts = numStarts + 1; + } + else + { + names[ a ] = self.name( src ); + prefixs[ a ] = prefix.substring( 0, prefix.length - ( names[ a ].length + 1 ) ); + prefix = prefix.substring( 0, prefix.length - ( names[ a ].length ) ); + exts[ a ] = self.ext( src ); + + if( prefix.substring( 0, 2 ) === './' ) + { + prefixs[ a ] = prefixs[ a ].substring( 2 ); + } + + prefixs[ a ] = prefixs[ a ].split( '/' ); + + let prefNum = prefixs[ a ].length; + + if( maxPrefNum < prefNum ) + { + maxPrefNum = prefNum; + longerI = a; + } + + let empty = prefixs[ a ][ 0 ] === '' && names[ a ] === '' && exts[ a ] === ''; + + if( empty && src.charAt( 0 ) === '.' ) + exts[ a ] = src.substring( 1 ); + + } + + if( exts[ a ] !== '' ) + extsBool = true; + + if( prefix !== '' ) + prefixBool = true; + + } + + longerI = longerI - numStarts - numNull; + + let result = names.join( '' ); + + if( prefixBool === true ) + { + let first; + if( start !== -1 ) + { + logger.log( prefixs, start) + first = prefixs.splice( start, 1 ); + } + + prefixsMake(); + + let head = self.join.apply( self, prefixs[ longerI ] ); + result = self.join.apply( self, [ head, result ] ); + + if( start !== -1 ) + { + result = self.join.apply( self, [ first[ 0 ], result ] ); + } + + } + + if( extsBool === true ) + { + result = result + '.' + exts.join( '' ); + } + + // xxx : qqq : what is normalize for? + result = self.normalize( result ); + + return result; + + /* */ + + function prefixsMake() + { + for( let p = 0; p < maxPrefNum; p++ ) + { + for( let j = prefixs.length - 1; j >= 0; j-- ) + { + let pLong = prefixs[ longerI ][ maxPrefNum - 1 - p ]; + let pj = prefixs[ j ][ prefixs[ j ].length - 1 - p ]; + if( j !== longerI ) + { + if( pj !== undefined && pLong !== undefined ) + { + + if( j < longerI ) + { + prefixs[ longerI ][ maxPrefNum - 1 - p ] = self.joinNames.apply( self, [ pj, pLong ] ); + } + else + { + prefixs[ longerI ][ maxPrefNum - 1 - p ] = self.joinNames.apply( self, [ pLong, pj ] ); + } + } + else if( pLong === undefined ) + { + prefixs[ longerI ][ maxPref - 1 - p ] = pj; + } + else if( pj === undefined ) + { + prefixs[ longerI ][ maxPrefNum - 1 - p ] = pLong; + } + } + } + } + } +} + +/* +function joinNames() +{ + let names = []; + let exts = []; + + if( Config.debug ) + for( let a = arguments.length-1 ; a >= 0 ; a-- ) + { + let src = arguments[ a ]; + _.assert( _.strIs( src ) || src === null ); + } + + for( let a = arguments.length-1 ; a >= 0 ; a-- ) + { + let src = arguments[ a ]; + if( src === null ) + break; + names[ a ] = this.name( src ); + exts[ a ] = src.substring( names[ a ].length ); + } + + let result = names.join( '' ) + exts.join( '' ); + + return result; +} +*/ + +// -- +// stater +// -- + +function current() +{ + _.assert( arguments.length === 0, 'Expects no arguments' ); + // return this.hereToken; + return this.upToken; +} + +// + +function from( src ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.strIs( src ) ) + return src; + else + _.assert( 0, 'Expects string, but got ' + _.entity.strType( src ) ); + +} + +// -- +// relator +// -- + +/** +* Returns a relative path to `path` from an `relative` path. This is a path computation : the filesystem is not +* accessed to confirm the existence or nature of path or start. + +* * If `o.relative` and `o.path` each resolve to the same path method returns `.`. +* * If `o.resolving` is enabled -- paths `o.relative` and `o.path` are resolved before computation, uses result of {@link module:Tools/PathBasic.Path.current _.path.current} as base. +* * If `o.resolving` is disabled -- paths `o.relative` and `o.path` are not resolved and must be both relative or absolute. +* +* **Examples of how result is computed and how to chech the result:** +* +* Result is checked by a formula : from + result === to, where '+' means join operation {@link module:Tools/PathBasic.Path.join _.path.join} +* +* **Note** : +* * `from` -- `o.relative` +* * `to` -- `o.path` +* * `cd` -- current directory +* +* *Example #1* +* ``` +* from : /a +* to : /b +* result : ../b +* from + result = to : /a + ../b = /b +* ``` +* *Example #2* +* ``` +* from : / +* to : /b +* result : ./b +* from + result = to : / + ./b = /b +* ``` +* *Example #3* +* ``` +* resolving : 0 +* from : .. +* to : . +* result : . +* from + result = to : .. + . != .. <> . -- error because result doesn't satisfy the final check +* from + result = to : .. + .. != ../.. <> . -- error because result doesn't satisfy the final check +* ``` +* +* *Example #4* +* ``` +* resolving : 1 +* cd : /d -- current dir +* from : .. -> / +* to : . -> /d +* result : ./d +* from + result = to : / + ./d === /d +* ``` +* +* *Example #5* +* ``` +* resolving : 0 +* from : ../a/b +* to : ../c/d +* result : ../../c/d +* from + result = to : ../a/b + ../../c/d === ../c/d +* ``` +* +* *Example #6* +* ``` +* resolving : 1 +* cd : / +* from : ../a/b -> /../a/b +* to : ../c/d -> /../c/d +* from + result = to : /../a/b + /../../c/d === /../c/d -- error resolved "from" leads out of file system +* ``` +* +* *Example #7* +* ``` +* resolving : 0 +* from : .. +* to : ./a +* result : ../a +* from + result = to : .. + ../a != ./a -- error because result doesn't satisfy the final check +* ``` +* *Example #8* +* ``` +* resolving : 1 +* cd : / +* from : .. -> /.. +* to : ./a -> /a +* result : /../a +* from + result = to : .. + ../a != ./a -- error resolved "from" leads out of file system +* ``` +* +* @param {Object} [o] Options map. +* @param {String|wFileRecord} [o.relative] Start path. +* @param {String|String[]} [o.path] Targer path(s). +* @param {String|String[]} [o.resolving=0] Resolves {o.relative} and {o.path} before computation. +* @param {String|String[]} [o.dotted=1] Allows '.' as the result, otherwise returns empty string. +* @returns {String|String[]} Returns relative path as String or array of Strings. +* @throws {Exception} If {o.resolving} is enabled and {o.relative} or {o.path} leads out of file system. +* @throws {Exception} If result of computation doesn't satisfy formula: o.relative + result === o.path. +* @throws {Exception} If {o.relative} is not a string or wFileRecord instance. +* @throws {Exception} If {o.path} is not a string or array of strings. +* @throws {Exception} If both {o.relative} and {path} are not relative or absolute. +* +* @example +* let from = '/a'; +* let to = '/b' +* _.path._relative({ relative : from, path : to, resolving : 0 }); +* //'../b' +* +* @example +* let from = '../a/b'; +* let to = '../c/d' +* _.path._relative({ relative : from, path : to, resolving : 0 }); +* //'../../c/d' +* +* @example +* //resolving, assume that cd is : '/d' +* let from = '..'; +* let to = '.' +* _.path._relative({ relative : from, path : to, resolving : 1 }); +* //'./d' +* +* @function _relative +* @namespace Tools.path +*/ + +function _relative( o ) +{ + let self = this; + let result = ''; + // let basePath = self.from( o.basePath ); + // let filePath = self.from( o.filePath ); + + o.basePath = self.from( o.basePath ); + o.filePath = self.from( o.filePath ); + + _.assert( _.strIs( o.basePath ), 'Expects string {-o.basePath-}, but got', _.entity.strType( o.basePath ) ); + _.assert( _.strIs( o.filePath ) || _.arrayIs( o.filePath ) ); + _.routine.assertOptions( _relative, arguments ); + + if( o.resolving ) + { + o.basePath = self.resolve( o.basePath ); + o.filePath = self.resolve( o.filePath ); + } + else + { + o.basePath = self.normalize( o.basePath ); + o.filePath = self.normalize( o.filePath ); + } + + let basePath = o.basePath; + let filePath = o.filePath; + let baseIsAbsolute = self.isAbsolute( basePath ); + let fileIsAbsolute = self.isAbsolute( filePath ); + let baseIsTrailed = self.isTrailed( basePath ); + + /* makes common style for relative paths, each should begin from './' */ + + if( o.resolving ) + { + + basePath = self.resolve( basePath ); + filePath = self.resolve( filePath ); + + _.assert( self.isAbsolute( basePath ) ); + _.assert( self.isAbsolute( filePath ) ); + + _.assert + ( + !_.strBegins( basePath, self.upToken + self.downToken ), + 'Resolved o.basePath:', basePath, 'leads out of file system.' + ); + _.assert + ( + !_.strBegins( filePath, self.upToken + self.downToken ), + 'Resolved o.filePath:', filePath, 'leads out of file system.' + ); + + } + else + { + basePath = self.normalize( basePath ); + filePath = self.normalize( filePath ); + + let baseIsAbsolute = self.isAbsolute( basePath ); + let fileIsAbsolute = self.isAbsolute( filePath ); + + /* makes common style for relative paths, each should begin with './' */ + + // if( !baseIsAbsolute && basePath !== self.hereToken ) + // basePath = _.strPrependOnce( basePath, self.hereUpToken ); + // if( !fileIsAbsolute && filePath !== self.hereToken ) + // filePath = _.strPrependOnce( filePath, self.hereUpToken ); + + if( !baseIsAbsolute ) + basePath = _.strRemoveBegin( basePath, self.hereUpToken ); + if( !fileIsAbsolute ) + filePath = _.strRemoveBegin( filePath, self.hereUpToken ); + + while( beginsWithDown( basePath ) ) + { + if( !beginsWithDown( filePath ) ) + break; + basePath = removeBeginDown( basePath ); + filePath = removeBeginDown( filePath ); + } + + _.assert + ( + ( baseIsAbsolute && fileIsAbsolute ) || ( !baseIsAbsolute && !fileIsAbsolute ), + 'Both paths must be either absolute or relative.' + ); + + _.assert + ( + // basePath !== self.hereUpToken + self.downToken && !_.strBegins( basePath, self.hereUpToken + self.downUpToken ) + !beginsWithDown( basePath ), + `Cant get path relative base path "${o.basePath}", it begins with "${self.downToken}"` + ); + + if( !baseIsAbsolute && basePath !== self.hereToken ) + basePath = _.strPrependOnce( basePath, self.hereUpToken ); + if( !fileIsAbsolute && filePath !== self.hereToken ) + filePath = _.strPrependOnce( filePath, self.hereUpToken ); + + } + + _.assert( basePath.length > 0 ); + _.assert( filePath.length > 0 ); + + /* extracts common filePath and checks if its a intermediate dir, otherwise cuts filePath and repeats the check*/ + + let common = _.strCommonLeft( basePath, filePath ); + let commonTrailed = _.strAppendOnce( common, self.upToken ); + if + ( + !_.strBegins( _.strAppendOnce( basePath, self.upToken ), commonTrailed ) + || !_.strBegins( _.strAppendOnce( filePath, self.upToken ), commonTrailed ) + ) + { + common = self.dir( common ); + } + + /* - */ + + /* gets count of up steps required to get to common dir */ + basePath = _.strRemoveBegin( basePath, common ); + filePath = _.strRemoveBegin( filePath, common ); + + let basePath2 = _.strRemoveBegin( _.strRemoveEnd( basePath, self.upToken ), self.upToken ); + let count = _.strCount( basePath2, self.upToken ); + + if( basePath === self.upToken || !basePath ) + count = 0; + else + count += 1; + + if( !_.strBegins( filePath, self.upToken + self.upToken ) && common !== self.upToken ) + filePath = _.strRemoveBegin( filePath, self.upToken ); + + /* prepends up steps */ + if( filePath || count === 0 ) + result = _.strDup( self.downUpToken, count ) + filePath; + else + result = _.strDup( self.downUpToken, count-1 ) + self.downToken; + + /* removes redundant slash at the end */ + if( _.strEnds( result, self.upToken ) ) + _.assert( result.length > self.upToken.length ); + + if( result === '' ) + result = self.hereToken; + + if( _.strEnds( o.filePath, self.upToken ) && !_.strEnds( result, self.upToken ) ) + if( o.basePath !== self.rootToken ) + result = result + self.upToken; + + if( baseIsTrailed ) + { + if( result === self.hereToken ) + result = self.hereToken; + else if( result === self.hereUpToken ) + result = self.hereUpToken; + else + result = self.hereUpToken + result; + } + + /* checks if result is normalized */ + + _.assert( result.length > 0 ); + _.assert( result.lastIndexOf( self.upToken + self.hereToken + self.upToken ) === -1 ); + _.assert( !_.strEnds( result, self.upToken + self.hereToken ) ); + + if( Config.debug ) + { + let i = result.lastIndexOf( self.upToken + self.downToken + self.upToken ); + _.assert( i === -1 || !/\w/.test( result.substring( 0, i ) ) ); + if( o.resolving ) + _.assert + ( + self.undot( self.resolve( o.basePath, result ) ) === self.undot( o.filePath ), + () => o.basePath + ' + ' + result + ' <> ' + o.filePath + ); + else + _.assert + ( + self.undot( self.join( o.basePath, result ) ) === self.undot( o.filePath ), + () => o.basePath + ' + ' + result + ' <> ' + o.filePath + ); + } + + return result; + + function beginsWithDown( filePath ) + { + return filePath === self.downToken || _.strBegins( filePath, self.downUpToken ); + } + + function removeBeginDown( filePath ) + { + if( filePath === self.downToken ) + return self.hereToken; + return _.strRemoveBegin( filePath, self.downUpToken ); + } + +} + +_relative.defaults = +{ + basePath : null, + filePath : null, + resolving : 0, +} + +// + +/** +* Short-cut for routine relative {@link module:Tools/PathBasic.Path._relative _.path._relative}. +* Returns a relative path to `path` from an `relative`. Does not resolve paths {o.relative} and {o.path} before computation. +* +* @param {string|wFileRecord} relative Start path. +* @param {string|string[]} path Target path(s). +* @returns {string|string[]} Returns relative path as String or array of Strings. +* For more details please see {@link module:Tools/PathBasic.Path._relative _.path._relative}. +* +* @example +* let from = '/a'; +* let to = '/b' +* _.path.relative( from, to ); +* //'../b' +* +* @example +* let from = '/'; +* let to = '/b' +* _.path.relative( from, to ); +* //'./b' +* +* @example +* let from = '/a/b'; +* let to = '/c' +* _.path.relative( from, to ); +* //'../../c' +* +* @example +* let from = '/a'; +* let to = './b' +* _.path.relative( from, to ); // throws an error paths have different type +* +* @example +* let from = '.'; +* let to = '..' +* _.path.relative( from, to ); +* //'..' +* +* @example +* let from = '..'; +* let to = '..' +* _.path.relative( from, to ); +* //'.' +* +* @example +* let from = '../a/b'; +* let to = '../c/d' +* _.path.relative( from, to ); +* //'../../c/d' +* +* @function relative +* @namespace Tools.path +*/ + +function relative_head( routine, args ) +{ + let o = args[ 0 ]; + if( args[ 1 ] !== undefined ) + o = { basePath : args[ 0 ], filePath : args[ 1 ] } + + _.routine.options_( routine, o ); + _.assert( args.length === 1 || args.length === 2 ); + _.assert( arguments.length === 2 ); + + return o; +} + +// + +function relative_body( o ) +{ + return this._relative( o ); +} + +relative_body.defaults = Object.create( _relative.defaults ); + +let relative = _.routine.uniteCloning_replaceByUnite( relative_head, relative_body ); + +// + +function relativeCommon() +{ + let commonPath = this.common( filePath ); + let relativePath = []; + + for( let i = 0 ; i < filePath.length ; i++ ) + relativePath[ i ] = this.relative( commonPath, filePath[ i ] ); + + return relativePath; +} + +// + +function _commonPair( src1, src2 ) +{ + let self = this; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src1 ) && _.strIs( src2 ) ); + + let result = []; + let first = pathParse( src1 ); + let second = pathParse( src2 ); + + let needToSwap = first.isRelative && second.isAbsolute; + if( needToSwap ) + { + let tmp = second; + second = first; + first = tmp; + } + + let bothAbsolute = first.isAbsolute && second.isAbsolute; + let bothRelative = first.isRelative && second.isRelative; + let absoluteAndRelative = first.isAbsolute && second.isRelative; + + if( absoluteAndRelative ) + { + if( first.splitted.length > 3 || first.splitted[ 0 ] !== '' || first.splitted[ 2 ] !== '' || first.splitted[ 1 ] !== '/' ) + { + throw _.err( 'Incompatible paths.' ); + } + else + return '/'; + } + + if( bothAbsolute ) + { + commonGet(); + + result = result.join( '' ); + + if( !result.length ) + result = '/'; + } + else if( bothRelative ) + { + if( first.levelsDown === second.levelsDown ) + commonGet(); + + result = result.join(''); + + let levelsDown = Math.max( first.levelsDown, second.levelsDown ); + + if( levelsDown > 0 ) + { + let prefix = _.longFill( [], self.downToken, levelsDown ); + prefix = prefix.join( '/' ); + result = prefix + result; + } + + if( !result.length ) + { + if( first.isRelativeHereThen && second.isRelativeHereThen ) + result = self.hereToken; + else + result = '.'; + } + } + + return result; + + /* - */ + + function commonGet() + { + let length = Math.min( first.splitted.length, second.splitted.length ); + for( let i = 0; i < length; i++ ) + { + if( first.splitted[ i ] === second.splitted[ i ] ) + { + if( first.splitted[ i ] === self.upToken && first.splitted[ i + 1 ] === self.upToken ) + break; + result.push( first.splitted[ i ] ); + } + else + { + break; + } + } + } + + /* */ + + function pathParse( path ) + { + let result = + { + isRelativeDown : false, + isRelativeHereThen : false, + isRelativeHere : false, + levelsDown : 0, + }; + + result.normalized = self.normalize( path ); + result.splitted = split( result.normalized ); + result.isAbsolute = self.isAbsolute( result.normalized ); + result.isRelative = !result.isAbsolute; + + if( result.isRelative ) + if( result.splitted[ 0 ] === self.downToken ) + { + result.levelsDown = _.longCountElement( result.splitted, self.downToken ); + let substr = _.longFill( [], self.downToken, result.levelsDown ).join( '/' ); + let withoutLevels = _.strRemoveBegin( result.normalized, substr ); + result.splitted = split( withoutLevels ); + result.isRelativeDown = true; + } + else if( result.splitted[ 0 ] === '.' ) + { + result.splitted = result.splitted.splice( 2 ); + result.isRelativeHereThen = true; + } + else + { + result.isRelativeHere = true; + } + + return result; + } + + /* */ + + function split( src ) + { + return _.strSplitFast( { src, delimeter : [ '/' ], preservingDelimeters : 1, preservingEmpty : 1 } ); + } + + /* */ + +} + +// + +/** + * The routine common() gets common path ( common directory ) from set of file paths in arguments. + * + * @example + * _.path.common(); + * // returns : null + * + * @example + * _.path.common( '/home/user/dir', '/home/user/dir2' ); + * // returns : '/home/user' + * + * @example + * _.path.common( '/', './some' ); + * // returns : '/' + * + * @example + * _.path.common( './foo/baz', 'foo/baz2' ); + * // returns : './foo' + * + * @param { String|Array|Aux } arguments - The set of file paths to get common path. + * @returns { Null|String } - Returns common path if it exists, otherwise, returns null. + * @function common + * @throws { Error } If absolute path with directories and a relative path are compared. + * @throws { Error } If absolute path with directories and a dot path are compared. + * @namespace wTools.path + * @extends Tools + */ + +/* +qqq : teach common to work with path maps and cover it by tests +*/ + +function common() +{ + + let paths = _.arrayFlatten( null, arguments ); + + for( let s = 0 ; s < paths.length ; s++ ) + { + if( _.mapIs( paths[ s ] ) ) + _.longBut_( paths, [ s, s + 1 ], _.props.keys( paths[ s ] ) ); + /* qqq for Dmtro : double check! */ + // paths.splice( s, 1, _.props.keys( paths[ s ] ) ); + } + + _.assert( _.strsAreAll( paths ) ); + + if( !paths.length ) + return null; + + paths.sort( function( a, b ) + { + return b.length - a.length; + }); + + let result = paths.pop(); + + for( let i = 0, len = paths.length ; i < len ; i++ ) + result = this._commonPair( paths[ i ], result ); + + return result; +} + +// + +function common_() +{ + let self = this; + + let paths = pathsArrayMake.apply( self, arguments ); + if( !paths.length ) + return null; + + _.assert( _.strsAreAll( paths ) ); + + /* */ + + let isAbsolute = self.isAbsolute( paths[ 0 ] ); + let isRelativeHereThen = true; + + if( !pathsConsistencyCheck() ) + return self.rootToken; + + let result = ''; + paths = pathsNormalize(); + + if( isAbsolute ) + { + result = pathCommonGet(); + } + else + { + let levelsDown = countLevelsDown(); + if( levelsDown[ 0 ] === levelsDown[ 1 ] ) + result = pathCommonGet(); + + if( levelsDown[ 1 ] > 0 ) + { + let prefix = _.longFill_( [], self.downToken, levelsDown[ 1 ] ); + prefix = prefix.join( '/' ); + result = prefix + result; + } + + if( !result.length ) + { + if( isRelativeHereThen ) + result = self.hereToken; + else + result = '.'; + } + } + + return result; + + /* */ + + function pathsArrayMake() + { + let paths = _.arrayFlatten( null, arguments ); + for( let s = 0 ; s < paths.length ; s++ ) + { + if( _.mapIs( paths[ s ] ) ) + _.longBut_( paths, [ s, s + 1 ], _.props.keys( paths[ s ] ) ); + /* aaa for Dmytro : double check! */ /* Dmytro : removed, it was needed for debugging */ + } + + return paths; + } + + /* */ + + function pathsConsistencyCheck() + { + for( let i = 1 ; i < paths.length ; i++ ) + { + let currentPathIsAbsolute = self.isAbsolute( paths[ i ] ); + + if( currentPathIsAbsolute !== isAbsolute ) + { + let absolutePath = isAbsolute ? paths[ 0 ] : paths[ i ]; + let splitted = split( self.normalize( absolutePath ) ); + + let absolutePathIsRoot = splitted.length > 3 || splitted[ 0 ] !== '' || splitted[ 1 ] !== '/' || splitted[ 2 ] !== ''; + + if( absolutePathIsRoot ) + throw _.err( 'Incompatible paths.' ); + else + return false; + } + } + return true; + } + + /* */ + + function split( src ) + { + return _.strSplitFast( { src, delimeter : [ '/' ], preservingDelimeters : 1, preservingEmpty : 1 } ); + } + + /* */ + + function pathsNormalize() + { + for( let i = 0 ; i < paths.length ; i++ ) + paths[ i ] = self.normalize( paths[ i ] ); + + return paths; + } + + /* */ + + function countLevelsDown() + { + let maxLevelsDown = 0; + let minLevelsDown = Infinity; + + for( let i = 0 ; i < paths.length ; i++ ) + { + let splitted = split( paths[ i ] ); + if( splitted[ 0 ] === self.downToken ) + { + let currentLevelsDown = _.longCountElement( splitted, self.downToken ); + let substr = _.longFill( [], self.downToken, currentLevelsDown ).join( '/' ); + paths[ i ] = _.strRemoveBegin( paths[ i ], substr ); + + maxLevelsDown = Math.max( maxLevelsDown, currentLevelsDown ); + minLevelsDown = Math.min( minLevelsDown, currentLevelsDown ); + } + else if( splitted[ 0 ] === '.' ) + { + paths[ i ] = paths[ i ].substring( 2, paths[ i ].length ); + minLevelsDown = 0; + } + else + { + isRelativeHereThen = false; + minLevelsDown = 0; + } + } + + return [ minLevelsDown, maxLevelsDown ]; + } + + /* */ + + function pathCommonGet() + { + paths = paths.sort(); + + let first = paths[ 0 ]; + let last = paths[ paths.length - 1 ]; + let i = 0; + while( i < first.length && first.charAt( i ) === last.charAt( i ) ) + i++; + + let fullCommonPath = first.substring( 0, i ); + let indexForSubstr = last.lastIndexOf( '/', i ); + if( indexForSubstr >= i ) + last = last.substr( 0, indexForSubstr ); + + if( fullCommonPath === last ) + return fullCommonPath; + + if( !fullCommonPath.length ) + return fullCommonPath; + + if( fullCommonPath.lastIndexOf( '/' ) === fullCommonPath.length - 1 ) + return fullCommonPath; + + let common = self.dir( fullCommonPath ); + if( common.length > 1 || common !== self.rootToken ) + common += '/'; + return common; + + } +} + +// + +function rebase( filePath, oldPath, newPath ) +{ + + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + + filePath = this.normalize( filePath ); + if( oldPath ) + oldPath = this.normalize( oldPath ); + newPath = this.normalize( newPath ); + + if( oldPath ) + { + let commonPath = this.common( filePath, oldPath ); + filePath = _.strRemoveBegin( filePath, commonPath ); + } + + filePath = this.reroot( newPath, filePath ) + + return filePath; +} + +// -- +// exception +// -- + +function _onErrorNotSafe( prefix, filePath, level ) +{ + _.assert( arguments.length === 3 ); + _.assert( _.strIs( prefix ) ); + _.assert( _.strIs( filePath ) || _.arrayIs( filePath ), 'Expects string or strings' ); + _.assert( _.numberIs( level ) ); + let args = + [ + prefix + ( prefix ? '. ' : '' ), + 'Not safe to use file ' + _.strQuote( filePath ) + '.', + `Please decrease safity level explicitly if you know what you do, current safity level is ${level}` + ]; + return args; +} + +let ErrorNotSafe = _.error.error_functor( 'ErrorNotSafe', _onErrorNotSafe ); + +// -- +// fields +// -- + +let Parameters = +{ +} + +// -- +// implementation +// -- + +let Extension = +{ + + // dichotomy + + like, + isElement, + + isSafe, + isGlob, + + hasSymbolBase, + + // transformer + + prefixGet, + // name, + // fullName, + + ext, + exts, + withoutExt, + changeExt, + + // joiner + + // qqq : implement and cover routine _.path.joiner() + join, + joinRaw, + joinIfDefined, + joinCross, /* qqq : cover. take into account case when some path is empty array */ + reroot, + resolve, + joinNames, + + // stater + + current, + + // relator + + from, + _relative, + relative, + relativeCommon, + + _commonPair, + common, /* !!! use instead of common */ /* Dmytro : coverage of the alternative routine is identical to original */ + common_, + rebase, + + // fields + + ErrorNotSafe, + +} + +_.props.supplement( Self, Parameters ); +_.props.supplement( Self.Parameters, Parameters ); +_.props.supplement( Self, Extension ); + +Self.Init(); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathbasic/proto/wtools/abase/l2/PathBasic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathbasic/proto/wtools/abase/l2' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, PathBasic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file PathBasic_s */ })(); + +/* */ /* begin of file PathsBasic_s */ ( function PathsBasic_s() { function PathsBasic_s_naked() { ( function _PathsBasic_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to operate multiple paths in the reliable and consistent way. + * @namespace wTools.paths + * @extends Tools + * @module Tools/PathBasic + */ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + + require( '../l2/PathBasic.s' ); + +} + +// + +const _global = _global_; +const _ = _global_.wTools; + +const Parent = _.path; +// const Self = _.path.s = _.paths = _.paths || Object.create( Parent ); +const Self = _.paths = _.path.s = _.paths || _.path.s || Object.create( Parent ); + +// -- +// +// -- + +function _keyEndsPathFilter( e, k, c ) +{ + if( _.strIs( k ) ) + { + if( _.strEnds( k, 'Path' ) ) + return true; + else + return false + } + return this.is( e ); +} + +// + +function _isPathFilter( e ) +{ + return this.is( e[ 0 ] ) +} + +// + +function _vectorize( routine, select ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( routine ) ); + select = select || 1; + return _.routineVectorize_functor + ({ + routine : [ 'single', routine ], + vectorizingArray : 1, + vectorizingMapVals : 0, + vectorizingMapKeys : 1, + select, + }); +} + +// + +function _vectorizeAsArray( routine, select ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( routine ) ); + select = select || 1; + + let after = _.routineVectorize_functor + ({ + routine : [ 'single', routine ], + vectorizingArray : 1, + vectorizingMapVals : 0, + vectorizingMapKeys : 0, + select, + }); + + return wrap; + + function wrap( srcs ) + { + if( _.mapIs( srcs ) ) + srcs = _.props.keys( srcs ); + arguments[ 0 ] = srcs; + return after.apply( this, arguments ); + } + +} + +// + +function _vectorizeAll( routine, select ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( routine ) ); + + let routine2 = _vectorizeAsArray( routine, select ); + + return all; + + function all() + { + let result = routine2.apply( this, arguments ); + return _.all( result ); + } + +} + +// + +function _vectorizeAny( routine, select ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( routine ) ); + + let routine2 = _vectorizeAsArray( routine, select ); + + return any; + + function any() + { + let result = routine2.apply( this, arguments ); + return !!_.any( result ); + } + +} + +// + +function _vectorizeNone( routine, select ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( routine ) ); + + let routine2 = _vectorizeAsArray( routine, select ); + + return none; + + function none() + { + let result = routine2.apply( this, arguments ); + return _.none( result ); + } + +} + +// + +function _vectorizeOnly( routine ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.strIs( routine ) ); + return _.routineVectorize_functor + ({ + routine : [ 'single', routine ], + propertyCondition : _keyEndsPathFilter, + vectorizingArray : 1, + vectorizingMapVals : 1, + }); +} + +// -- +// textual reporter +// -- + +function groupTextualReport_head( routine, args ) +{ + let o = args[ 0 ]; + + _.routine.options_( routine, o ); + _.assert( args.length === 1 ); + + o.verbosity = _.numberIs( o.verbosity ) ? o.verbosity : o.verbosity; + + if( !o.onRelative ) + o.onRelative = _.routineJoin( this, this.relative ); + + _.assert( _.routineIs( o.onRelative ) ); + + return o; +} + +// + +function groupTextualReport_body( o ) +{ + let self = this; + let r = ''; + let commonPath; + + _.routine.assertOptions( groupTextualReport_body, arguments ); + + if( o.verbosity >= 5 && o.groupsMap ) + r += _.entity.exportString( o.groupsMap[ '/' ], { multiline : 1, wrap : 0, levels : 2 } ) + '\n'; + + if( o.groupsMap ) + { + commonPath = self.common( _.props.keys( o.groupsMap ).filter( ( p ) => p !== '/' ) ); + if( o.verbosity >= 3 && o.groupsMap[ '/' ].length ) + r += ' ' + o.groupsMap[ '/' ].length + ' at ' + commonPath + '\n'; + } + + if( o.verbosity >= 3 && o.groupsMap ) + { + let details = _.filter_( null, o.groupsMap, ( filesPath, basePath ) => + { + if( basePath === '/' ) + return; + if( !filesPath.length ) + return; + return ' ' + filesPath.length + ' at ' + self.dot( o.onRelative( commonPath, basePath ) ); + }); + if( _.props.vals( details ).length ) + r += _.props.vals( details ).join( '\n' ) + '\n'; + } + + if( o.verbosity >= 1 ) + { + r += o.explanation + ( o.groupsMap ? o.groupsMap[ '/' ].length : 0 ) + ' file(s)'; + if( commonPath ) + r += ', at ' + commonPath; + if( o.spentTime !== null ) + r += ', in ' + _.time.spentFormat( o.spentTime ); + } + + return r; +} + +groupTextualReport_body.defaults = +{ + explanation : '', + groupsMap : null, + verbosity : 3, + spentTime : null, + onRelative : null +} + +let groupTextualReport = _.routine.uniteCloning_replaceByUnite( groupTextualReport_head, groupTextualReport_body ); + +// + +function _commonTextualReport( o ) +{ + _.routine.options_( _commonTextualReport, o ); + _.assert( arguments.length === 1 ); + _.assert( _.routineIs( o.onRelative ) ); + + let filePath = o.filePath; + + if( _.mapIs( filePath ) ) + filePath = _.props.keys( filePath ); + + if( _.arrayIs( filePath ) && filePath.length === 0 ) + return '()'; + + if( _.arrayIs( filePath ) && filePath.length === 1 ) + filePath = filePath[ 0 ]; + + if( _.strIs( filePath ) ) + return filePath; + + let commonPath = this.common.apply( this, filePath ); + + if( !commonPath ) + return '[ ' + filePath.join( ' , ' ) + ' ]'; + + let relativePath = []; + + for( let i = 0 ; i < filePath.length ; i++ ) + relativePath[ i ] = o.onRelative( commonPath, filePath[ i ] ); + + if( commonPath === '.' ) + return '[ ' + relativePath.join( ' , ' ) + ' ]'; + else + return '( ' + commonPath + ' + ' + '[ ' + relativePath.join( ' , ' ) + ' ]' + ' )'; +} + +_commonTextualReport.defaults = +{ + filePath : null, + onRelative : null +} + +// + +function commonTextualReport( filePath ) +{ + let self = this; + _.assert( arguments.length === 1 ); + let onRelative = _.routineJoin( this, this.relative ); + return self._commonTextualReport({ filePath, onRelative }); +} + +// + +function moveTextualReport_head( routine, args ) +{ + let self = this; + + let o = args[ 0 ]; + if( args[ 1 ] !== undefined ) + o = { dstPath : args[ 0 ], srcPath : args[ 1 ] } + + _.routine.options_( routine, o ); + _.assert( args.length === 1 || args.length === 2 ); + _.assert( arguments.length === 2 ); + + let srcIsAbsolute = false; + if( o.srcPath && self.s.anyAreAbsolute( o.srcPath ) ) + srcIsAbsolute = true; + + let dstIsAbsolute = false; + if( o.dstPath && self.s.anyAreAbsolute( o.dstPath ) ) + dstIsAbsolute = true; + + if( !o.srcPath ) + o.srcPath = dstIsAbsolute ? '/{null}' : '{null}'; + if( !o.dstPath ) + o.dstPath = srcIsAbsolute ? '/{null}' : '{null}'; + + if( !o.onRelative ) + o.onRelative = _.routineJoin( self, self.relative ); + + _.assert( _.routineIs( o.onRelative ) ); + + return o; +} + +function moveTextualReport_body( o ) +{ + let result = ''; + + _.routine.assertOptions( moveTextualReport_body, arguments ); + + let common = this.common( o.dstPath, o.srcPath ); + + if( o.decorating && _.color ) + { + if( common.length > 1 ) + result = _.color.strFormat( common, 'path' ) + ' : ' + _.color.strFormat( o.onRelative( common, o.dstPath ), 'path' ) + ' <- ' + _.color.strFormat( o.onRelative( common, o.srcPath ), 'path' ); + else + result = _.color.strFormat( o.dstPath, 'path' ) + ' <- ' + _.color.strFormat( o.srcPath, 'path' ); + } + else + { + if( common.length > 1 ) + result = common + ' : ' + o.onRelative( common, o.dstPath ) + ' <- ' + o.onRelative( common, o.srcPath ); + else + result = o.dstPath + ' <- ' + o.srcPath; + } + + return result; +} + +moveTextualReport_body.defaults = +{ + dstPath : null, + srcPath : null, + decorating : 1, + onRelative : null +} + +let moveTextualReport = _.routine.uniteCloning_replaceByUnite( moveTextualReport_head, moveTextualReport_body ); + +// + +/** + * @summary Check if elements from provided array( src ) are paths. Writes results into array. + * @param {Array|Object} src + * @example + * _.path.s.are(['/a', 1 ]); //[ true, false ] + * @returns {Array} Returns array of same size with check results. + * @function are + * @namespace Tools.paths + */ + +/** + * @summary Check if all elements from provided array( src ) are paths. + * @param {Array|Object} src + * @example + * _.path.s.allAre(['/a', 1 ]); //false + * @returns {Bollean} Returns true if all elements are paths or false. + * @function allAre + * @namespace Tools.paths + */ + +/** + * @summary Check if at least one element from provided array( src ) are paths. + * @param {Array|Object} src + * @example + * _.path.s.anyAre(['/a', 1 ]); //true + * @returns {Bollean} Returns true if at least one element is a path or false. + * @function anyAre + * @namespace Tools.paths + */ + +/** + * @summary Check if provided array( src ) contains path element. + * @param {Array|Object} src + * @example + * _.path.s.noneAre(['/a', 1 ]); //false + * @returns {Bollean} Returns false if at least one element is a path, otherwise true. + * @function noneAre + * @namespace Tools.paths + */ + +/** + * @summary Normalizes paths from array( src ). + * @description Look {@link module:Tools/PathBasic.normalize _.path.normalize } for details. + * @param {Array|Object} src + * @example + * _.path.s.normalize(['\\a', '/a/../b' ]); //['/a', '/b' ] + * @returns {Array} Returns array with normalized paths. + * @function normalize + * @namespace Tools.paths + */ + +/** + * @summary Joins provided paths. + * @description + * Supports combining of arrays/maps/strings, see examples. + * Look {@link module:Tools/PathBasic.join _.path.join } for details. + * @param {...String|...Array|...Object} arguments + * + * @example //also works same as regular _.path.join + * _.path.s.join( '/a', 'b' ); //'/a/b' + * + * @example //combining string with array + * _.path.s.join( '/a', [ 'b', 'c' ], 'd' ); // [ '/a/b/d', '/a/c/d' ] + * + * @example //combining string with array and map + * _.path.s.join( 'a', ['b', 'c'], {'d' : 1 } ); // { 'a/b/d' : 1, 'a/c/d' : 1 } + * + * @returns {Array|Object} Returns array with joined paths. + * @function join + * @namespace Tools.paths + */ + +/** + * @summary Gets parent dir for each path from array( src ). Writes results into array. + * @description + * Look {@link module:Tools/PathBasic.dir _.path.dir } for details. + * @param {Array} src Array of paths + * + * @example //also works same as regular _.path.dir + * _.path.s.dir( '/a/b' ); // '/a' + * + * @example + * _.path.s.dir( [ '/a/b', '/b/c' ] ); // [ '/a', '/b' ] + * + * @returns {Array} Returns array with results of dir operation. + * @function dir + * @namespace Tools.paths + */ + +/** + * @summary Gets name of each path from array( src ). Writes results into array. + * @description + * Look {@link module:Tools/PathBasic.name _.path.name } for details. + * @param {Array} src Array of paths + * + * @example //also works same as regular _.path.dir + * _.path.s.name( '/a/b' ); // 'b' + * + * @example + * _.path.s.name( [ '/a/b', '/b/c' ] ); // [ 'b', 'c' ] + * + * @returns {Array} Returns array with results of name operation. + * @function name + * @namespace Tools.paths + */ + + +/** + * @summary Gets extension of each path from array( src ). Writes results into array. + * @description + * Look {@link module:Tools/PathBasic.ext _.path.ext } for details. + * @param {Array} src Array of paths + * + * @example //also works same as regular _.path.dir + * _.path.s.ext( '/a/b.js' ); // 'js' + * + * @example + * _.path.s.ext( [ '/a/b.js', '/b/c.s' ] ); // [ 'js', 's' ] + * + * @returns {Array} Returns array with results of ext operation. + * @function ext + * @namespace Tools.paths + */ + + +/** + * @summary Gets common path + * @description + * Supports combining of arrays/maps/strings, see examples. + * Look {@link module:Tools/PathBasic.common _.path.common } for details. + * @param {...String|...Array|...Object} src Array of paths + * + * @example //also works same as regular _.path.common + * _.path.s.common( '/a', '/a/b', '/a/c' ); //'/a' + * + * @example //combining string with array + * _.path.s.common('/a', ['/a/b', '/c' ] ); // [ '/a', '/' ] + * + * @example //combining string with array and map + * _.path.s.common('/a', ['/a/b', '/c' ], {'/a/b' : 1 } ) //{ '/a' : 1, '/': 1} + * + * @returns {Array|Object} Returns array with result for each combination of paths. + * @function common + * @namespace Tools.paths + */ + +// -- +// meta +// -- + +let ParentInit = Parent.Init; +Parent.Init = function Init() +{ + let result = ParentInit.apply( this, arguments ); + + _.assert( _.object.isBasic( this.s ) ); + _.assert( this.s.single !== undefined ); + this.s = Object.create( this.s ); + this.s.single = this; + + return result; +} + +// -- +// implementation +// -- + +let PathExtension = +{ + + // textual reporter + + groupTextualReport, + _commonTextualReport, + commonTextualReport, + moveTextualReport, + +} + +let PathsExtension = +{ + + _keyEndsPathFilter, + _isPathFilter, + + _vectorize, + _vectorizeAsArray, + _vectorizeAll, + _vectorizeAny, + _vectorizeNone, + _vectorizeOnly, + + /* qqq : implement and cover routines: + - joiner + - resolver + */ + + // dichotomy + + are : _vectorizeAsArray( 'is' ), + areAbsolute : _vectorizeAsArray( 'isAbsolute' ), + areRelative : _vectorizeAsArray( 'isRelative' ), + areGlobal : _vectorizeAsArray( 'isGlobal' ), + areGlob : _vectorizeAsArray( 'isGlob' ), + areRefined : _vectorizeAsArray( 'isRefined' ), + areNormalized : _vectorizeAsArray( 'isNormalized' ), + areRoot : _vectorizeAsArray( 'isRoot' ), + areDotted : _vectorizeAsArray( 'isDotted' ), + areTrailed : _vectorizeAsArray( 'isTrailed' ), + areSafe : _vectorizeAsArray( 'isSafe' ), + + allAre : _vectorizeAll( 'is' ), + allAreAbsolute : _vectorizeAll( 'isAbsolute' ), + allAreRelative : _vectorizeAll( 'isRelative' ), + allAreGlobal : _vectorizeAll( 'isGlobal' ), + allAreGlob : _vectorizeAll( 'isGlob' ), + allAreRefined : _vectorizeAll( 'isRefined' ), + allAreNormalized : _vectorizeAll( 'isNormalized' ), + allAreRoot : _vectorizeAll( 'isRoot' ), + allAreDotted : _vectorizeAll( 'isDotted' ), + allAreTrailed : _vectorizeAll( 'isTrailed' ), + allAreSafe : _vectorizeAll( 'isSafe' ), + + anyAre : _vectorizeAny( 'is' ), + anyAreAbsolute : _vectorizeAny( 'isAbsolute' ), + anyAreRelative : _vectorizeAny( 'isRelative' ), + anyAreGlobal : _vectorizeAny( 'isGlobal' ), + anyAreGlob : _vectorizeAny( 'isGlob' ), + anyAreRefined : _vectorizeAny( 'isRefined' ), + anyAreNormalized : _vectorizeAny( 'isNormalized' ), + anyAreRoot : _vectorizeAny( 'isRoot' ), + anyAreDotted : _vectorizeAny( 'isDotted' ), + anyAreTrailed : _vectorizeAny( 'isTrailed' ), + anyAreSafe : _vectorizeAny( 'isSafe' ), + + noneAre : _vectorizeNone( 'is' ), + noneAreAbsolute : _vectorizeNone( 'isAbsolute' ), + noneAreRelative : _vectorizeNone( 'isRelative' ), + noneAreGlobal : _vectorizeNone( 'isGlobal' ), + noneAreGlob : _vectorizeNone( 'isGlob' ), + noneAreRefined : _vectorizeNone( 'isRefined' ), + noneAreNormalized : _vectorizeNone( 'isNormalized' ), + noneAreRoot : _vectorizeNone( 'isRoot' ), + noneAreDotted : _vectorizeNone( 'isDotted' ), + noneAreTrailed : _vectorizeNone( 'isTrailed' ), + noneAreSafe : _vectorizeNone( 'isSafe' ), + + // normalizer + + refine : _vectorize( 'refine' ), + normalize : _vectorize( 'normalize' ), + canonize : _vectorize( 'canonize' ), + normalizeTolerant : _vectorize( 'normalizeTolerant' ), + nativize : _vectorize( 'nativize' ), + dot : _vectorize( 'dot' ), + undot : _vectorize( 'undot' ), + trail : _vectorize( 'trail' ), + detrail : _vectorize( 'detrail' ), + + onlyRefine : _vectorizeOnly( 'refine' ), + onlyNormalize : _vectorizeOnly( 'normalize' ), + onlyDot : _vectorizeOnly( 'dot' ), + onlyUndot : _vectorizeOnly( 'undot' ), + onlyTrail : _vectorizeOnly( 'trail' ), + onlyDetrail : _vectorizeOnly( 'detrail' ), + + // path cut off + + dir : _vectorize( 'dir' ), + dirFirst : _vectorize( 'dirFirst' ), + prefixGet : _vectorize( 'prefixGet' ), + name : _vectorize( 'name' ), + fullName : _vectorize( 'fullName' ), + ext : _vectorize( 'ext' ), + exts : _vectorize( 'exts' ), + withoutExt : _vectorize( 'withoutExt' ), + changeExt : _vectorize( 'changeExt', 2 ), + + // joiner + + join : _vectorize( 'join', Infinity ), + joinRaw : _vectorize( 'joinRaw', Infinity ), + joinIfDefined : _vectorize( 'joinIfDefined', Infinity ), + reroot : _vectorize( 'reroot', Infinity ), + resolve : _vectorize( 'resolve', Infinity ), + joinNames : _vectorize( 'joinNames', Infinity ), + + // + + onlyDir : _vectorizeOnly( 'dir' ), + onlyPrefixGet : _vectorizeOnly( 'prefixGet' ), + onlyName : _vectorizeOnly( 'name' ), + onlyWithoutExt : _vectorizeOnly( 'withoutExt' ), + onlyExt : _vectorizeOnly( 'ext' ), + + // path transformer + + from : _vectorize( 'from' ), + relative : _vectorize( 'relative', 2 ), + common : _vectorize( 'common', Infinity ), + common_ : _vectorize( 'common_', Infinity ), /* !!! */ + + // fields + + path : Parent, + +} + +_.mapExtendDstNotOwn( _.path, PathExtension ); +_.mapExtendDstNotOwn( _.path.s, PathsExtension ); + +_.assert( _.path.groupTextualReport === groupTextualReport ); + +Self.Init(); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathbasic/proto/wtools/abase/l3/PathsBasic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathbasic/proto/wtools/abase/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, PathsBasic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file PathsBasic_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathtools/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathtools/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wpathtools */ ( function wpathtools() { function wpathtools_naked() { +module.exports = require( '../wtools/abase/l5/PathTools.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wPathTools', 'wpathtools' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathtools/proto/node_modules/wpathtools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathtools/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wpathtools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wpathtools */ })(); + +/* */ /* begin of file Glob_s */ ( function Glob_s() { function Glob_s_naked() { ( function _Glob_s_() +{ + +'use strict'; + +/** + * */ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + _.include( 'wPathBasic' ); + _.include( 'wStringsExtra' ); + +} + +// + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.path = _.path || Object.create( null ); + +// -- +// functor +// -- + +function _vectorize( routine, select ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + select = select || 1; + return _.routineVectorize_functor + ( { + routine, + vectorizingArray : 1, + vectorizingMapVals : 0, + vectorizingMapKeys : 1, + select, + } ); +} + +// -- +// simple transformer +// -- + +/* +(\*\*)| -- ** +([?*])| -- ?* +(\[[!^]?.*\])| -- [!^] +([+!?*@]\(.*\))| -- @+!?*() +(\{.*\}) -- {} +(\(.*\)) -- () +*/ + +let _pathIsGlobRegexpSource = ''; +_pathIsGlobRegexpSource += '(?:[?*]+)'; /* asterix, question mark */ +_pathIsGlobRegexpSource += '|(?:([!?*@+]*)\\((.*?(?:\\|(.*?))*)\\))'; /* parentheses */ +_pathIsGlobRegexpSource += '|(?:\\[(.+?)\\])'; /* square brackets */ +_pathIsGlobRegexpSource += '|(?:\\{(.*)\\})'; /* curly brackets */ +_pathIsGlobRegexpSource += '\\(\\)|\\0'; /* zero */ + +let _pathIsGlobRegexp = new RegExp( _pathIsGlobRegexpSource ); + +function _fromGlob( glob ) +{ + let self = this; + let result; + + _.assert( _.strIs( glob ), () => 'Expects string {-glob-}, but got ' + _.entity.strType( glob ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( glob === '' || glob === null ) + return glob; + + let i = glob.search( _pathIsGlobRegexp ); + + if( i >= 0 ) + { + + while( i >= 0 && glob[ i ] !== self.upToken ) + i -= 1; + + if( i === -1 ) + result = ''; + else + result = glob.substr( 0, i+1 ); + + result = self.detrail( result || self.hereToken ); + + } + else + { + result = glob; + } + + _.assert( !self.isGlob( result ) ); + + return result; +} + +// + +function globNormalize( glob ) +{ + let self = this; + let result = _.strReplaceAll( glob, { '()' : '', '*()' : '', '\0' : '' } ); /* xxx : cover */ + if( result !== glob ) + result = self.canonize( result ); + return result; +} + +// + +let _globShortSplitToRegexpSource = ( function functor() +{ + + let self; + let _globRegexpSourceCache = Object.create( null ) + + let _transformation0 = + [ + [ /\[(.+?)\]/g, handlePass ], /* square brackets */ + [ /\.\./g, handlePass ], /* dual dot */ + [ /\./g, handlePass ], /* dot */ + [ /\(\)|\0/g, handlePass ], /* empty parentheses or zero */ + [ /([!?*@+]*)\((.*?(?:\|(.*?))*)\)/g, handlePass ], /* parentheses */ + [ /\*\*\*/g, handlePass ], /* triple asterix */ + [ /\*\*/g, handlePass ], /* dual asterix */ + [ /(\*)/g, handlePass ], /* single asterix */ + [ /(\?)/g, handlePass ], /* question mark */ + ] + + let _transformation1 = + [ + [ /\[(.+?)\]/g, handleSquareBrackets ], /* square brackets */ + [ /\{(.*)\}/g, handleCurlyBrackets ], /* curly brackets */ + ] + + let _transformation2 = + [ + [ /\.\./g, '\\.\\.' ], /* dual dot */ + [ /\./g, '\\.' ], /* dot */ + [ /\(\)|\0/g, '' ], /* empty parentheses or zero */ + [ /([!?*@+]?)\((.*?(?:\|(.*?))*)\)/g, hanleParentheses ], /* parentheses */ + // [ /\/\*\*/g, '(?:\/.*)?', ], /* slash + dual asterix */ + [ /\*\*\*/g, '(?:.*)' ], /* triple asterix */ + [ /\*\*/g, '.*' ], /* dual asterix */ + [ /(\*)/g, '[^\/]*' ], /* single asterix */ + [ /(\?)/g, '[^\/]' ], /* question mark */ + ] + + /* */ + + _globShortSplitToRegexpSource.functor = functor; + return _globShortSplitToRegexpSource; + + function _globShortSplitToRegexpSource( src ) + { + self = this; + + let result = _globRegexpSourceCache[ src ]; + if( result ) + return result; + + _.assert( _.strIs( src ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert + ( + !_.strHas( src, /(^|\/)\.\.(\/|$)/ ) || src === self.downToken, + 'glob should not has splits with ".." combined with something' + ); + + result = transform( src ); + + _globRegexpSourceCache[ src ] = result; + + return result; + } + + /* */ + + function transform( src ) + { + let result = src; + + result = _.strReplaceAll + ( { + src : result, + dictionary : _transformation0, + joining : 1, + onUnknown : handleUnknown, + } ); + + result = _.strReplaceAll( result, _transformation1 ); + result = _.strReplaceAll( result, _transformation2 ); + + return result; + } + + /* */ + + function handleUnknown( src ) + { + return _.regexpEscape( src ); + } + + /* */ + + function handlePass( src ) + { + return src; + } + + /* */ + + function handleCurlyBrackets( src, it ) + { + throw _.err( 'Glob with curly brackets is not allowed ', src ); + } + + /* */ + + function handleSquareBrackets( src, it ) + { + let inside = it.groups[ 0 ]; + /* escape inner [] */ + inside = inside.replace( /[\[\]]/g, ( m ) => '\\' + m ); + /* replace ! -> ^ at the beginning */ + inside = inside.replace( /^!/g, '^' ); + if( inside[ 0 ] === '^' ) + inside = inside + '\/'; + return [ '[' + inside + ']' ]; + } + + /* */ + + function hanleParentheses( src, it ) + { + + let inside = it.groups[ 1 ].split( '|' ); + let multiplicator = it.groups[ 0 ]; + + multiplicator = _.strReverse( multiplicator ); + if( multiplicator === '*' ) + multiplicator += '?'; + + _.assert( _.strCount( multiplicator, '!' ) === 0 || multiplicator === '!' ); + _.assert( _.strCount( multiplicator, '@' ) === 0 || multiplicator === '@' ); + + inside = inside.map( ( i ) => self._globShortSplitToRegexpSource( i ) ); + + let result = '(?:' + inside.join( '|' ) + ')'; + if( multiplicator === '@' ) + result = result; + else if( multiplicator === '!' ) + result = '(?:(?!(?:' + result + '|\/' + ')).)*?'; + else + result += multiplicator; + + /* (?:(?!(?:abc)).)+ */ + + return result; + } + + /* */ + +} )(); + +// -- +// short filter +// -- + +function globShortSplitToRegexp( glob ) +{ + let self = this; + + _.assert( _.strIs( glob ) || _.regexpIs( glob ) ); + _.assert( arguments.length === 1 ); + + if( _.regexpIs( glob ) ) + return glob; + + let str = self._globShortSplitToRegexpSource( glob ); + let result = new RegExp( '^' + str + '$' ); + return result; +} + +// + +function globShortFilter_head( routine, args ) +{ + let result; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + + let o = args[ 0 ]; + if( args[ 1 ] !== undefined ) + o = { src : args[ 0 ], selector : args[ 1 ] } + + o = _.routine.options_( routine, o ); + + if( o.onEvaluate === null ) + o.onEvaluate = function byVal( e, k, src ) + { + return e; + } + + return o; +} + +// + +function globShortFilter_body( o ) +{ + let self = this; + let result; + + _.assert( arguments.length === 1 ); + + // if( _global_.debugger ) + // debugger; + + if( self.isGlob( o.selector ) ) + { + let regexp = self.globShortSplitsToRegexps( o.selector ); + result = _.filter_( null, o.src, ( e, k ) => + { + let val = o.onEvaluate( e, k, o.src ); + return regexp.test( val ) ? e : undefined; + } ); + } + else + { + result = _.filter_( null, o.src, ( e, k ) => + { + return o.onEvaluate( e, k, o.src ) === o.selector ? e : undefined; + } ); + } + + return result; +} + +globShortFilter_body.defaults = +{ + src : null, + selector : null, + onEvaluate : null, +} + +let globShortFilter = _.routine.uniteCloning_replaceByUnite( globShortFilter_head, globShortFilter_body ); + +let globShortFilterVals = _.routine.uniteCloning_replaceByUnite( globShortFilter_head, globShortFilter_body ); +globShortFilterVals.defaults.onEvaluate = function byVal( e, k, src ) +{ + return e; +} + +let globShortFilterKeys = _.routine.uniteCloning_replaceByUnite( globShortFilter_head, globShortFilter_body ); +globShortFilterKeys.defaults.onEvaluate = function byKey( e, k, src ) +{ + return _.arrayIs( src ) ? e : k; +} + +// + +function globShortFit_body( o ) +{ + let self = this; + let result = self.globShortFilter + ( { + src : [ o.src ], + selector : o.selector, + onEvaluate : o.onEvaluate, + } ); + return result.length === 1; +} + +globShortFit_body.defaults = +{ + src : null, + selector : null, + onEvaluate : null, +} + +let globShortFit = _.routine.uniteCloning_replaceByUnite( globShortFilter_head, globShortFit_body ); + +// -- +// long +// -- + +function _globLongSplitsToRegexps( glob ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + _.assert( self.isGlob( glob ) ); + + glob = self.canonize( glob ); + + let analogs1 = self._globAnalogs1( glob ); + let result = []; + + let splits = self.split( analogs1 ); + if( splits[ 0 ] === '' ) + splits[ 0 ] = '/'; + let sources = splits.map( ( e, i ) => self._globShortSplitToRegexpSource( e ) ); + result = self._globRegexpSourceSplitsJoinForTerminal( sources ); + + result = new RegExp( '^(?:' + result + ')$' ); + + return result; +} + +// + +function globLongFilter_head( routine, args ) +{ + let result; + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + + let o = args[ 0 ]; + if( args[ 1 ] !== undefined ) + o = { src : args[ 0 ], selector : args[ 1 ] } + + o = _.routine.options_( routine, o ); + + if( o.onEvaluate === null ) + o.onEvaluate = function byVal( e, k, src ) + { + return e; + } + + return o; +} + +// + +function globLongFilter_body( o ) +{ + let self = this; + let result; + + _.assert( arguments.length === 1 ); + + if( self.isGlob( o.selector ) ) + { + let selectorIsAbsolute = self.isAbsolute( o.selector ); + let regexp = self._globLongSplitsToRegexps( o.selector ); + result = _.filter_( null, o.src, ( e, k ) => + { + let val = o.onEvaluate( e, k, o.src ); + // if( selectorIsAbsolute && !self.isAbsolute( val ) ) + // return undefined; + // debugger; + val = self.canonize( val ); + return regexp.test( val ) ? e : undefined; + } ); + } + else + { + result = _.filter_( null, o.src, ( e, k ) => + { + return o.onEvaluate( e, k, o.src ) === o.selector ? e : undefined; + } ); + } + + return result; +} + +globLongFilter_body.defaults = +{ + src : null, + selector : null, + onEvaluate : null, +} + +let globLongFilter = _.routine.uniteCloning_replaceByUnite( globLongFilter_head, globLongFilter_body ); + +let globLongFilterVals = _.routine.uniteCloning_replaceByUnite( globLongFilter_head, globLongFilter_body ); +globLongFilterVals.defaults.onEvaluate = function byVal( e, k, src ) +{ + return e; +} + +let globLongFilterKeys = _.routine.uniteCloning_replaceByUnite( globLongFilter_head, globLongFilter_body ); +globLongFilterKeys.defaults.onEvaluate = function byKey( e, k, src ) +{ + return _.arrayIs( src ) ? e : k; +} + +// + +function globLongFit_body( o ) +{ + let self = this; + let result = self.globLongFilter + ( { + src : [ o.src ], + selector : o.selector, + onEvaluate : o.onEvaluate, + } ); + return result.length === 1; +} + +globLongFit_body.defaults = +{ + src : null, + selector : null, + onEvaluate : null, +} + +let globLongFit = _.routine.uniteCloning_replaceByUnite( globLongFilter_head, globLongFit_body ); + +// -- +// full filter +// -- + +let _removeExtraDoubleAsterisk = new RegExp( '\\*\\*' + '(?:' + Self._upRegSource + '\\*\\*' + ')+' ); + +function _globAnalogs1( glob ) +{ + let self = this; + let splits = self.split( glob ); + let counter = 0; + + _.assert( _.strIs( glob ), 'Expects string {-glob-}' ); + + /* separate dual asterisks */ + + for( let s = splits.length-1 ; s >= 0 ; s-- ) + { + let split = splits[ s ]; + + if( split === '**' || split === '***' ) + continue; + + if( !_.strHas( split, '**' ) ) + continue; + + counter += 1; + split = _.strSplitFast( { src : split, delimeter : [ '***', '**' ], preservingEmpty : 0 } ); + + for( let e = split.length-1 ; e >= 0 ; e-- ) + { + let element = split[ e ]; + if( element === '**' || element === '***' ) + { + element = '***'; + split[ e ] = element; + continue; + } + + if( !element ) + { + _.assert( 0, 'not expected' ); + split.splice( e, 1 ); + continue; + } + + if( e > 0 ) + element = '*' + element; + if( e < split.length-1 ) + element = element + '*'; + + split[ e ] = element; + } + _.longBut_( splits, splits, [ s, s ], split ); + // _.longButInplace( splits, [ s, s+1 ], split ); + } + + /* concat */ + + let result = splits.join( self.upToken ); + + /* remove duplicates of dual asterisks */ + + for( let r = result.length-1 ; r >= 0 ; r-- ) + { + let res = result[ r ]; + do + { + res = res.replace( _removeExtraDoubleAsterisk, self.upToken ); + if( res === result[ r ] ) + break; + else + result[ r ] = res; + } + while( true ); + } + + /* */ + + return result; +} + +// + +function _globAnalogs2( glob, stemPath, basePath ) +{ + let self = this; + + if( _.arrayIs( glob ) ) + { + return glob.map( ( glob ) => self._globAnalogs2( glob, stemPath, basePath ) ); + } + + _.assert( arguments.length === 3, 'Expects exactly four arguments' ); + _.assert( _.strIs( glob ), 'Expects string {-glob-}' ); + _.assert( _.strIs( stemPath ), 'Expects string' ); + _.assert( _.strIs( basePath ) ); + _.assert( !self.isRelative( glob ) === !self.isRelative( stemPath ), 'Expects both relative path either absolute' ); + _.assert( self.isGlob( glob ), () => 'Expects glob, but got ' + glob ); + + let result = []; + let globDir = self.fromGlob( glob ); + + let globRelativeBase = self.relative( basePath, glob ); + let globDirRelativeBase = self.relative( basePath, globDir ); + let stemRelativeBase = self.relative( basePath, stemPath ); + let baseRelativeStem = self.relative( stemPath, basePath ); + let globDirRelativeStem = self.relative( stemPath, globDir ); + let stemRelativeGlobDir = self.relative( globDir, stemPath ); + let globRelativeGlobDir = self.relative( globDir, glob ); + + if( globDirRelativeBase === self.hereToken && stemRelativeBase === self.hereToken ) + { + + result.push( self.dot( globRelativeBase ) ); + + } + else + { + + if( isDotted( stemRelativeGlobDir ) ) + { + if( self.begins( stemPath, globDir ) || self.begins( globDir, stemPath ) ) + handleInside(); + else + handleNever(); + } + else + { + handleOutside(); + } + + } + + return result; + + /* */ + + function handleInside() + { + + let globSplits = globRelativeGlobDir + + let glob3 = globSplits; + if( globDirRelativeStem !== self.hereToken ) + glob3 = globDirRelativeStem + self.upToken + glob3; + if( stemRelativeGlobDir === self.hereToken ) + { + glob3 = globDirRelativeBase + self.upToken + glob3; + } + else + { + glob3 = self.join( stemRelativeBase, glob3 ); + } + _.arrayAppendOnce( result, self.dot( glob3 ) ); + + if( self.begins( globDir, basePath ) || self.begins( basePath, globDir ) ) + { + let glob4 = globSplits; + if( !isDotted( globDirRelativeBase ) ) + glob4 = globDirRelativeBase + self.upToken + glob4; + _.arrayAppendOnce( result, self.dot( glob4 ) ); + } + + } + + /* */ + + function handleOutside() + { + + let globSplits = globRelativeGlobDir.split( self.upToken ); + let globRegexpSourceSplits = globSplits.map( ( e, i ) => self._globShortSplitToRegexpSource( e ) ); + + if( handleCertain( globSplits, globRegexpSourceSplits ) ) + return; + + let s = 0; + let firstAny = globSplits.length; + while( s < globSplits.length ) + { + let split = globSplits[ s ]; + if( split === '**' || split === '***' ) + { + firstAny = s; + } + let globSliced = new RegExp( '^' + self._globRegexpSourceSplitsJoinForTerminal( globRegexpSourceSplits.slice( 0, s+1 ) ) + '$' ); + if( globSliced.test( stemRelativeGlobDir ) ) + { + + let splits3 = firstAny < globSplits.length ? globSplits.slice( firstAny ) : globSplits.slice( s+1 ); + if( stemRelativeBase !== self.hereToken ) + { + if( isDotted( stemRelativeGlobDir ) ) + _.arrayPrependArray( splits3, self.split( baseRelativeStem ) ); + _.arrayPrependArray( splits3, self.split( stemRelativeBase ) ); + let glob3 = splits3.join( self.upToken ); + _.arrayAppendOnce( result, self.dot( glob3 ) ); + } + + let splits4 = firstAny < globSplits.length ? globSplits.slice( firstAny ) : globSplits.slice( s+1 ); + let glob4 = splits4.join( self.upToken ); + _.arrayAppendOnce( result, self.dot( glob4 ) ); + + } + s += 1; + } + + } + + /* */ + + function handleCertain( globSplits, globRegexpSourceSplits ) + { + + if( globSplits.length === 1 ) + if( globSplits[ 0 ] === '**' || globSplits[ 0 ] === '***' ) + { + _.assert( result.length === 0 ); + result.push( '**' ); + return true; + } + + if( globSplits[ globSplits.length - 1 ] !== '**' && globSplits[ globSplits.length - 1 ] !== '***' ) + return false; + + let globSliced = new RegExp( '^' + self._globRegexpSourceSplitsJoinForTerminal( globRegexpSourceSplits ) + '$' ); + if( !globSliced.test( stemRelativeGlobDir ) ) + return false; + + _.assert( result.length === 0 ); + result.push( '**' ); + return true; + } + + /* */ + + function handleNever() + { + } + + /* */ + + function isDotted( filePath ) + { + return filePath === self.hereToken || filePath === self.downToken || _.strBegins( filePath, self.downToken ); + } + + /* */ + + function isUp( filePath ) + { + return filePath === self.downToken || _.strBegins( filePath, self.downToken ); + } + + /* */ + +} + +// + +function globHas( superGlob, subGlob ) +{ + let self = this; + + _.assert( _.strIs( superGlob ), 'Expects string' ); + _.assert( _.strIs( subGlob ), 'Expects string' ); + + let superGlob0 = superGlob; + let superGlobs = self.globNormalize( superGlob ); + superGlobs = _.array.as( self._globAnalogs1( superGlobs ) ); + + let subGlob0 = subGlob; + let subGlobs = self.globNormalize( subGlob ); + subGlobs = _.array.as( self._globAnalogs1( subGlobs ) ); + + _.assert( _.arrayIs( superGlobs ) ); + _.assert( _.arrayIs( subGlobs ) ); + + + for( let sp = 0 ; sp < superGlobs.length ; sp++ ) + { + let superGlob = superGlobs[ sp ]; + let superPath = self.fromGlob( superGlob ); + + let superGlobSplits = superGlob.split( self.upToken ); + let lastSplit = superGlobSplits[ superGlobSplits.length-1 ]; + + if( lastSplit !== '**' && lastSplit !== '***' ) + continue; + + for( let sb = 0 ; sb < subGlobs.length ; sb++ ) + { + let subGlob = subGlobs[ sb ]; + let subPath = self.fromGlob( subGlob ); + + if( self.begins( subGlob, superGlob ) ) + return true; + + if( !self.begins( subPath, superPath ) ) + continue; + + let superSourceSplits = superGlobSplits.map( ( e, i ) => self._globShortSplitToRegexpSource( e ) ); + + let superRegexp = new RegExp( '^' + self._globRegexpSourceSplitsJoinForTerminal( superSourceSplits ) + '$' ); + if( superRegexp.test( subPath ) ) + return true; + + } + } + + return false; +} + +// + +function _globRegexpSourceSplitsConcatWithSlashes( globRegexpSourceSplits ) +{ + let result = []; + + /* + asterisk and dual-asterisk are optional elements of pattern + so them could be missing + */ + + let isPrevTriAsterisk = false; + let isPrevRoot = false; + for( let s = 0 ; s < globRegexpSourceSplits.length ; s++ ) + { + let split = globRegexpSourceSplits[ s ]; + + let isTriAsterisk = split === '(?:.*)'; /* *** */ + let isDualAsterisk = split === '.*'; /* ** */ + let isAsterisk = split === '[^\/]*'; /* * */ + let isRoot = split === '/'; /* / */ + let prefix = isPrevRoot ? '(?:)' : '(?:^|/)'; + // prefix = '(?:^|/)'; /* xxx : comment out later */ + + if( isTriAsterisk ) + { + split = `(?:${prefix}` + split + ')?'; + } + else if( isDualAsterisk ) + { + split = `(?:${prefix}` + split + ')?'; + } + else if( isAsterisk ) + { + split = `(?:${prefix}` + split + ')?'; + } + else if( s > 0 ) + { + if( isPrevTriAsterisk ) + split = `${prefix}?` + split; + else + split = prefix + split; + } + + isPrevRoot = isRoot; + isPrevTriAsterisk = isTriAsterisk; + result[ s ] = split; + } + + return result; +} + +// + +function _globRegexpSourceSplitsJoinForTerminal( globRegexpSourceSplits ) +{ + let self = this; + let splits = self._globRegexpSourceSplitsConcatWithSlashes( globRegexpSourceSplits ); + let result = splits.join( '' ); + return result; +} + +// + +function _globRegexpSourceSplitsJoinForDirectory( globRegexpSourceSplits ) +{ + let self = this; + let splits = self._globRegexpSourceSplitsConcatWithSlashes( globRegexpSourceSplits ); + let result = _.regexpsAtLeastFirst( splits ).source; + return result; +} + +// + +let _globFullToRegexpSingleCache = Object.create( null ); /* xxx : try */ +function _globFullToRegexpSingle( glob, stemPath, basePath ) +{ + let self = this; + + _.assert( _.strIs( glob ), 'Expects string {-glob-}' ); + _.assert( _.strIs( stemPath ) && !self.isGlob( stemPath ) ); + _.assert( _.strIs( basePath ) && !self.isGlob( basePath ) ); + // _.assert( !!isPositive || isPositive === undefined ); /* xxx */ + // _.assert( arguments.length === 3 || arguments.length === 4 ); + _.assert( arguments.length === 3 ); + + // if( isPositive !== undefined && !isPositive ) + // debugger; + + glob = self.join( stemPath, glob ); + + _.assert( self.isGlob( glob ) ); + + let analogs1 = self._globAnalogs1( glob ); + let analogs2 = self._globAnalogs2( analogs1, stemPath, basePath ); + + let result = Object.create( null ); + result.transient = []; + result.actual = []; + result.certainly = []; + + for( let r = 0 ; r < analogs2.length ; r++ ) + { + let analog = analogs2[ r ]; + let splits = self.split( analog ); + + let certainlySplits; + if( splits[ splits.length - 1 ] === '**' || splits[ splits.length - 1 ] === '***' ) + certainlySplits = splits.slice(); + + let sources = splits.map( ( e, i ) => self._globShortSplitToRegexpSource( e ) ); + if( certainlySplits ) + certainlySplits = certainlySplits.map( ( e, i ) => self._globShortSplitToRegexpSource( e ) ); + + result.actual.push( self._globRegexpSourceSplitsJoinForTerminal( sources ) ); + result.transient.push( self._globRegexpSourceSplitsJoinForDirectory( sources ) ); + if( certainlySplits ) + result.certainly.push( self._globRegexpSourceSplitsJoinForTerminal( certainlySplits ) ); + } + + result.transient = '(?:(?:' + result.transient.join( ')|(?:' ) + '))'; + result.transient = _.regexpsJoin( [ '^', result.transient, '$' ] ); + + result.actual = '(?:(?:' + result.actual.join( ')|(?:' ) + '))'; + result.actual = _.regexpsJoin( [ '^', result.actual, '$' ] ); + + if( result.certainly.length ) + { + result.certainly = '(?:(?:' + result.certainly.join( ')|(?:' ) + '))'; + result.certainly = _.regexpsJoin( [ '^', result.certainly, '$' ] ); + } + else + { + result.certainly = null; + } + + return result; +} + +// + +function globsFullToRegexps() +{ + let self = this; + let r = self._globsFullToRegexps.apply( this, arguments ); + if( _.arrayIs( r ) ) + { + let result = Object.create( null ); + result.actual = r.map( ( e ) => e.actual ); + result.transient = r.map( ( e ) => e.transient ); + return result; + } + return r; +} + +// + +function pathMapToRegexps( o ) +{ + let self = this; + let regexps = Object.create( null ); + + if( arguments[ 1 ] !== undefined ) + o = { filePath : arguments[ 0 ], basePath : arguments[ 1 ] } + + _.routine.options_( pathMapToRegexps, o ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.mapIs( o.basePath ) ); + _.assert( _.mapIs( o.filePath ) ) + + /* has only booleans */ + + let hasOnlyBools = 1; + for( let srcGlob in o.filePath ) + { + let dstPath = o.filePath[ srcGlob ]; + if( !_.boolLike( dstPath ) ) + { + hasOnlyBools = 0; + break; + } + } + + if( hasOnlyBools ) + { + for( let srcGlob in o.filePath ) + if( _.boolLike( o.filePath[ srcGlob ] ) && o.filePath[ srcGlob ] ) + o.filePath[ srcGlob ] = ''; + } + + /* unglob filePath */ + + fileUnglob(); + o.optimizedUnglobedFilePath = _.props.extend( null, o.unglobedFilePath ); + + /* unglob basePath */ + + o.unglobedBasePath = baseUnglob(); + o.optimizedUnglobedBasePath = _.props.extend( null, o.unglobedBasePath ); + + /* group by path */ + + o.groupsMap = groupBySrc( 0 ); + o.optimalGroupsMap = groupBySrc( 1 ); + + /* */ + + o.optimalRegexpsMap = Object.create( null ); + for( let stemPath in o.optimalGroupsMap ) + { + let r = o.optimalRegexpsMap[ stemPath ] = regexpsMapFor( stemPath, o.optimalGroupsMap[ stemPath ] ); + } + + o.regexpsMap = Object.create( null ); + for( let stemPath in o.groupsMap ) + { + let r = o.regexpsMap[ stemPath ] = regexpsMapFor( stemPath, o.groupsMap[ stemPath ] ); + } + + /* */ + + return o; + + /* */ + + function globRemoveLastTotal( filePath ) + { + + if( filePath[ filePath.length-1 ] !== '*' ) + return filePath; + + if( filePath === '***' ) + filePath = '.'; + else if( filePath === '**' ) + filePath = '.'; + else if( filePath === '/***' ) + filePath = '/'; + else if( filePath === '/**' ) + filePath = '/'; + else if( _.strEnds( filePath, '/***' ) ) + filePath = _.strRemoveEnd( filePath, '/**' ) + else + filePath = _.strRemoveEnd( filePath, '/**' ) + + return filePath; + } + + /* */ + + function regexpsMapFor( stemPath, group ) + { + + let basePath = o.unglobedBasePath[ stemPath ]; + let r = Object.create( null ); + r.certainlyHash = new HashMap; + r.transient = []; + r.actualAny = []; + r.actualAny2 = []; + r.actualAll = []; + r.actualNone = []; + + _.assert( _.strDefined( basePath ), 'No base path for', stemPath ); + + let logicPathArray = []; + let shortPathArray = []; + for( let fileGlob0 in group ) + { + let fileGlob = fileGlob0; + let value = group[ fileGlob ]; + + fileGlob = self.globNormalize( fileGlob ); + fileGlob = self._globAnalogs1( fileGlob ); + _.assert( _.strIs( fileGlob ) ); + + if( !self.isGlob( fileGlob ) ) + fileGlob = self.join( fileGlob, '**' ); + + if( fileGlob0 !== fileGlob ) + { + delete group[ fileGlob0 ]; + group[ fileGlob ] = value; + } + + let shortGlob = self.fromGlob( fileGlob ); + + if( _.boolLike( value ) ) + logicPathArray.push( shortGlob ); + else + shortPathArray.push( [ shortGlob, fileGlob ] ); + + } + + shortPathArray.sort( ( a, b ) => + { + if( a[ 0 ] === b[ 0 ] ) + return 0; + else if( a[ 0 ] < b[ 0 ] ) + return -1; + else if( a[ 0 ] > b[ 0 ] ) + return +1; + } ); + + for( let s1 = 0 ; s1 < shortPathArray.length ; s1++ ) + { + let short1Path = shortPathArray[ s1 ][ 0 ]; + let full1Path = shortPathArray[ s1 ][ 1 ]; + for( let s2 = s1+1 ; s2 < shortPathArray.length ; s2++ ) + { + let short2Path = shortPathArray[ s2 ][ 0 ]; + let full2Path = shortPathArray[ s2 ][ 1 ]; + if( !self.begins( short2Path, short1Path ) ) + break; + if( !self.globHas( full1Path, full2Path ) ) + continue; + _.assert( group[ full2Path ] !== undefined ); + delete group[ full2Path ]; + shortPathArray.splice( s2, 1 ); + s2 -= 1; + } + } + + if( shortPathArray.length === 1 && shortPathArray[ 0 ][ 0 ] === stemPath ) + if( !self.isGlob( globRemoveLastTotal( shortPathArray[ 0 ][ 1 ] ) ) ) + { + let shortPath = shortPathArray[ 0 ][ 0 ]; + let fullPath = shortPathArray[ 0 ][ 1 ]; + delete group[ fullPath ]; + shortPathArray.splice( 0, 1 ); + } + + for( let fileGlob in group ) + { + let value = group[ fileGlob ]; + + _.assert( self.isGlob( fileGlob ) ); + + // let isPositive = !( ( _.boolLike( value ) && !value ) ); + // let regexps = regexpsFor( fileGlob, stemPath, basePath, isPositive ); + let regexps = regexpsFor( fileGlob, stemPath, basePath ); + + if( regexps.certainly ) + r.certainlyHash.set( regexps.actual, regexps.certainly ) + + if( value || value === null || value === '' ) + { + if( _.boolLike( value ) ) + { + r.actualAll.push( regexps.actual ); + } + else + { + r.actualAny.push( regexps.actual ); + } + r.transient.push( regexps.transient ) + } + else + { + r.actualNone.push( regexps.actual ); + } + + } + + return r; + } + + /* */ + + function regexpsFor( fileGlob, stemPath, basePath ) + { + let hash = fileGlob + '\0' + stemPath + '\0' + basePath; + let result = regexps[ hash ]; + if( !result ) + result = regexps[ hash ] = self._globFullToRegexpSingle( fileGlob, stemPath, basePath ); + return result; + } + + /* */ + + // function unglobedBasePathAdd( unglobedBasePath, fileGlob, filePath, basePath ) + function unglobedBasePathAdd( op ) + { + _.assert( _.strIs( op.fileGlob ) ); + _.assert( op.filePath === undefined || _.strIs( op.filePath ) ); + _.assert( _.strIs( op.basePath ) ); + _.assert( o.filePath[ op.fileGlob ] !== undefined, () => 'No file path for file glob ' + g ); + + if( _.boolLike( o.filePath[ op.fileGlob ] ) ) + return; + + if( !op.filePath ) + op.filePath = self.fromGlob( op.fileGlob ); + + _.assert + ( + op.unglobedBasePath[ op.filePath ] === undefined || op.unglobedBasePath[ op.filePath ] === op.basePath, + () => 'The same file path ' + _.strQuote( op.filePath ) + ' has several different base paths:' + + '\n - ' + _.strQuote( op.unglobedBasePath[ op.filePath ] ), + '\n - ' + _.strQuote( op.basePath ) + ); + + op.unglobedBasePath[ op.filePath ] = op.basePath; + } + + /* */ + + function fileUnglob() + { + o.fileGlobToPathMap = Object.create( null ); + o.filePathToGlobMap = Object.create( null ); + o.unglobedFilePath = Object.create( null ); + for( let srcGlob in o.filePath ) + { + let dstPath = o.filePath[ srcGlob ]; + + if( dstPath === null ) + dstPath = ''; + + _.assert( self.isAbsolute( srcGlob ), () => 'Expects absolute path, but ' + _.strQuote( srcGlob ) + ' is not' ); + + let srcPath = self.fromGlob( srcGlob ); + + o.fileGlobToPathMap[ srcGlob ] = srcPath; + o.filePathToGlobMap[ srcPath ] = o.filePathToGlobMap[ srcPath ] || []; + o.filePathToGlobMap[ srcPath ].push( srcGlob ); + let wasUnglobedFilePath = o.unglobedFilePath[ srcPath ]; + if( wasUnglobedFilePath === undefined || _.boolLike( wasUnglobedFilePath ) ) + if( !_.boolLike( dstPath ) ) + { + _.assert( wasUnglobedFilePath === undefined || _.boolLike( wasUnglobedFilePath ) || wasUnglobedFilePath === dstPath ); + o.unglobedFilePath[ srcPath ] = dstPath; + } + + } + + } + + /* */ + + function baseUnglob() + { + + let unglobedBasePath = Object.create( null ); + for( let fileGlob in o.basePath ) + { + _.assert( self.isAbsolute( fileGlob ) ); + _.assert( !self.isGlob( o.basePath[ fileGlob ] ) ); + + let filePath; + let basePath = o.basePath[ fileGlob ]; + if( o.filePath[ fileGlob ] === undefined ) + { + filePath = fileGlob; + fileGlob = o.filePathToGlobMap[ filePath ]; + } + + if( _.arrayIs( filePath ) ) + filePath.forEach( ( filePath ) => unglobedBasePathAdd({ unglobedBasePath, fileGlob, filePath, basePath }) ); + else + unglobedBasePathAdd({ unglobedBasePath, fileGlob, filePath, basePath }) + } + + return unglobedBasePath; + } + + /* */ + + function groupBySrc( optimal ) + { + + let groupsMap = Object.create( null ); + let redundantArray = o.redundantArray = Object.keys( o.filePath ); + redundantArray.sort(); + + /* + sorted, so paths with the same base are neighbours now + */ + + for( let f = 0 ; f < redundantArray.length ; f++ ) + { + let fileGlob = redundantArray[ f ]; + let value = o.filePath[ fileGlob ]; + let filePath = o.fileGlobToPathMap[ fileGlob ]; + let group = { [ fileGlob ] : value }; + + if( _.boolLike( value ) ) + continue; + + redundantArray.splice( f, 1 ); + f -= 1; + + for( let f2 = f+1 ; f2 < redundantArray.length ; f2++ ) + { + let fileGlob2 = redundantArray[ f2 ]; + let value2 = o.filePath[ fileGlob2 ]; + let filePath2 = o.fileGlobToPathMap[ fileGlob2 ]; + let begin; + + if( _.boolLike( value2 ) ) + continue; + + _.assert( fileGlob !== fileGlob2 ); + + if( self.begins( filePath2, filePath ) ) + begin = filePath; + + /* skip if different group */ + if( !begin ) + break; + + if( _.boolLike( value2 ) ) + { + group[ fileGlob2 ] = value2; + } + else + { + if( filePath === filePath2 ) + { + group[ fileGlob2 ] = value2; + redundantArray.splice( f2, 1 ); + f2 -= 1; + } + else + { + if( optimal ) + if( o.basePath[ fileGlob2 ] === o.basePath[ fileGlob ] ) + { + group[ fileGlob2 ] = value2; + redundantArray.splice( f2, 1 ); + f2 -= 1; + delete o.optimizedUnglobedFilePath[ filePath2 ]; + delete o.optimizedUnglobedBasePath[ filePath2 ]; + } + } + } + + } + + let commonPath = filePath; + + /* */ + + if( optimal ) + for( let fileGlob2 in group ) + { + let value2 = o.filePath[ fileGlob2 ]; + + if( _.boolLike( value2 ) ) + continue; + + let filePath2 = o.fileGlobToPathMap[ fileGlob2 ]; + if( filePath2.length < commonPath.length ) + { + _.assert( 0 ); + commonPath = filePath2; + } + + } + + /* */ + + for( let f2 = f ; f2 >= 0 ; f2-- ) + { + let fileGlob2 = redundantArray[ f2 ]; + let value2 = o.filePath[ fileGlob2 ]; + let filePath2 = o.fileGlobToPathMap[ fileGlob2 ]; + let begin; + + if( !_.boolLike( value2 ) ) + continue; + + _.assert( fileGlob !== fileGlob2 ); + + if( self.begins( filePath, filePath2 ) ) + begin = filePath; + + /* skip if different group */ + if( !begin ) + continue; + + group[ fileGlob2 ] = value2; + } + + /* */ + + for( let f2 = f+1 ; f2 < redundantArray.length ; f2++ ) + { + let fileGlob2 = redundantArray[ f2 ]; + let value2 = o.filePath[ fileGlob2 ]; + let filePath2 = o.fileGlobToPathMap[ fileGlob2 ]; + let begin; + + if( !_.boolLike( value2 ) ) + continue; + + _.assert( fileGlob !== fileGlob2 ); + + if( self.begins( filePath2, filePath ) ) + begin = filePath; + + /* skip if different group */ + if( !begin ) + break; + + group[ fileGlob2 ] = value2; + } + + _.assert( groupsMap[ commonPath ] === undefined ); + groupsMap[ commonPath ] = group; + + } + + return groupsMap; + } + +} + +pathMapToRegexps.defaults = +{ + filePath : null, + basePath : null, +} + +// -- +// extension +// -- + +let Extension = +{ + + // simple transformer + + _fromGlob, + fromGlob : _vectorize( _fromGlob ), + globNormalize, + _globShortSplitToRegexpSource, + + // short filter + + globShortSplitToRegexp, + globShortSplitsToRegexps : _vectorize( globShortSplitToRegexp ), + globShortFilter, + globShortFilterVals, + globShortFilterKeys, + globShortFit, + + // long filter + + _globLongSplitsToRegexps, + globLongFilter, + globLongFilterVals, + globLongFilterKeys, + globLongFit, + + // full filter + + _globAnalogs1, + _globAnalogs2, + globHas, + + _globRegexpSourceSplitsConcatWithSlashes, + _globRegexpSourceSplitsJoinForTerminal, + _globRegexpSourceSplitsJoinForDirectory, + _globFullToRegexpSingle, + _globsFullToRegexps : _vectorize( _globFullToRegexpSingle, 3 ), + + globsFullToRegexps, + pathMapToRegexps, + +} + +_.props.supplement( Self, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +} )(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathtools/proto/wtools/abase/l5/Glob.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathtools/proto/wtools/abase/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Glob_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Glob_s */ })(); + +/* */ /* begin of file PathTools_s */ ( function PathTools_s() { function PathTools_s_naked() { ( function _PathTools_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to operate paths reliably and consistently. Implements routines for manipulating paths maps and globing. Extends module PathBasic. + @module Tools/base/Path +*/ + +/** + * */ + +/** + * @summary Collection of cross-platform routines to operate paths reliably and consistently. + * @namespace wTools.path + * @module Tools/PathTools + */ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + _.include( 'wPathBasic' ); + _.include( 'wStringsExtra' ); + +} + +// + +const _global = _global_; +const _ = _global_.wTools; +_.path = _.path || Object.create( null ); +_.path.map = _.path.map || Object.create( null ); + +// -- +// path map +// -- + +function _filterPairs( o ) +{ + let self = this; + let result = Object.create( null ); + let hasDst = false; + let hasSrc = false; + let it = Object.create( null ); + it.src = ''; + it.dst = ''; + + _.routine.options_( _filterPairs, o ); + _.assert( arguments.length === 1 ); + _.routineIs( o.onEach ); + + if( o.filePath === null ) + { + o.filePath = ''; + } + if( _.strIs( o.filePath ) ) + { + if( o.isSrc ) + it.src = o.filePath; + else + it.dst = o.filePath; + + let r = o.onEach( it ); + elementsWrite( result, it, r ); + } + else if( _.arrayIs( o.filePath ) ) + { + if( o.isSrc ) + { + for( let p = 0 ; p < o.filePath.length ; p++ ) + { + if( !_.boolIs( o.filePath[ p ] ) ) + { + it.src = o.filePath[ p ] === null ? '' : o.filePath[ p ]; + let r = o.onEach( it ); + elementsWrite( result, it, r ); + } + } + } + else + { + for( let p = 0 ; p < o.filePath.length ; p++ ) + { + if( !_.boolIs( o.filePath[ p ] ) ) + { + it.src = ''; + it.dst = o.filePath[ p ] === null ? '' : o.filePath[ p ]; + let r = o.onEach( it ); + elementsWrite( result, it, r ); + } + } + } + } + else if( _.mapIs( o.filePath ) ) + { + for( let src in o.filePath ) + { + let dst = o.filePath[ src ]; + if( _.arrayIs( dst ) ) + { + if( dst.length === 0 ) + { + it.src = src; + it.dst = ''; + let r = o.onEach( it ); + elementsWrite( result, it, r ); + } + else + { + for( let d = 0 ; d < dst.length ; d++ ) + { + it.src = src; + it.dst = dst[ d ] === null ? '' : dst[ d ]; + let r = o.onEach( it ); + elementsWrite( result, it, r ); + } + } + } + else + { + it.src = src; + it.dst = dst === null ? '' : dst; + let r = o.onEach( it ); + elementsWrite( result, it, r ); + } + } + } + else _.assert( 0 ); + + return end(); + + /* */ + + function elementsWrite( result, it, elements ) + { + + if( elements === it ) + { + _.assert( it.dst === null || _.strIs( it.dst ) || _.arrayIs( it.dst ) || _.boolLike( it.dst ) ); + elements = Object.create( null ); + if( _.arrayIs( it.src ) ) + { + for( let s = 0 ; s < it.src.length ; s++ ) + put( elements, it.src[ s ], it.dst ); + } + else + { + _.assert( it.src === null || _.strIs( it.src ) ); + put( elements, it.src, it.dst ); + } + } + + if( _.arrayIs( elements ) ) + { + elements.forEach( ( r ) => elementsWrite( result, it, r ) ); + return result; + } + else if( elements === undefined ) + { + return result; + } + else if( elements === null || elements === '' ) + { + return elementWrite( result, '', '' ); + } + else if( _.strIs( elements ) ) + { + return elementWrite( result, elements, it.dst ); + } + // else if( _.arrayIs( elements ) ) + // { + // elements.forEach( ( src ) => elementWrite( result, src, it.dst ) ); + // return result; + // } + else if( _.mapIs( elements ) ) + { + for( let src in elements ) + { + let dst = elements[ src ]; + elementWrite( result, src, dst ); + } + return result; + } + + _.assert( 0 ); + } + + /* */ + + function put( container, src, dst ) + { + if( src === null ) + src = ''; + if( dst === null ) + dst = ''; + _.assert( container[ src ] === undefined || container[ src ] === dst ); + _.assert( _.strIs( src ) ); + // _.assert( _.strIs( dst ) || _.arrayIs( dst ) || _.boolLike( dst ) ); // Dmytro : has no sense, this assertions checks above + container[ src ] = dst; + } + + /* */ + + function elementWrite( result, src, dst ) + { + if( _.arrayIs( dst ) ) + { + if( dst.length ) + dst.forEach( ( dst ) => elementWriteSingle( result, src, dst ) ); + else + elementWriteSingle( result, src, '' ); + + return result; + } + else + { + elementWriteSingle( result, src, dst ); + return result; + } + } + + /* */ + + function elementWriteSingle( result, src, dst ) + { + if( dst === null ) + dst = ''; + if( src === null ) + src = ''; + + _.assert( _.strIs( src ) ); + _.assert( _.strIs( dst ) || _.boolLike( dst ) || _.instanceIs( dst ) ); + + + if( _.boolLike( dst ) ) + { + dst = !!dst; + } + + if( _.boolLike( result[ src ] ) ) + { + if( dst !== '' ) + result[ src ] = dst; + } + else if( _.arrayIs( result[ src ] ) ) + { + if( dst !== '' && !_.boolLike( dst ) ) + result[ src ] = _.scalarAppendOnce( result[ src ], dst ); + } + else if( _.strIs( result[ src ] ) || _.instanceIs( result[ src ] ) ) + { + if( result[ src ] === '' || result[ src ] === dst || dst === false ) + result[ src ] = dst; + else if( result[ src ] !== '' && dst !== '' ) + { + if( dst !== true ) + result[ src ] = _.scalarAppendOnce( result[ src ], dst ); + } + } + else + { + result[ src ] = dst; + } + + if( src ) + hasSrc = true; + if( dst !== '' ) + hasDst = true; + + return result; + } + + /* */ + + function end() + { + let r; + + if( result[ '' ] === '' ) + delete result[ '' ]; + + if( !hasSrc ) + { + if( !hasDst ) + return ''; + else if( !o.isSrc && !_.mapIs( o.filePath ) ) + return _.props.vals( result )[ 0 ]; + return result; + } + else if( !hasDst ) + { + r = _.props.keys( result ); + } + else if( !o.isSrc && !_.mapIs( o.filePath ) ) + { + let keys = _.props.keys( result ); + if( keys.length === 1 && keys[ 0 ] === '' ) + return result[ '' ]; + return result; + } + else + { + return result; + } + + if( r.length === 1 ) + r = r[ 0 ] + else if( r.length === 0 ) + r = ''; + + _.assert( _.strIs( r ) || _.arrayIs( r ) ) + return r; + } + +} +_filterPairs.defaults = +{ + filePath : null, + onEach : null, + isSrc : true, +} + +// + +function filterPairs( filePath, onEach ) +{ + + _.assert( arguments.length === 2 ) + + return this._filterPairs + ({ + filePath, + onEach, + isSrc : true, + }); +} + +// + +function filterSrcPairs( filePath, onEach ) +{ + + _.assert( arguments.length === 2 ) + + return this._filterPairs + ({ + filePath, + onEach, + isSrc : true, + }); +} + +// + +function filterDstPairs( filePath, onEach ) +{ + + _.assert( arguments.length === 2 ) + + return this._filterPairs + ({ + filePath, + onEach, + isSrc : false, + }); +} + +// function filterPairs( filePath, onEach ) +// { +// let result = Object.create( null ); +// let hasDst = false; +// let hasSrc = false; +// let it = Object.create( null ); +// it.src = ''; +// it.dst = ''; +// +// _.assert( arguments.length === 2 ); +// _.assert( filePath === null || _.strIs( filePath ) || _.arrayIs( filePath ) || _.mapIs( filePath ) ); +// _.routineIs( onEach ); +// +// if( filePath === null || filePath === '' ) +// { +// let r = onEach( it ); +// elementsWrite( result, it, r ); +// } +// else if( _.strIs( filePath ) ) +// { +// it.src = filePath; +// let r = onEach( it ); +// elementsWrite( result, it, r ); +// } +// else if( _.arrayIs( filePath ) ) +// { +// for( let p = 0 ; p < filePath.length ; p++ ) +// { +// it.src = filePath[ p ]; +// if( filePath[ p ] === null ) +// it.src = ''; +// if( _.boolIs( filePath[ p ] ) ) +// { +// } +// else +// { +// let r = onEach( it ); +// elementsWrite( result, it, r ); +// } +// } +// } +// else if( _.mapIs( filePath ) ) +// { +// for( let src in filePath ) +// { +// let dst = filePath[ src ]; +// if( _.arrayIs( dst ) ) +// { +// if( !dst.length ) +// { +// it.src = src; +// it.dst = ''; +// let r = onEach( it ); +// elementsWrite( result, it, r ); +// } +// else +// for( let d = 0 ; d < dst.length ; d++ ) +// { +// it.src = src; +// it.dst = dst[ d ]; +// if( it.dst === null ) +// it.dst = ''; +// let r = onEach( it ); +// elementsWrite( result, it, r ); +// } +// } +// else +// { +// it.src = src; +// it.dst = dst; +// if( it.dst === null ) +// it.dst = ''; +// let r = onEach( it ); +// elementsWrite( result, it, r ); +// } +// } +// } +// else _.assert( 0 ); +// +// return end(); +// +// /* */ +// +// function elementsWrite( result, it, elements ) +// { +// +// if( _.arrayIs( elements ) ) +// { +// elements.forEach( ( r ) => elementsWrite( result, it, r ) ); +// return result; +// } +// +// _.assert( elements === undefined || elements === null || _.strIs( elements ) || _.arrayIs( elements ) || _.mapIs( elements ) ); +// +// if( elements === undefined ) +// return result; +// +// if( elements === null || elements === '' ) +// return elementWrite( result, '', '' ); +// +// if( _.strIs( elements ) ) +// return elementWrite( result, elements, it.dst ); +// +// if( _.arrayIs( elements ) ) +// { +// elements.forEach( ( src ) => elementWrite( result, src, it.dst ) ); +// return result; +// } +// +// if( _.mapIs( elements ) ) +// { +// for( let src in elements ) +// { +// let dst = elements[ src ]; +// elementWrite( result, src, dst ); +// } +// return result; +// } +// +// _.assert( 0 ); +// } +// +// /* */ +// +// function elementWrite( result, src, dst ) +// { +// if( _.arrayIs( dst ) ) +// { +// if( dst.length ) +// dst.forEach( ( dst ) => elementWriteSingle( result, src, dst ) ); +// else +// elementWriteSingle( result, src, '' ); +// return result; +// } +// elementWriteSingle( result, src, dst ); +// return result; +// } +// +// /* */ +// +// function elementWriteSingle( result, src, dst ) +// { +// if( dst === null ) +// dst = ''; +// if( src === null ) +// src = ''; +// +// _.assert( _.strIs( src ) ); +// _.assert( _.strIs( dst ) || _.boolLike( dst ) || _.instanceIs( dst ) ); +// +// +// if( _.boolLike( dst ) ) +// dst = !!dst; +// +// if( _.boolLike( result[ src ] ) ) +// { +// if( dst !== '' ) +// result[ src ] = dst; +// } +// else if( _.arrayIs( result[ src ] ) ) +// { +// if( dst !== '' && !_.boolLike( dst ) ) +// result[ src ] = _.scalarAppendOnce( result[ src ], dst ); +// } +// else if( _.strIs( result[ src ] ) || _.instanceIs( result[ src ] ) ) +// { +// if( result[ src ] === '' || result[ src ] === dst || dst === false ) +// result[ src ] = dst; +// else if( result[ src ] !== '' && dst !== '' ) +// { +// if( dst !== true ) +// result[ src ] = _.scalarAppendOnce( result[ src ], dst ); +// } +// } +// else +// result[ src ] = dst; +// +// // result[ src ] = _.scalarAppendOnce( result[ src ], dst ); +// +// if( src ) +// hasSrc = true; +// +// if( dst !== '' ) +// hasDst = true; +// +// return result; +// } +// +// /* */ +// +// function end() +// { +// let r; +// +// if( result[ '' ] === '' ) +// delete result[ '' ]; +// +// if( !hasSrc ) +// { +// if( !hasDst ) +// return ''; +// return result; +// } +// else if( !hasDst ) +// { +// r = _.props.keys( result ); +// } +// else +// return result; +// +// if( _.arrayIs( r ) ) +// { +// if( r.length === 1 ) +// r = r[ 0 ] +// else if( r.length === 0 ) +// r = ''; +// } +// +// _.assert( _.strIs( r ) || _.arrayIs( r ) ) +// return r; +// } +// +// } + +// + +// function _filterPairsInplace( filePath, onEach ) +function _filterPairsInplace( o ) +{ + let result = Object.create( null ); + let hasDst = false; + let hasSrc = false; + let it = Object.create( null ); + it.src = ''; + it.dst = ''; + + _.routine.options_( _filterPairsInplace, arguments ); + _.assert( arguments.length === 1 ); + _.routineIs( o.onEach ); + + if( o.filePath === null ) + { + o.filePath = ''; + } + if( _.strIs( o.filePath ) ) + { + + if( o.isSrc ) + it.src = o.filePath; + else + it.dst = o.filePath; + + let r = o.onEach( it ); + elementsWrite( result, it, r ); + + o.filePath = result; + + let keys = _.props.keys( o.filePath ); + if( o.isSrc ) + { + let vals = _.props.vals( o.filePath ); + if( vals.length === 1 && ( vals[ 0 ] === '' || vals[ 0 ] === null ) ) + return keys[ 0 ]; + else if( vals.length === 0 ) + return ''; + } + else + { + if( keys.length === 1 && keys[ 0 ] === '' ) + return o.filePath[ '' ]; + else if( keys.length === 0 ) + return ''; + } + + } + else if( _.arrayIs( o.filePath ) ) + { + + if( o.isSrc ) + { + let filePath2 = _.arrayAppendArraysOnce( [], o.filePath ); + o.filePath.splice( 0, o.filePath.length ); + + for( let p = 0 ; p < filePath2.length ; p++ ) + { + if( !_.boolIs( filePath2[ p ] ) ) + { + it.src = filePath2[ p ] === null ? '' : filePath2[ p ]; + let r = o.onEach( it ); + elementsWrite( result, it, r ); + } + } + _.arrayAppendArrayOnce( o.filePath, normalizeArray( _.props.keys( result ) ) ); + } + else + { + for( let p = 0; p < o.filePath.length; p++ ) + { + if( !_.boolIs( o.filePath[ p ] ) ) + { + it.src = ''; + it.dst = o.filePath[ p ] === null ? '' : o.filePath[ p ]; + let r = o.onEach( it ); + elementsWrite( result, it, r ); + } + } + + let keys = _.props.keys( result ); + if( keys.length === 1 && keys[ 0 ] === '' ) + { + o.filePath.splice( 0, o.filePath.length ); + if( _.arrayIs( result[ '' ] ) ) + _.arrayAppendArrayOnce( o.filePath, result[ '' ] ); + else + _.arrayAppendOnce( o.filePath, result[ '' ] ); + + normalizeArray( o.filePath ); + } + else if( keys.length === 0 ) + { + o.filePath.splice( 0, o.filePath.length ); + } + else + { + o.filePath = result; + } + } + + } + else if( _.mapIs( o.filePath ) ) + { + + for( let src in o.filePath ) + { + let dst = o.filePath[ src ]; + + delete o.filePath[ src ]; + + if( _.arrayIs( dst ) ) + { + if( dst.length === 0 ) + { + it.src = src; + it.dst = ''; + let r = o.onEach( it ); + elementsWrite( o.filePath, it, r ); + } + else + for( let d = 0 ; d < dst.length ; d++ ) + { + it.src = src; + it.dst = dst[ d ] === null ? '' : dst[ d ]; + let r = o.onEach( it ); + elementsWrite( o.filePath, it, r ); + } + } + else + { + it.src = src; + it.dst = dst === null ? '' : dst; + let r = o.onEach( it ); + elementsWrite( o.filePath, it, r ); + } + } + + } + else _.assert( 0 ); + + if( _.mapIs( o.filePath ) ) + { + if( o.filePath[ '' ] === '' ) + delete o.filePath[ '' ]; + } + + return o.filePath; + + /* */ + + function elementsWrite( filePath, it, elements ) + { + + if( elements === it ) + { + _.assert( it.dst === null || _.strIs( it.dst ) || _.arrayIs( it.dst ) || _.boolLike( it.dst ) ); + elements = Object.create( null ); + if( _.arrayIs( it.src ) ) + { + for( let s = 0 ; s < it.src.length ; s++ ) + put( elements, it.src[ s ], it.dst ); + } + else + { + _.assert( it.src === null || _.strIs( it.src ) ); + put( elements, it.src, it.dst ); + } + } + + if( elements === undefined ) + { + return filePath; + } + else if( elements === null || elements === '' ) + { + return elementWrite( filePath, '', '' ); + } + else if( _.strIs( elements ) ) + { + if( o.isSrc ) + return elementWrite( filePath, elements, it.dst ); + else + return elementWrite( filePath, it.src, elements ); + } + else if( _.arrayIs( elements ) ) + { + if( elements.length === 0 ) + return elementWrite( filePath, '', '' ); + elements.forEach( ( r ) => elementsWrite( filePath, it, r ) ); + return filePath; + } + else if( _.mapIs( elements ) ) + { + for( let src in elements ) + { + let dst = elements[ src ]; + elementWrite( filePath, src, dst ); + } + return filePath; + } + + _.assert( 0 ); + } + + /* */ + + function put( container, src, dst ) + { + if( src === null ) + src = ''; + if( dst === null ) + dst = ''; + _.assert( container[ src ] === undefined || container[ src ] === dst ); + _.assert( _.strIs( src ) ); + // _.assert( _.strIs( dst ) || _.arrayIs( dst ) || _.boolLike( dst ) ); + // Dmytro : it has no sense, this assertions check dst above + container[ src ] = dst; + } + + /* */ + + function elementWrite( filePath, src, dst ) + { + if( _.arrayIs( dst ) ) + { + if( dst.length ) + dst.forEach( ( dst ) => elementWriteSingle( filePath, src, dst ) ); + else + elementWriteSingle( filePath, src, '' ); + + return filePath; + } + else + { + elementWriteSingle( filePath, src, dst ); + return filePath; + } + } + + /* */ + + function elementWriteSingle( filePath, src, dst ) + { + if( dst === null ) + dst = ''; + if( src === null ) + src = ''; + + _.assert( _.strIs( src ) ); + _.assert( _.strIs( dst ) || _.boolLike( dst ) || _.instanceIs( dst ) ); + + if( _.boolLike( dst ) ) + { + dst = !!dst; + } + + if( _.boolLike( filePath[ src ] ) ) + { + if( dst !== '' ) + filePath[ src ] = dst; + } + else if( _.arrayIs( filePath[ src ] ) ) + { + if( dst !== '' && !_.boolLike( dst ) ) + filePath[ src ] = _.scalarAppendOnce( filePath[ src ], dst ); + } + else if( _.strIs( filePath[ src ] ) || _.instanceIs( filePath[ src ] ) ) + { + if( filePath[ src ] === '' || filePath[ src ] === dst || dst === false ) + filePath[ src ] = dst; + else if( filePath[ src ] !== '' && dst !== '' ) + { + if( dst !== true ) + filePath[ src ] = _.scalarAppendOnce( filePath[ src ], dst ); + } + } + else + { + filePath[ src ] = dst; + } + + return filePath; + } + + /* */ + + function normalizeArray( src ) + { + return _.arrayRemoveElement( src, '' ); + } + +} + +_filterPairsInplace.defaults = +{ + filePath : null, + onEach : null, + isSrc : true, +} + +// + +function filterPairsInplace( filePath, onEach ) +{ + _.assert( arguments.length === 2 ); + + return this._filterPairsInplace + ({ + filePath, + onEach, + isSrc : true, + }); +} + +// + +function filterSrcPairsInplace( filePath, onEach ) +{ + _.assert( arguments.length === 2 ); + + return this._filterPairsInplace + ({ + filePath, + onEach, + isSrc : true, + }); +} + +// + +function filterDstPairsInplace( filePath, onEach ) +{ + _.assert( arguments.length === 2 ); + + return this._filterPairsInplace + ({ + filePath, + onEach, + isSrc : false, + }); +} + +// + +function filterPairs_head( routine, args ) +{ + _.assert( arguments.length === 2 ); + + let o = Object.create( null ); + if( args.length === 1 ) + { + _.assert( _.mapIs( args[ 0 ] ) ); + o = args[ 0 ]; + } + else + { + if( args.length === 3 ) + { + o.onEach = args[ 2 ]; + o.filePath = args[ 1 ]; + + if( args[ 0 ] === null ) + o.dst = true; + else if( args[ 0 ] === o.filePath ) + o.dst = false; + else if( _.arrayIs( args[ 0 ] ) || _.mapIs( args[ 0 ] ) ) + o.dst = args[ 0 ]; + else + _.assert( 0 ); + } + else if( args.length === 2 ) + { + o.onEach = args[ 1 ]; + o.filePath = args[ 0 ]; + o.dst = false; + } + else + _.assert( 0 ); + } + + _.routine.options_( routine, o ); + _.routineIs( o.onEach, '{-onEach-} should be a routine' ); + + return o; +} + +// + +function filterPairs_body( o ) +{ + let self = this; + let result = Object.create( null ); + let hasDst = false; + let hasSrc = false; + let it = Object.create( null ); + it.src = ''; + it.dst = ''; + + if( o.filePath === null ) + { + o.filePath = ''; + } + if( _.strIs( o.filePath ) ) + { + + if( o.isSrc ) + it.src = o.filePath; + else + it.dst = o.filePath; + + let r = o.onEach( it ); + elementsWrite( result, it, r ); + + } + else if( _.arrayIs( o.filePath ) ) + { + + if( o.isSrc ) + { + for( let p = 0; p < o.filePath.length; p++ ) + { + it.src = o.filePath[ p ] === null ? '' : o.filePath[ p ]; + it.dst = ''; + + if( !_.boolIs( o.filePath[ p ] ) ) + { + let r = o.onEach( it ); + elementsWrite( result, it, r ); + } + } + } + else + { + for( let p = 0; p < o.filePath.length; p++ ) + { + it.src = ''; + it.dst = o.filePath[ p ] === null ? '' : o.filePath[ p ]; + + if( !_.boolIs( o.filePath[ p ] ) ) + { + let r = o.onEach( it ); + elementsWrite( result, it, r ); + } + } + } + + } + else if( _.mapIs( o.filePath ) ) + { + for( let src in o.filePath ) + { + let dst1 = o.filePath[ src ]; + + if( _.arrayIs( dst1 ) ) + { + if( dst1.length === 0 ) + { + it.src = src; + it.dst = ''; + let r = o.onEach( it ); + elementsWrite( result, it, r ); + } + else + for( let d = 0 ; d < dst1.length ; d++ ) + { + it.src = src; + it.dst = dst1[ d ] === null ? '' : dst1[ d ]; + let r = o.onEach( it ); + elementsWrite( result, it, r ); + } + } + else + { + it.src = src; + it.dst = dst1 === null ? '' : dst1; + let r = o.onEach( it ); + elementsWrite( result, it, r ); + } + } + } + else + { + _.assert( 0 ); + } + + return end(); + + /* */ + + function elementsWrite( filePath, it, elements ) + { + + if( elements === it ) + { + _.assert( it.dst === null || _.strIs( it.dst ) || _.arrayIs( it.dst ) || _.boolLike( it.dst ) ); + elements = Object.create( null ); + if( _.arrayIs( it.src ) ) + { + for( let s = 0 ; s < it.src.length ; s++ ) + put( elements, it.src[ s ], it.dst ); + } + else + { + _.assert( it.src === null || _.strIs( it.src ) ); + put( elements, it.src, it.dst ); + } + } + + if( elements === undefined ) + { + return filePath; + } + else if( elements === null || elements === '' ) + { + return elementWrite( filePath, '', '' ); + } + else if( _.strIs( elements ) ) + { + return elementWrite( filePath, elements, it.dst ); + } + else if( _.arrayIs( elements ) ) + { + if( elements.length === 0 ) + return elementWrite( filePath, '', '' ); + + for( let i = 0; i < elements.length; i++ ) + elementsWrite( filePath, it, elements[ i ] ); + return filePath; + } + else if( _.mapIs( elements ) ) + { + for( let src in elements ) + elementWrite( filePath, src, elements[ src ] ); + return filePath; + } + + _.assert( 0 ); + } + + /* */ + + function put( container, src, dst ) + { + if( src === null ) + src = ''; + if( dst === null ) + dst = ''; + _.assert( _.strIs( src ) ); + _.assert( container[ src ] === undefined || container[ src ] === dst ); + container[ src ] = dst; + } + + /* */ + + function elementWrite( filePath, src, dst ) + { + if( _.arrayIs( dst ) ) + { + if( dst.length ) + dst.forEach( ( dst ) => elementWriteSingle( filePath, src, dst ) ); + else + elementWriteSingle( filePath, src, '' ); + return filePath; + } + else + { + elementWriteSingle( filePath, src, dst ); + return filePath; + } + } + + /* */ + + function elementWriteSingle( filePath, src, dst ) + { + if( dst === null ) + dst = ''; + if( src === null ) + src = ''; + + _.assert( _.strIs( src ) ); + _.assert( _.strIs( dst ) || _.boolLike( dst ) || _.instanceIs( dst ) ); + + if( _.boolLike( dst ) ) + { + dst = !!dst; + } + + if( _.boolLike( filePath[ src ] ) ) + { + if( dst !== '' ) + filePath[ src ] = dst; + } + else if( _.arrayIs( filePath[ src ] ) ) + { + if( dst !== '' && !_.boolLike( dst ) ) + filePath[ src ] = _.scalarAppendOnce( filePath[ src ], dst ); + } + else if( _.strIs( filePath[ src ] ) || _.instanceIs( filePath[ src ] ) ) + { + if( filePath[ src ] === '' || filePath[ src ] === dst || dst === false ) + filePath[ src ] = dst; + else if( filePath[ src ] !== '' && dst !== '' ) + { + if( dst !== true ) + filePath[ src ] = _.scalarAppendOnce( filePath[ src ], dst ); + } + } + else + { + filePath[ src ] = dst; + } + + if( src ) + hasSrc = true; + if( dst !== '' ) + hasDst = true; + + return filePath; + } + + /* */ + + function end() + { + if( !hasSrc ) + { + if( !hasDst ) + result = ''; + else if( !o.isSrc && !_.mapIs( o.filePath ) ) + result = _.props.vals( result )[ 0 ]; + } + else if( !hasDst && o.isSrc ) + result = _.props.keys( result ); + + if( o.dst === false ) + { + if( _.arrayIs( o.filePath ) ) + { + o.filePath.splice( 0, o.filePath.length ); + + if( _.arrayIs( result ) ) + { + result = _.arrayAppendArrayOnce( o.filePath, result ); + } + else if( _.mapIs( result ) ) + { + if( o.isSrc ) + result = _.arrayAppendArrayOnce( o.filePath, _.props.keys( result ) ); + } + else + { + result = _.arrayAppendOnce( o.filePath, result ); + } + } + else if( _.mapIs( o.filePath ) ) + { + for( let k in o.filePath ) + delete o.filePath[ k ]; + + if( _.mapIs( result ) ) + for( let k in result ) + o.filePath[ k ] = result[ k ]; + + else if( _.arrayIs( result ) ) + for( let i = 0; i < result.length; i++ ) + o.filePath[ result[ i ] ] = ''; + else + o.filePath[ result ] = ''; + + result = o.filePath; + } + else if( _.primitiveIs( o.filePath ) ) + { + if( result.length === 1 ) + return result[ 0 ]; + } + + result = self.simplify_( result, result ); + } + else if( o.dst === true ) + { + if( result.length === 1 ) + return result[ 0 ]; + else if( result.length === 0 ) + return ''; + + result = self.simplify_( null, result ); + } + else + { + if( _.arrayIs( o.dst ) ) + { + if( _.arrayIs( result ) ) + result = _.arrayAppendArrayOnce( o.dst, result ); + else if( _.mapIs( result ) ) + { + if( o.isSrc ) + result = _.arrayAppendArrayOnce( o.dst, _.props.keys( result ) ); + else + result = _.arrayAppendArraysOnce( o.dst, _.props.vals( result ) ); + } + else + result = _.arrayAppendOnce( o.dst, result ); + } + else if( _.mapIs( o.dst ) ) + { + if( _.mapIs( result ) ) + { + if( !o.isSrc && !_.mapIs( o.filePath ) ) + { + for( let k in result ) + o.dst[ '' ] = _.scalarAppendOnce( o.dst[ '' ], result[ k ] ); + } + else + { + for( let k in result ) + o.dst[ k ] = result[ k ]; + } + } + + else if( _.arrayIs( result ) ) + { + if( !o.isSrc && !_.mapIs( o.filePath ) ) + { + for( let i = 0; i < result.length; i++ ) + o.dst[ '' ] = _.scalarAppend( o.dst[ '' ], result[ i ] ); + } + else + { + for( let i = 0; i < result.length; i++ ) + o.dst[ result[ i ] ] = ''; + } + } + else + { + if( o.isSrc ) + o.dst[ result ] = ''; + else + o.dst[ '' ] = result; + } + + result = o.dst; + } + result = self.simplify_( result, result ); + + } + + if( _.mapIs( result ) && result[ '' ] === '' ) + delete result[ '' ]; + + return result; + } + +} +filterPairs_body.defaults = +{ + dst : null, + filePath : null, + onEach : null, + isSrc : true, +} + +// + +var filterPairs_ = _.routine.uniteCloning_replaceByUnite( filterPairs_head, filterPairs_body ); +filterPairs_.defaults = +{ + dst : null, + filePath : null, + onEach : null, + isSrc : true, +} + +// + +var filterSrcPairs_ = _.routine.uniteCloning_replaceByUnite( filterPairs_head, filterPairs_body ); +filterSrcPairs_.defaults = +{ + dst : null, + filePath : null, + onEach : null, + isSrc : true, +} + +// + +var filterDstPairs_ = _.routine.uniteCloning_replaceByUnite( filterPairs_head, filterPairs_body ); +filterDstPairs_.defaults = +{ + dst : null, + filePath : null, + onEach : null, + isSrc : false, +} + +// + +function _filterInplace( o ) +{ + let it = Object.create( null ); + + _.routine.options_( _filterInplace, o ); + _.assert( arguments.length === 1 ); + _.routineIs( o.onEach ); + + if( o.filePath === null ) + { + o.filePath = ''; + } + if( _.strIs( o.filePath ) ) + { + + it.value = o.filePath; + if( o.isSrc ) + { + it.src = o.filePath; + it.dst = ''; + it.side = 'src'; + } + else + { + it.src = ''; + it.dst = o.filePath; + it.side = 'dst'; + } + let r = o.onEach( it.value, it ); + + if( r === undefined || r === null ) + return ''; + else if( _.strIs( r ) ) + return r; + else if( _.arrayIs( r ) ) + r = write( it, r ); + + if( r.length === 0 ) + return ''; + if( r.length === 1 ) + return r[ 0 ]; + else + return r; + } + else if( _.arrayIs( o.filePath ) ) + { + if( o.isSrc ) + { + let filePath2 = o.filePath.slice(); + o.filePath.splice( 0, o.filePath.length ); + it.side = 'src'; + + for( let p = 0 ; p < filePath2.length ; p++ ) + { + + it.index = p; + it.src = filePath2[ p ] === null ? '' : filePath2[ p ]; + it.dst = ''; + it.value = it.src; + + let r = o.onEach( it.value, it ); + if( r !== undefined ) + _.arrayAppendArraysOnce( o.filePath, r ); + } + return write( it, o.filePath ); + } + else + { + let filePath2 = o.filePath.slice(); + o.filePath.splice( 0, o.filePath.length ); + it.side = 'dst'; + + for( let p = 0 ; p < filePath2.length ; p++ ) + { + it.index = p; + it.src = ''; + it.dst = filePath2[ p ] === null ? '' : filePath2[ p ]; + it.value = it.dst; + + let r = o.onEach( it.value, it ); + if( r !== undefined ) + _.arrayAppendArraysOnce( o.filePath, r ); + } + return write( it, o.filePath ); + } + } + else if( _.mapIs( o.filePath ) ) + { + for( let src in o.filePath ) + { + let dst = o.filePath[ src ]; + + delete o.filePath[ src ]; + + if( _.arrayIs( dst ) ) + { + dst = dst.slice(); + if( dst.length === 0 ) + { + it.src = src; + it.dst = ''; + it.value = it.src; + it.side = 'src'; + let srcResult = o.onEach( it.value, it ); + it.side = 'dst'; + it.value = it.dst; + let dstResult = o.onEach( it.value, it ); + write( o.filePath, srcResult, dstResult ); + } + else + { + for( let d = 0 ; d < dst.length ; d++ ) + { + it.src = src; + it.dst = dst[ d ] === null ? '' : dst[ d ]; + it.value = it.src; + it.side = 'src'; + let srcResult = o.onEach( it.value, it ); + it.value = it.dst; + it.side = 'dst'; + let dstResult = o.onEach( it.value, it ); + write( o.filePath, srcResult, dstResult ); + } + } + } + else + { + it.src = src; + it.dst = dst === null ? '' : dst; + it.value = it.src; + it.side = 'src'; + let srcResult = o.onEach( it.value, it ); + it.side = 'dst'; + it.value = it.dst; + let dstResult = o.onEach( it.value, it ); + write( o.filePath, srcResult, dstResult ); + } + + } + + } + else _.assert( 0 ); + + if( _.mapIs( o.filePath ) ) + { + if( o.filePath[ '' ] === '' ) + delete o.filePath[ '' ]; + } + + return o.filePath; + + /* */ + + function write( pathMap, src, dst ) + { + if( src === null || ( _.arrayIs( dst ) && dst.length === 0 ) ) + src = ''; + if( dst === null || ( _.arrayIs( dst ) && dst.length === 0 ) ) + dst = ''; + if( _.arrayIs( dst ) && dst.length === 1 ) + dst = dst[ 0 ]; + if( _.boolLike( dst ) ) + dst = !!dst; + + _.assert( src === undefined || _.strIs( src ) || _.arrayIs( src ) ); + + if( dst !== undefined ) + { + if( _.arrayIs( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( src[ s ] !== undefined ) + pathMap[ src[ s ] ] = append( pathMap[ src[ s ] ], dst ); + } + else + { + if( src !== undefined ) + pathMap[ src ] = append( pathMap[ src ], dst ); + } + } + else if( _.arrayIs( src ) ) + { + let src2 = src.slice(); + src.splice( 0, src.length ); + for( let i = 0 ; i < src2.length ; i++ ) + { + if( src2[ i ] !== null && src2[ i ] !== '' && src2[ i ] !== undefined && !_.boolLike( src2[ i ] ) ) + _.arrayAppendOnce( src, src2[ i ] ); + } + return src; + } + + } + + function append( dst, src ) + { + if( src === '' ) + dst = src; + else if( _.boolLike( src ) ) + dst = src; + else + { + if( _.strIs( dst ) || _.arrayIs( dst ) ) + dst = _.scalarAppendOnce( dst, src ); + else + dst = src; + } + return dst; + } + +} +_filterInplace.defaults = +{ + filePath : null, + onEach : null, + isSrc : true, +} + +// + +function filterInplace( filePath, onEach ) +{ + + _.assert( arguments.length === 2 ); + + return _filterInplace + ({ + filePath, + onEach, + isSrc : true, + }); +} + +// + +function filterSrcInplace( filePath, onEach ) +{ + + _.assert( arguments.length === 2 ); + + return _filterInplace + ({ + filePath, + onEach, + isSrc : true, + }); +} + +// + +function filterDstInplace( filePath, onEach ) +{ + + _.assert( arguments.length === 2 ); + + return _filterInplace + ({ + filePath, + onEach, + isSrc : false, + }); +} + +// + +function _filter( o ) +{ + let self = this; + let it = Object.create( null ); + let result; + + _.routine.options_( _filter, o ); + _.assert( arguments.length === 1 ); + _.routineIs( o.onEach ); + + if( o.filePath === null ) + { + o.filePath = ''; + } + if( _.strIs( o.filePath ) ) + { + + it.value = o.filePath; + if( o.isSrc ) + { + it.src = o.filePath; + it.dst = ''; + it.side = 'src'; + } + else + { + it.src = ''; + it.dst = o.filePath; + it.side = 'dst'; + } + + result = o.onEach( it.value, it ); + if( result === undefined ) + return null; + + } + else if( _.arrayIs( o.filePath ) ) + { + + result = []; + + if( o.isSrc ) + { + it.side = 'src'; + for( let p = 0; p < o.filePath.length; p++ ) + { + it.index = p; + it.src = o.filePath[ p ] === null ? '' : o.filePath[ p ]; + it.dst = ''; + it.value = it.src; + + let r = o.onEach( it.value, it ); + if( r !== undefined ) + _.arrayAppendArraysOnce( result, r ); + } + } + else + { + it.side = 'dst'; + for( let p = 0; p < o.filePath.length; p++ ) + { + it.index = p; + it.src = ''; + it.dst = o.filePath[ p ] === null ? '' : o.filePath[ p ]; + it.value = it.dst; + let r = o.onEach( it.value, it ); + if( r !== undefined ) + _.arrayAppendArraysOnce( result, r ); + } + } + + } + else if( _.mapIs( o.filePath ) ) + { + + result = Object.create( null ); + for( let src in o.filePath ) + { + let dst = o.filePath[ src ]; + + if( _.arrayIs( dst ) ) + { + dst = dst.slice(); + if( dst.length === 0 ) + { + it.src = src; + it.dst = ''; + it.value = it.src; + it.side = 'src'; + let srcResult = o.onEach( it.value, it ); + it.value = it.dst; + it.side = 'dst'; + let dstResult = o.onEach( it.value, it ); + write( result, srcResult, dstResult ); + } + else + { + for( let d = 0 ; d < dst.length ; d++ ) + { + it.src = src; + it.dst = dst[ d ] === null ? '' : dst[ d ]; + it.value = it.src; + it.side = 'src'; + let srcResult = o.onEach( it.value, it ); + it.value = it.dst; + it.side = 'dst'; + let dstResult = o.onEach( it.value, it ); + write( result, srcResult, dstResult ); + } + } + } + else + { + it.src = src; + it.dst = dst === null ? '' : dst; + it.value = it.src; + it.side = 'src'; + let srcResult = o.onEach( it.value, it ); + it.value = it.dst; + it.side = 'dst'; + let dstResult = o.onEach( it.value, it ); + write( result, srcResult, dstResult ); + } + } + + } + else _.assert( 0 ); + + return self.simplify( result ); + + /* */ + + function write( pathMap, src, dst ) + { + if( src === null || ( _.arrayIs( dst ) && dst.length === 0 ) ) + src = ''; + if( dst === null || ( _.arrayIs( dst ) && dst.length === 0 ) ) + dst = ''; + + _.assert( src === undefined || _.strIs( src ) || _.arrayIs( src ) ); + + if( dst !== undefined ) + { + if( _.arrayIs( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( src[ s ] !== undefined ) + pathMap[ src[ s ] ] = _.scalarAppend( pathMap[ src[ s ] ], dst ); + } + else if( src !== undefined ) + { + pathMap[ src ] = _.scalarAppend( pathMap[ src ], dst ); + } + } + + } + +} +_filter.defaults = +{ + filePath : null, + onEach : null, + isSrc : true, +} + +// + +function filter( filePath, onEach ) +{ + + _.assert( arguments.length === 2 ); + + return this._filter + ({ + filePath, + onEach, + isSrc : true, + }); +} + +// + +function filterSrc( filePath, onEach ) +{ + + _.assert( arguments.length === 2 ); + + return this._filter + ({ + filePath, + onEach, + isSrc : true, + }); +} + +// + +function filterDst( filePath, onEach ) +{ + + _.assert( arguments.length === 2 ); + + return this._filter + ({ + filePath, + onEach, + isSrc : false, + }); +} + +// + +// function filter( filePath, onEach ) +// { +// let self = this; +// let it = Object.create( null ); +// +// _.assert( arguments.length === 2 ); +// _.assert( filePath === null || _.strIs( filePath ) || _.arrayIs( filePath ) || _.mapIs( filePath ) ); +// _.routineIs( onEach ); +// +// if( filePath === null || _.strIs( filePath ) ) +// { +// it.value = filePath; +// let r = onEach( it.value, it ); +// if( r === undefined ) +// return null; +// return self.simplify( r ); +// } +// else if( _.arrayIs( filePath ) ) +// { +// let result = []; +// for( let p = 0 ; p < filePath.length ; p++ ) +// { +// it.index = p; +// it.value = filePath[ p ]; +// let r = onEach( it.value, it ); +// if( r !== undefined ) +// result.push( r ); +// } +// return self.simplify( result ); +// } +// else if( _.mapIs( filePath ) ) +// { +// let result = Object.create( null ); +// for( let src in filePath ) +// { +// let dst = filePath[ src ]; +// +// if( _.arrayIs( dst ) ) +// { +// dst = dst.slice(); +// for( let d = 0 ; d < dst.length ; d++ ) +// { +// it.src = src; +// it.dst = dst[ d ]; +// it.value = it.src; +// it.side = 'src'; +// let srcResult = onEach( it.value, it ); +// it.value = it.dst; +// it.side = 'dst'; +// let dstResult = onEach( it.value, it ); +// write( result, srcResult, dstResult ); +// } +// } +// else +// { +// it.src = src; +// it.dst = dst; +// it.value = it.src; +// it.side = 'src'; +// let srcResult = onEach( it.value, it ); +// it.value = it.dst; +// it.side = 'dst'; +// let dstResult = onEach( it.value, it ); +// write( result, srcResult, dstResult ); +// } +// +// } +// +// return self.simplify( result ); +// } +// else _.assert( 0 ); +// +// /* */ +// +// function write( pathMap, src, dst ) +// { +// +// _.assert( src === undefined || _.strIs( src ) || _.arrayIs( src ) ); +// +// if( dst !== undefined ) +// { +// if( _.arrayIs( src ) ) +// { +// for( let s = 0 ; s < src.length ; s++ ) +// if( src[ s ] !== undefined ) +// pathMap[ src[ s ] ] = _.scalarAppend( pathMap[ src[ s ] ], dst ); +// } +// else if( src !== undefined ) +// { +// pathMap[ src ] = _.scalarAppend( pathMap[ src ], dst ); +// } +// } +// +// } +// +// } + +// + +function filter_head( routine, args ) +{ + _.assert( arguments.length === 2 ); + + let o = Object.create( null ); + if( args.length === 1 ) + { + _.assert( _.mapIs( args[ 0 ] ) ); + o = args[ 0 ]; + } + else + { + if( args.length === 3 ) + { + o.onEach = args[ 2 ]; + o.filePath = args[ 1 ]; + + if( args[ 0 ] === null ) + o.dst = true; + else if( args[ 0 ] === args[ 1 ] ) + o.dst = false; + else if( _.arrayIs( args[ 0 ] ) || _.mapIs( args[ 0 ] ) ) + o.dst = args[ 0 ]; + else + _.assert( 0 ); + } + else if( args.length === 2 ) + { + o.onEach = args[ 1 ]; + o.filePath = args[ 0 ]; + o.dst = false; + } + else + _.assert( 0 ); + + + } + + _.routine.options_( routine, o ); + _.routineIs( o.onEach, '{-onEach-} should be a routine' ); + + return o; +} + + +function filter_body( o ) +{ + + if( o.filePath === null ) + o.filePath = ''; + + let result; + let it = Object.create( null ); + + if( o.dst === true ) + result = new o.filePath.constructor(); + else if( o.dst === false ) + result = o.filePath; + else + result = o.dst; + + if( _.strIs( o.filePath ) ) + { + it.value = o.filePath; + if( o.isSrc ) + { + it.src = o.filePath; + it.dst = ''; + it.side = 'src'; + } + else + { + it.src = ''; + it.dst = o.filePath; + it.side = 'dst'; + } + + let r = o.onEach( it.value, it ); + if( r === undefined || r === null ) + { + r = ''; + } + else if( _.arrayIs( r ) ) + { + if( r.length === 0 ) + r = ''; + else if( r.length === 1 ) + r = r[ 0 ]; + } + + if( _.arrayIs( result ) ) + { + if( _.arrayIs( r ) ) + _.arrayAppendArrayOnce( result, r ); + else + _.arrayAppendOnce( result, r ); + } + else if( _.mapIs( result ) ) + { + result[ r ] = ''; + } + else + { + result = r; + } + } + else if( _.arrayIs( o.filePath ) ) + { + if( o.isSrc ) + { + it.side = 'src'; + for( let p = 0; p < o.filePath.length; p++ ) + { + it.index = p; + it.src = o.filePath[ p ] === null ? '' : o.filePath[ p ]; + it.dst = ''; + it.value = it.src; + + let r = o.onEach( it.value, it ); + writeArrayResult( r, p, result ); + } + } + else + { + it.side = 'dst'; + for( let p = 0; p < o.filePath.length; p++ ) + { + it.index = p; + it.src = ''; + it.dst = o.filePath[ p ] === null ? '' : o.filePath[ p ]; + it.value = it.dst; + + let r = o.onEach( it.value, it ); + writeArrayResult( r, p, result ); + } + } + + } + else if( _.mapIs( o.filePath ) ) + { + for( let src in o.filePath ) + { + let dst = o.filePath[ src ]; + + if( o.dst === false ) + delete o.filePath[ src ]; + + if( _.arrayIs( dst ) ) + { + if( dst.length === 0 ) + { + it.src = src; + it.dst = ''; + it.value = it.src; + it.side = 'src'; + let srcResult = o.onEach( it.value, it ); + it.side = 'dst'; + it.value = it.dst; + let dstResult = o.onEach( it.value, it ); + write( result, srcResult, dstResult ); + } + else + { + dst = dst.slice(); + for( let d = 0; d < dst.length; d++ ) + { + it.src = src; + it.dst = dst[ d ] === null ? '' : dst[ d ]; + it.value = it.src; + it.side = 'src'; + let srcResult = o.onEach( it.value, it ); + it.value = it.dst; + it.side = 'dst'; + let dstResult = o.onEach( it.value, it ); + write( result, srcResult, dstResult ); + } + } + } + else + { + it.src = src; + it.dst = dst === null ? '' : dst; + it.value = it.src; + it.side = 'src'; + let srcResult = o.onEach( it.value, it ); + it.side = 'dst'; + it.value = it.dst; + let dstResult = o.onEach( it.value, it ); + write( result, srcResult, dstResult ); + } + + } + } + else _.assert( 0 ); + + if( o.dst === true ) + { + result = this.simplify_( null, result ); + } + else + { + if( _.mapIs( result ) && result[ '' ] === '' ) + delete result[ '' ]; + result = this.simplify_( result, result ); + } + + return result; + + /* */ + + function write( pathMap, src, dst ) + { + if( src === null || ( _.arrayIs( src ) && src.length === 0 ) ) + src = ''; + if( dst === null || ( _.arrayIs( dst ) && dst.length === 0 ) ) + dst = ''; + if( _.arrayIs( dst ) && dst.length === 1 ) + dst = dst[ 0 ]; + if( _.boolLike( dst ) ) + dst = !!dst; + + if( dst !== undefined ) + { + if( _.mapIs( pathMap ) ) + { + if( _.arrayIs( src ) ) + { + for( let s = 0 ; s < src.length ; s++ ) + if( src[ s ] !== undefined ) + pathMap[ src[ s ] ] = append( pathMap[ src[ s ] ], dst ); + } + else if( _.strIs( src ) ) + pathMap[ src ] = append( pathMap[ src ], dst ); + else if( src !== undefined ) + _.assert( 0 ); + } + else + { + if( _.arrayIs( src ) ) + { + for( let s = 0; s < src.length; s++ ) + _.arrayAppendArrays( pathMap, [ src[ s ], dst ] ); + } + else + { + if( src !== undefined ) + _.arrayAppendOnce( pathMap, src ); + if( dst !== undefined ) + _.arrayAppendOnce( pathMap, dst ); + + } + } + } + + function append( dst, src ) + { + if( src === '' ) + dst = src; + else if( _.boolLike( src ) ) + dst = src; + else + { + if( _.strIs( dst ) || _.arrayIs( dst ) ) + dst = _.scalarAppendOnce( dst, src ); + else + dst = src; + } + return dst; + } + } + + /* */ + + function writeArrayResult( r, i, result ) + { + if( r === undefined || r === null ) + { + r = ''; + } + else if( _.arrayIs( r ) ) + { + if( r.length === 0 ) + r = ''; + else if( r.length === 1 ) + r = r[ 0 ]; + } + + if( o.dst === false ) + result[ i ] = r; + else if( _.arrayIs( result ) ) + _.arrayAppendArraysOnce( result, r ); + else if( _.mapIs( result ) ) + result[ r ] = ''; + } + +} +filter_body.defaults = +{ + dst : null, + filePath : null, + onEach : null, + isSrc : true, +} + +// + +let filter_ = _.routine.uniteCloning_replaceByUnite( filter_head, filter_body ); +filter_.defaults = +{ + dst : null, + filePath : null, + onEach : null, + isSrc : true, +} + +// + +let filterSrc_ = _.routine.uniteCloning_replaceByUnite( filter_head, filter_body ); +filterSrc_.defaults = +{ + dst : null, + filePath : null, + onEach : null, + isSrc : true, +} + +// + +let filterDst_ = _.routine.uniteCloning_replaceByUnite( filter_head, filter_body ); +filterDst_.defaults = +{ + dst : null, + filePath : null, + onEach : null, + isSrc : false, +} + +// + +function all( filePath, onEach ) +{ + + _.assert( arguments.length === 2 ); + _.assert( filePath === null || _.strIs( filePath ) || _.arrayIs( filePath ) || _.mapIs( filePath ) ); + _.routineIs( onEach ); + + let it = Object.create( null ); + if( filePath === null || _.strIs( filePath ) ) + { + it.value = filePath; + let r = onEach( it.value, it ); + if( !r ) + return false; + return true; + } + else if( _.arrayIs( filePath ) ) + { + for( let p = 0 ; p < filePath.length ; p++ ) + { + it.index = p; + it.value = filePath[ p ]; + let r = onEach( it.value, it ); + if( !r ) + return false; + } + return true; + } + else if( _.mapIs( filePath ) ) + { + for( let src in filePath ) + { + let dst = filePath[ src ]; + var r; + if( _.arrayIs( dst ) ) + { + dst = dst.slice(); + for( let d = 0 ; d < dst.length ; d++ ) + { + it.src = src; + it.dst = dst[ d ]; + it.value = it.src; + it.side = 'src'; + r = onEach( it.value, it ); + if( !r ) + return false; + it.value = it.dst; + it.side = 'dst'; + r = onEach( it.value, it ); + if( !r ) + return false; + } + } + else + { + it.src = src; + it.dst = dst; + it.value = it.src; + it.side = 'src'; + r = onEach( it.value, it ); + if( !r ) + return false; + it.value = it.dst; + it.side = 'dst'; + r = onEach( it.value, it ); + if( !r ) + return false; + } + + } + return true; + } + else _.assert( 0 ); + +} + +// + +function any( filePath, onEach ) +{ + + _.assert( arguments.length === 2 ); + _.assert( filePath === null || _.strIs( filePath ) || _.arrayIs( filePath ) || _.mapIs( filePath ) ); + _.routineIs( onEach ); + + let it = Object.create( null ); + + if( filePath === null || _.strIs( filePath ) ) + { + it.value = filePath; + let r = onEach( it.value, it ); + if( r ) + return true; + return false; + } + else if( _.arrayIs( filePath ) ) + { + for( let p = 0 ; p < filePath.length ; p++ ) + { + it.index = p; + it.value = filePath[ p ]; + let r = onEach( it.value, it ); + if( r ) + return true; + } + return false; + } + else if( _.mapIs( filePath ) ) + { + for( let src in filePath ) + { + let dst = filePath[ src ]; + var r; + if( _.arrayIs( dst ) ) + { + dst = dst.slice(); + for( let d = 0 ; d < dst.length ; d++ ) + { + it.src = src; + it.dst = dst[ d ]; + it.value = it.src; + it.side = 'src'; + r = onEach( it.value, it ); + if( r ) + return true; + it.value = it.dst; + it.side = 'dst'; + r = onEach( it.value, it ); + if( r ) + return true; + } + } + else + { + it.src = src; + it.dst = dst; + it.value = it.src; + it.side = 'src'; + r = onEach( it.value, it ); + if( r ) + return true; + it.value = it.dst; + it.side = 'dst'; + r = onEach( it.value, it ); + if( r ) + return true; + } + + } + return false; + } + else _.assert( 0 ); + +} + +// + +function none( filePath, onEach ) +{ + return !this.any.apply( this, arguments ) +} + +// + +// function isEmpty( src ) +// { +// let self = this; +// +// _.assert( arguments.length === 1 ); +// +// if( src === null || src === '' ) +// { +// return true; +// } +// else if( _.strIs( src ) ) +// { +// return false; +// } +// else if( _.arrayIs( src ) ) +// { +// if( src.length === 0 ) +// return true; +// if( src.length === 1 ) +// if( src[ 0 ] === null || src[ 0 ] === '' ) +// return true; +// return false; +// } +// else if( _.mapIs( src ) ) +// { +// let keys = _.props.keys( src ); +// if( keys.length === 0 ) +// return true; +// if( keys.length === 1 ) +// if( src[ '' ] === null || src[ '' ] === '' ) +// return true; +// return false; +// } +// else +// _.assert( 0 ); +// } + +function isEmpty( src ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + _.assert( src === null || _.arrayIs( src ) || _.strIs( src ) || _.mapIs( src ) ); + + if( src === null || src === '' ) + return true; + + if( _.strIs( src ) ) + return false; + + if( _.arrayIs( src ) ) + { + if( src.length === 0 ) + return true; + if( src.length === 1 ) + if( src[ 0 ] === null || src[ 0 ] === '' || src[ 0 ] === '.' ) // qqq zzz : refactor to remove dot case | Dmytro : uncomment routine above, please + return true; + return false; + } + + if( _.props.keys( src ).length === 0 ) + return true; + if( _.props.keys( src ).length === 1 ) + if( src[ '.' ] === null || src[ '.' ] === '' || src[ '' ] === null || src[ '' ] === '' ) // qqq zzz : refactor to remove dot | Dmytro : uncomment routine above, please + return true; + + return false; +} + +// + +function _mapExtend( o ) +{ + let self = this; + let used = false; + + _.routine.optionsWithoutUndefined( _mapExtend, arguments ); + _.assert( o.dstPathMap === null || _.strIs( o.dstPathMap ) || _.arrayIs( o.dstPathMap ) || _.mapIs( o.dstPathMap ) ); + _.assert( !_.mapIs( o.dstPath ) ); + _.assert( _.longHas( [ 'replace', 'append', 'prepend' ], o.mode ) ); + + o.dstPath = dstPathNormalize( o.dstPath ); + o.srcPathMap = srcPathMapNormalize( o.srcPathMap ); + + if( o.supplementing ) + { + getDstPathFromSrcMap(); + getDstPathFromDstMap(); + } + else + { + getDstPathFromDstMap(); + getDstPathFromSrcMap(); + } + + [ o.dstPathMap, used ] = dstPathMapNormalize( o.dstPathMap ); + + if( o.srcPathMap !== '' ) + used = dstPathMapExtend( o.dstPathMap, o.srcPathMap, o.dstPath ) || used; + + if( used && o.dstPathMap[ '' ] === o.dstPath ) + { + delete o.dstPathMap[ '' ]; + } + + /* */ + + return o.dstPathMap; + + /* */ + + function dstPathNormalize( dstPath ) + { + dstPath = self.simplify( dstPath ); + return dstPath; + } + + /* */ + + function srcPathMapNormalize( srcPathMap ) + { + srcPathMap = self.simplify( srcPathMap ); + return srcPathMap; + } + + /* */ + + function getDstPathFromDstMap() + { + + if( o.dstPath === null || o.dstPath === '' ) + if( _.mapIs( o.dstPathMap ) ) + if( o.dstPathMap[ '' ] !== undefined && o.dstPathMap[ '' ] !== null && o.dstPathMap[ '' ] !== '' ) + if( o.srcPathMap !== '' ) + if( o.dstPath !== o.dstPathMap[ '' ] ) + { + o.dstPath = o.dstPathMap[ '' ]; + used = false; + } + + } + + /* */ + + function getDstPathFromSrcMap() + { + + if( o.dstPath === null || o.dstPath === '' ) + if( _.mapIs( o.srcPathMap ) ) + if( o.srcPathMap[ '' ] !== undefined && o.srcPathMap[ '' ] !== null && o.srcPathMap[ '' ] !== '' ) + if( o.dstPath !== o.srcPathMap[ '' ] ) + { + o.dstPath = o.srcPathMap[ '' ]; + used = false; + } + + } + + /* */ + + function dstPathMapNormalize( dstPathMap ) + { + let used = false; + + if( dstPathMap === null ) + { + dstPathMap = Object.create( null ); + } + else if( _.strIs( dstPathMap ) ) + { + let originalDstPath = dstPathMap; + dstPathMap = Object.create( null ); + if( originalDstPath !== '' || ( o.dstPath !== null && o.dstPath !== '' ) ) + { + dstPathMap[ originalDstPath ] = o.dstPath; + if( originalDstPath !== '' ) + used = true; + } + } + else if( _.arrayIs( dstPathMap ) ) + { + let originalDstPath = dstPathMap; + dstPathMap = Object.create( null ); + originalDstPath.forEach( ( p ) => + { + dstPathMap[ p ] = o.dstPath; + used = true; + }); + } + else if( _.mapIs( dstPathMap ) ) + { + for( let f in dstPathMap ) + { + let val = dstPathMap[ f ]; + if( ( val === null || val === '' ) && !_.boolLike( o.dstPath ) ) + { + dstPathMap[ f ] = o.dstPath; + used = true; + } + else + if( _.boolLike( val ) ) + { + dstPathMap[ f ] = !!val; + } + } + + } + + /* get dstPath from dstPathMap if it has empty key */ + + if( dstPathMap[ '' ] === '' || dstPathMap[ '' ] === null ) + { + delete dstPathMap[ '' ]; + } + + _.assert( _.mapIs( dstPathMap ) ); + return [ dstPathMap, used ]; + } + + /* */ + + function dstPathMapRemove( dstPathMap, dstPath ) + { + if( dstPath !== '' && _.props.keys( dstPathMap ).length === 0 ) + { + dstPathMap[ '' ] = dstPath; + } + else for( let src in dstPathMap ) + { + dstPathMap[ src ] = dstPath; + if( src === '' && dstPath === '' ) + delete dstPathMap[ '' ]; + } + } + + /* */ + + function dstPathMapExtend( dstPathMap, srcPathMap, dstPath ) + { + let used = false; + + if( _.strIs( srcPathMap ) ) + { + let dst; + srcPathMap = self.normalize( srcPathMap ); + [ dst, used ] = dstJoin( dstPathMap[ srcPathMap ], dstPath, srcPathMap ); + if( srcPathMap !== '' || dst !== '' ) + dstPathMap[ srcPathMap ] = dst; + } + else if( _.mapIs( srcPathMap ) ) + { + for( let g in srcPathMap ) + { + let dstPath2 = srcPathMap[ g ]; + let tryingToUse = false; + + dstPath2 = dstPathNormalize( dstPath2 ); + + if( ( dstPath2 === null ) || ( dstPath2 === '' ) ) + { + dstPath2 = dstPath; + tryingToUse = true; + } + + if( tryingToUse ) + used = dstPathMapExtend( dstPathMap, g, dstPath2 ) || used; + else + dstPathMapExtend( dstPathMap, g, dstPath2 ); + } + } + else if( _.argumentsArray.like( srcPathMap ) ) + { + for( let g = 0 ; g < srcPathMap.length ; g++ ) + { + let srcPathMap2 = srcPathMap[ g ]; + srcPathMap2 = srcPathMapNormalize( srcPathMap2 ); + used = dstPathMapExtend( dstPathMap, srcPathMap2, dstPath ) || used; + } + } + else _.assert( 0, () => 'Expects srcPathMap, got ' + _.entity.strType( srcPathMap ) ); + + return used; + } + + /* */ + + function dstJoin( dst, src, key ) + { + let used = false; + let r; + + if( _.boolLike( src ) ) + src = !!src; + + _.assert + ( + dst === undefined + || dst === null + || _.arrayIs( dst ) + || _.strIs( dst ) + || _.boolIs( dst ) + || _.object.isBasic( dst ) + ); + _.assert + ( + src === null + || _.arrayIs( src ) + || _.strIs( src ) + || _.boolIs( src ) + || _.object.isBasic( src ) + ); + + if( o.mode === 'replace' ) + { + if( o.supplementing ) + { + r = dst; + if( dst === undefined || dst === null || dst === '' ) + { + r = src; + if( key !== '' ) + used = true; + } + } + else + { + if( key !== '' ) + used = true; + r = src; + } + } + else + { + r = dst; + + if( dst === undefined || dst === null || dst === '' ) + { + r = src; + if( key !== '' ) + used = true; + } + else if( src === null || src === '' || _.boolLike( src ) || _.boolLike( dst ) ) + { + if( o.supplementing && ( src === null || src === '' || _.boolLike( src ) ) ) + { + r = dst; + } + else + { + r = src; + if( key !== '' ) + used = true; + } + } + // { + // if( o.supplementing ) + // { + // r = dst; + // } + // else + // { + // r = src; + // if( key !== '' ) + // used = true; + // } + // } + else + { + if( key !== '' ) + used = true; + if( o.mode === 'append' ) + r = _.scalarAppendOnce( dst, src ); + else + r = _.scalarPrependOnce( dst, src ); + } + + } + + r = self.simplifyInplace( r ); + + return [ r, used ]; + } + +} + +_mapExtend.defaults = +{ + dstPathMap : null, + srcPathMap : null, + dstPath : null, + mode : 'replace', + supplementing : 0, +} + +// + +function mapExtend( dstPathMap, srcPathMap, dstPath ) +{ + let self = this; + _.cinterval.assertIn( arguments, [ 1, 3 ] ); + return self._mapExtend + ({ + dstPathMap, + srcPathMap, + dstPath, + mode : 'replace', + supplementing : 0, + }); +} + +// + +function mapSupplement( dstPathMap, srcPathMap, dstPath ) +{ + let self = this; + _.cinterval.assertIn( arguments, [ 1, 3 ] ); + return self._mapExtend + ({ + dstPathMap, + srcPathMap, + dstPath, + mode : 'replace', + supplementing : 1, + }); +} + +// + +function mapAppend( dstPathMap, srcPathMap, dstPath ) +{ + let self = this; + _.cinterval.assertIn( arguments, [ 1, 3 ] ); + return self._mapExtend + ({ + dstPathMap, + srcPathMap, + dstPath, + mode : 'append', + supplementing : 1, + }); +} + +// + +function mapPrepend( dstPathMap, srcPathMap, dstPath ) +{ + let self = this; + _.assert( arguments.length === 2 || arguments.length === 3 ); + return self._mapExtend + ({ + dstPathMap, + srcPathMap, + dstPath, + mode : 'prepend', + supplementing : 1, + }); +} + +// + +function mapsPair( dstFilePath, srcFilePath ) +{ + let self = this; + // let srcPath1; + // let srcPath2; + // let dstPath1; + // let dstPath2; + + _.assert( srcFilePath !== undefined ); + _.assert( dstFilePath !== undefined ); + _.assert( arguments.length === 2 ); + + if( srcFilePath && dstFilePath ) + { + + // srcPath1 = self.mapSrcFromSrc( srcFilePath ); + // srcPath2 = self.mapSrcFromDst( dstFilePath ); + // dstPath1 = self.mapDstFromSrc( srcFilePath ); + // dstPath2 = self.mapDstFromDst( dstFilePath ); + + // srcPath1 = self.mapSrcFromSrc( srcFilePath ).filter( ( e ) => e !== null ); + // srcPath2 = self.mapSrcFromDst( dstFilePath ).filter( ( e ) => e !== null ); + // dstPath1 = self.mapDstFromSrc( srcFilePath ).filter( ( e ) => e !== null ); + // dstPath2 = self.mapDstFromDst( dstFilePath ).filter( ( e ) => e !== null ); + + if( _.mapIs( srcFilePath ) && _.mapIs( dstFilePath ) ) + { + mapsVerify(); + } + else + { + srcVerify(); + // dstVerify(); + } + + if( _.mapIs( dstFilePath ) ) + { + dstFilePath = self.mapExtend( null, dstFilePath, null ); + srcFilePath = dstFilePath = self.mapSupplement( dstFilePath, srcFilePath, null ); + } + else + { + srcFilePath = dstFilePath = self.mapExtend( null, srcFilePath, dstFilePath ); + } + + } + else if( srcFilePath ) + { + if( self.isEmpty( srcFilePath ) ) + srcFilePath = dstFilePath = null; + else + srcFilePath = dstFilePath = self.mapExtend( null, srcFilePath, null ); + } + else if( dstFilePath ) + { + if( self.isEmpty( dstFilePath ) ) + srcFilePath = dstFilePath = null; + else if( _.mapIs( dstFilePath ) ) + srcFilePath = dstFilePath = self.mapExtend( null, dstFilePath, null ); + else + srcFilePath = dstFilePath = self.mapExtend( null, { '' : dstFilePath }, dstFilePath ); // yyy + } + else + { + srcFilePath = dstFilePath = null; + } + + return srcFilePath; + + /* */ + + function mapsVerify() + { + _.assert + ( + _.map.identical( srcFilePath, dstFilePath ), + () => 'File maps are inconsistent\n' + _.entity.exportString( srcFilePath ) + '\n' + _.entity.exportString( dstFilePath ) + ); + } + + /* */ + + function srcVerify() + { + if( dstFilePath && srcFilePath && Config.debug ) + { + let srcPath1 = self.mapSrcFromSrc( srcFilePath ).filter( ( e ) => e !== null ); + let srcPath2 = self.mapSrcFromDst( dstFilePath ).filter( ( e ) => e !== null ); + let srcFilteredPath1 = srcPath1.filter( ( e ) => !_.boolLike( e ) && e !== null ); + let srcFilteredPath2 = srcPath2.filter( ( e ) => !_.boolLike( e ) && e !== null ); + _.assert + ( + srcFilteredPath1.length === 0 || srcFilteredPath2.length === 0 + || self.isEmpty( srcFilteredPath1 ) || self.isEmpty( srcFilteredPath2 ) + || _.arraySetIdentical( srcFilteredPath1, srcFilteredPath2 ), + () => 'Source paths are inconsistent ' + _.entity.exportString( srcFilteredPath1 ) + ' ' + _.entity.exportString( srcFilteredPath2 ) + ); + } + } + +} + +// + +function simplify( src ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + + if( src === null ) + return ''; + + if( _.strIs( src ) ) + return src; + + if( _.boolLike( src ) ) + return !!src; + + if( _.arrayIs( src ) ) + { + let src2 = _.arrayAppendArrayOnce( null, src ); + src2 = src2.filter( ( e ) => e !== null && e !== '' ); + if( src2.length !== src.length ) + src = src2; + if( src.length === 0 ) + return ''; + else if( src.length === 1 ) + return src[ 0 ] + else + return src; + } + + if( !_.mapIs( src ) ) + return src; + + for( let k in src ) + { + src[ k ] = self.simplify( src[ k ] ); + } + + let keys = _.props.keys( src ); + if( keys.length === 0 ) + return ''; + if( keys.length !== 1 && keys.includes( '' ) && src[ '' ] === '' ) + delete src[ '' ]; + + let vals = _.props.vals( src ); + vals = vals.filter( ( e ) => e !== null && e !== '' ); + if( vals.length === 0 ) + { + if( keys.length === 1 && keys[ 0 ] === '' ) + return ''; + else if( keys.length === 1 ) + return keys[ 0 ] + else + return src; + } + + return src; +} + +// + +function simplifyDst( src ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + + if( src === null ) + return ''; + + if( _.strIs( src ) ) + return src; + + if( _.boolLike( src ) ) + return !!src; + + if( _.arrayIs( src ) ) + { + let src2 = _.arrayAppendArrayOnce( null, src ); + src2 = src2.filter( ( e ) => e !== null && e !== '' ); + if( src2.length !== src.length ) + src = src2; + if( src.length === 0 ) + return ''; + else if( src.length === 1 ) + return src[ 0 ] + else + return src; + } + + if( !_.mapIs( src ) ) + return src; + + for( let k in src ) + { + src[ k ] = self.simplifyDst( src[ k ] ); + } + + let keys = _.props.keys( src ); + if( keys.length === 0 ) + return ''; + + if( keys.length === 1 && src[ '' ] !== undefined ) + src = src[ '' ]; + + return src; +} + +// + +function simplifyInplace( src ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + + if( src === null ) + return ''; + + if( _.boolLike( src ) ) + return !!src; + + if( _.strIs( src ) ) + return src; + + if( _.arrayIs( src ) ) + { + src = _.arrayRemoveDuplicates( src, ( e ) => e ); + src = _.arrayRemoveElement( src, '', ( e ) => e === null || e === '' ); + return src; + } + + if( !_.mapIs( src ) ) + return src; + + for( let k in src ) + { + src[ k ] = self.simplifyInplace( src[ k ] ); + } + + return src; +} + +// + +function simplify_( dst, src ) +{ + let self = this; + let result; + + if( arguments.length === 1 ) + { + src = dst; + dst = true; + } + else + _.assert( arguments.length === 2 ); + + if( dst === null ) + dst = true; + else if( dst === src ) + dst = false; + + if( src === null ) + { + result = ''; + } + else if( _.strIs( src ) ) + { + result = src; + } + else if( _.boolLike( src ) ) + { + result = !!src; + } + else if( _.arrayIs( src ) ) + { + if( dst === false ) + { + result = _.arrayRemoveDuplicates( src, ( e ) => e ); + result = _.arrayRemoveElement( result, '', ( e ) => e === null || e === '' ); + return result; + } + else + { + result = _.arrayAppendArrayOnce( null, src ); + result = result.filter( ( e ) => e !== null && e !== '' ); + if( result.length === 0 ) + result = ''; + else if( result.length === 1 ) + result = result[ 0 ]; + } + } + else if( _.mapIs( src ) ) + { + if( dst === false ) + { + for( let k in src ) + src[ k ] = self.simplify( src[ k ] ); + result = src; + } + else + { + result = Object.create( null ); + + for( let k in src ) + result[ k ] = self.simplify( src[ k ] ); + + let keys = _.props.keys( result ); + if( keys.length > 0 ) + { + if( keys.length !== 1 && keys.includes( '' ) && result[ '' ] === '' ) + delete result[ '' ]; + + let vals = _.props.vals( result ); + vals = vals.filter( ( e ) => e !== null && e !== '' ); + if( vals.length === 0 ) + { + if( keys.length === 1 && keys[ 0 ] === '' ) + result = ''; + else if( keys.length === 1 ) + result = keys[ 0 ]; + } + } + else + result = ''; + } + } + else + { + result = src; + } + + fillDst(); + + return result; + + /* */ + + function fillDst() + { + if( !_.boolIs( dst ) ) + { + if( _.arrayIs( dst ) ) + { + if( _.arrayIs( result ) ) + _.arrayAppendArrayOnce( dst, result ); + else if( _.mapIs( result ) ) + _.arrayAppendArrayOnce( dst, _.props.keys( result ) ); + else if( result !== '' ) + _.arrayAppendOnce( dst, result ); + } + else if( _.mapIs( dst ) ) + { + if( _.mapIs( result ) ) + { + for( let k in result ) + dst[ k ] = result[ k ]; + } + else if( _.arrayIs( result ) ) + { + for( let i in result ) + dst[ result[ i ] ] = ''; + } + else + dst[ result ] = ''; + } + else + dst = result; + + result = self.simplify_( dst, dst ); + } + } + +} + +// + +function mapDstFromSrc( pathMap ) +{ + _.assert( arguments.length === 1 ); + + if( !_.mapIs( pathMap ) ) + { + if( pathMap === null ) + return []; + else + return [ null ]; + } + + let result = []; + + for( let k in pathMap ) + { + if( _.arrayIs( pathMap[ k ] ) ) + _.arrayAppendArrayOnce( result, pathMap[ k ] ); + else + _.arrayAppendOnce( result, pathMap[ k ] ); + } + + return result; +} + +// + +function mapDstFromDst( pathMap ) +{ + _.assert( arguments.length === 1 ); + + if( !_.mapIs( pathMap ) ) + { + if( pathMap === null ) + return []; + else + return _.array.asShallow( pathMap ); + } + + let result = []; + + for( let k in pathMap ) + { + if( _.arrayIs( pathMap[ k ] ) ) + _.arrayAppendArrayOnce( result, pathMap[ k ] ); + else + _.arrayAppendOnce( result, pathMap[ k ] ); + } + + return result; +} + +// + +function mapSrcFromSrc( pathMap ) +{ + _.assert( arguments.length === 1 ); + + if( !_.mapIs( pathMap ) ) + { + if( pathMap === null ) + return []; + else + return _.array.asShallow( pathMap ); + } + + let result = []; + + for( let k in pathMap ) + if( k !== '' || ( pathMap[ k ] !== '' && pathMap[ k ] !== null ) ) + result.push( k ); + + return result; +} + +// + +function mapSrcFromDst( pathMap ) +{ + _.assert( arguments.length === 1 ); + + if( !_.mapIs( pathMap ) ) + { + if( pathMap === null ) + return []; + else + return [ null ]; + } + + let result = []; + + for( let k in pathMap ) + result.push( k ); + + return result; +} + +// -- +// etc +// -- + +function traceToRoot( filePath ) +{ + let self = this; + let result = []; + + filePath = self.normalize( filePath ); + // filePath = self.detrail( filePath ); // Dmytro : cycled loop if path is absolute and has form '/..' + // filePath = self.canonize( filePath ); + + _.assert( arguments.length === 1 ); + _.assert( self.isAbsolute( filePath ) ); + + /* + should preserve trailing of the longest path + /a/b/ -> [ '/', '/a', '/a/b/' ] + */ + + // if( self.isAbsolute( filePath ) ) + // { + result.push( filePath ); + filePath = self.detrail( filePath ); + while( filePath !== self.rootToken ) + { + _.assert + ( + filePath !== self.rootToken + self.downToken + && !_.strBegins( filePath, self.rootToken + self.downToken + self.upToken ) + ); + filePath = self.dir( filePath ); + result.push( filePath ); + // filePath = self.detrail( dir ); /* qqq : not optimal! | aaa : Moved outside of the loop. */ + } + // } + // else + // { + // filePath = self.undot( filePath ); + // if( !self.isDotted( filePath ) ) + // do + // { + // result.unshift( filePath ); + // filePath = self.detrail( self.dir( filePath ) ); /* qqq : not optimal! */ + // } + // while( !self.isDotted( filePath ) ); + // } + + // result.push( filePath ); + + return result.reverse(); +} + +// + +function group( o ) +{ + let self = this; + + _.routine.options_( group, arguments ); + _.assert( _.arrayIs( o.vals ) ); + _.assert( o.result === null || _.mapIs( o.result ) ); + + o.result = o.result || Object.create( null ); + o.result[ '/' ] = o.result[ '/' ] || []; + + let vals = _.arrayFlattenOnce( null, o.vals ); + let keys = o.keys; + + keys = self.s.from( keys ); + vals = self.s.from( vals ); + + keys = self.mapSrcFromSrc( keys ); + + _.assert( _.arrayIs( keys ) ); + _.assert( _.arrayIs( vals ) ); + + // if( o.vals && o.vals.length ) + + /* */ + + for( let k = 0 ; k < keys.length ; k++ ) + { + let key = keys[ k ]; + let res = o.result[ key ] = o.result[ key ] || []; + } + + /* */ + + for( let key in o.result ) + { + let res = o.result[ key ]; + for( let v = 0 ; v < vals.length ; v++ ) + { + let val = vals[ v ]; + if( self.begins( val, key ) ) + _.sorted.addOnce( res, val, ( a, b ) => + { + a = a.toLowerCase(); + b = b.toLowerCase(); + if( a === b ) + return 0; + if( a < b ) + return -1; + return +1; + }); + // _.arrayAppendOnce( res, val ); + } + + } + + /* */ + + // if( o.vals && o.vals.length ) + + return o.result; +} + +group.defaults = +{ + keys : null, + vals : null, + result : null, +} + +// + +function mapGroupByDst( pathMap ) +{ + let path = this; + let result = Object.create( null ); + + _.assert( arguments.length === 1 ); + _.assert( _.mapIs( pathMap ) ); + + /* */ + + for( let src in pathMap ) + { + let normalizedSrc = path.fromGlob( src ); + let dst = pathMap[ src ]; + + if( _.boolLike( dst ) ) + continue; + + if( _.strIs( dst ) ) + { + extend( dst, src ); + } + else + { + _.assert( _.arrayIs( dst ) ); + for( var d = 0 ; d < dst.length ; d++ ) + extend( dst[ d ], src ); + } + + } + + /* */ + + for( let src in pathMap ) + { + let dst = pathMap[ src ]; + + if( !_.boolLike( dst ) ) + continue; + + for( var dst2 in result ) + { + + for( var src2 in result[ dst2 ] ) + { + if( path.isRelative( src ) ^ path.isRelative( src2 ) ) + { + result[ dst2 ][ src ] = !!dst; + } + else + { + let srcBase = path.fromGlob( src ); + let srcBase2 = path.fromGlob( src2 ); + if( path.begins( srcBase, srcBase2 ) || path.begins( srcBase2, srcBase ) ) + result[ dst2 ][ src ] = !!dst; + } + } + + } + + } + + /* */ + + return result; + + /* */ + + function extend( dst, src ) + { + dst = path.normalize( dst ); + result[ dst ] = result[ dst ] || Object.create( null ); + result[ dst ][ src ] = ''; + } + +} + +// + +function mapOptimize( filePath, basePath ) +{ + let self = this; + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( basePath === undefined || _.mapIs( basePath ) ); + _.assert( self.isElement( filePath ) ); + + if( !_.mapIs( filePath ) ) + filePath = self.mapExtend( null, filePath ); + + let include = []; + let exclude = []; + let trunk = []; + + for( let src in filePath ) + { + let dst = filePath[ src ]; + if( !_.boolLike( dst ) ) + trunk.push( src ); + else if( dst ) + include.push( src ); + else + exclude.push( src ); + } + + optimize( include ); + optimize( exclude ); + optimize( trunk ); + + return filePath; + + /* */ + + function optimize( array ) + { + array.sort(); + for( let i1 = 0 ; i1 < array.length ; i1++ ) + { + let path1 = array[ i1 ]; + for( let i2 = i1+1 ; i2 < array.length ; i2++ ) + { + let path2 = array[ i2 ]; + + if( !self.begins( path2, path1 ) ) + break; + + if( filePath[ path1 ] !== filePath[ path2 ] ) + continue; + + if( basePath ) + { + if( basePath[ path1 ] === basePath[ path2 ] ) + delete basePath[ path2 ]; + else + continue; + } + + array.splice( i2, 1 ); + delete filePath[ path2 ]; + i2 -= 1; + } + } + } + +} + +// + +function identical( src1, src2 ) +{ + /* qqq : write performance test and optimize it */ + + if( _.mapIs( src1 ) ) + return mapIdentical( src1, src2 ); + else if( _.arrayIs( src1 ) ) + return _.long.identical( src1, src2 ); + else + return src1 === src2; + + function mapIdentical( src1, src2 ) + { + if( !_.mapIs( src2 ) ) + return false; + let keys1 = Object.keys( src1 ); + let keys2 = Object.keys( src2 ); + if( keys1.length !== keys2.length ) + return false; + for( let i = 0, l = keys1.length ; i < l ; i++ ) + { + let k = keys1[ i ]; + if( _.arrayIs( src1[ k ] ) ) + { + if( !_.long.identical( src1[ k ], src2[ k ] ) ) + return false; + } + else + { + if( src1[ k ] !== src2[ k ] ) + return false + } + } + return true; + } + +} + +// -- +// implementation +// -- + +let PathExtension = +{ + + // path map + + _filterPairs, /* !!! */ + filterPairs, /* !!! */ + filterSrcPairs, /* !!! */ + filterDstPairs, /* !!! */ + + _filterPairsInplace, /* !!! */ + filterPairsInplace, /* !!! */ + filterSrcPairsInplace, /* !!! */ + filterDstPairsInplace, /* !!! */ + + _filterInplace, /* !!! */ + filterInplace, /* !!! */ + filterSrcInplace, /* !!! */ + filterDstInplace, /* !!! */ + + _filter, /* !!! */ + filter, /* !!! */ + filterSrc, /* !!! */ + filterDst, /* !!! */ + + all, /* !!! */ + any, /* !!! */ + none, /* !!! */ + + isEmpty, /* !!! */ + _mapExtend, /* !!! */ + mapExtend, /* !!! */ + mapSupplement, /* !!! */ + mapAppend, /* !!! */ + mapPrepend, /* !!! */ + mapsPair, /* !!! */ + + simplify, /* !!! */ + simplifyDst, /* !!! */ + simplifyInplace, /* !!! */ + + mapDstFromSrc, /* !!! */ + mapDstFromDst, /* !!! */ + mapSrcFromSrc, /* !!! */ + mapSrcFromDst, /* !!! */ + + // etc + + traceToRoot, + group, + mapGroupByDst, /* !!! */ + mapOptimize, /* !!! */ + + // to replace + + /* xxx : replace */ + filterPairs_, /* !!! : use instead of filterPairs, filterPairsInplace */ + filterSrcPairs_, /* !!! : use instead of filterSrcPairs, filterSrcPairsInplace */ + filterDstPairs_, /* !!! : use instead of filterDstPairs, filterDstPairsInplace */ + filter_, /* !!! : use instead of filter, filterInplace */ + filterSrc_, /* !!! : use instead of filterSrc, filterSrcInplace */ + filterDst_, /* !!! : use instead of filterDst, filterDstInplace */ + simplify_, /* !!! : use instead of simplify, simplifyInplace */ + + /* + | routine | makes new dst container | saves dst container | + | ----------------| -------------------------------------------------| ----------------------------------------------------| + | filterPairs_ | _.path.filterPairs_( null, filePath, onEach ) | _.path.filterPairs_( filePath, onEach ) | + | | | _.path.filterPairs_( filePath, filePath, onEach ) | + | | | _.path.filterPairs_( dst, filePath, onEach ) | + | | | dst should be array or map | + | ----------------| -------------------------------------------------| ----------------------------------------------------| + | filterSrcPairs_ | _.path.filterSrcPairs_( null, filePath, onEach ) | _.path.filterSrcPairs_( filePath, onEach ) | + | | | _.path.filterSrcPairs_( filePath, filePath, onEach )| + | | | _.path.filterSrcPairs_( dst, filePath, onEach ) | + | | | dst should be array or map | + | ----------------| -------------------------------------------------| ----------------------------------------------------| + | filterDstPairs_ | _.path.filterDstPairs_( null, filePath, onEach ) | _.path.filterDstPairs_( filePath, onEach ) | + | | | _.path.filterDstPairs_( filePath, filePath, onEach )| + | | | _.path.filterDstPairs_( dst, filePath, onEach ) | + | | | dst should be array or map | + | ----------------| -------------------------------------------------| ----------------------------------------------------| + | filter_ | _.path.filter_( null, filePath, onEach ) | _.path.filter_( filePath, onEach ) | + | | | _.path.filter_( filePath, filePath, onEach ) | + | | | _.path.filter_( dst, filePath, onEach ) | + | | | dst should be array or map | + | --------------- | -------------------------------------------------| ----------------------------------------------------| + | filterSrc_ | _.path.filterSrc_( null, filePath, onEach ) | _.path.filterSrc_( filePath, onEach ) | + | | | _.path.filterSrc_( filePath, filePath, onEach ) | + | | | _.path.filterSrc_( dst, filePath, onEach ) | + | | | dst should be array or map | + | --------------- | -------------------------------------------------| ----------------------------------------------------| + | filterDst_ | _.path.filterDst_( null, filePath, onEach ) | _.path.filterDst_( filePath, onEach ) | + | | | _.path.filterDst_( filePath, filePath, onEach ) | + | | | _.path.filterDst_( dst, filePath, onEach ) | + | | | dst should be array or map | + | --------------- | -------------------------------------------------| ----------------------------------------------------| + | simplify_ | _.path.simplify_( filePath ) | _.path.simplify_( filePath, filePath ) | + | | _.path.simplify_( null, filePath ) | _.path.simplify_( dst, filePath ) | + | | _.path.simplify_( dst, filePath ) | | + | | if dst is not resizable | | + */ + +} + +let PathMapExtension = +{ + /* qqq : duplicate relevant routines here | aaa : Done. Yevhen S. */ + + _filterPairs, + filterPairs, + filterSrcPairs, + filterDstPairs, + + _filterPairsInplace, + filterPairsInplace, + filterSrcPairsInplace, + filterDstPairsInplace, + + _filterInplace, + filterInplace, + filterSrcInplace, + filterDstInplace, + + _filter, + filter, + filterSrc, + filterDst, + + all, + any, + none, + + isEmpty, + _extend : _mapExtend, + extend : mapExtend, + supplement : mapSupplement, + append : mapAppend, + prepend : mapPrepend, + pair : mapsPair, + + simplify, + simplifyDst, + simplifyInplace, + + dstFromSrc : mapDstFromSrc, + dstFromDst : mapDstFromDst, + srcFromSrc : mapSrcFromSrc, + srcFromDst : mapSrcFromDst, + + groupByDst : mapGroupByDst, + optimize : mapOptimize, + + identical, /* qqq : implement very optimal version */ + + + /* qqq : implement equivalent */ + +} + +_.props.supplement( _.path, PathExtension ); +_.props.supplement( _.path.map, PathMapExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +{ + module[ 'exports' ] = _; + require( './Glob.s' ); +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathtools/proto/wtools/abase/l5/PathTools.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wpathtools/proto/wtools/abase/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, PathTools_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file PathTools_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocedure/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocedure/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wprocedure */ ( function wprocedure() { function wprocedure_naked() { +module.exports = require( '../wtools/abase/l8_procedure/Include.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wProcedure', 'wprocedure' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocedure/proto/node_modules/wprocedure' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocedure/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wprocedure_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wprocedure */ })(); + +/* */ /* begin of file Include_s */ ( function Include_s() { function Include_s_naked() { ( function _Include_s_() +{ + +'use strict'; + +/** + * Minimal programming interface to launch, stop and track collection of asynchronous procedures. It prevents an application from termination waiting for the last procedure and helps to diagnose your system with many interdependent procedures. + @module Tools/base/Procedure +*/ + +/** + *@summary Collection of cross-platform routines to launch, stop and track collection of asynchronous procedures. + @namespace wTools.procedure + @module Tools/base/Procedure +*/ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + + _.include( 'wProto' ); + _.include( 'wCopyable' ); + + require( './Namespace.s' ); + require( './Procedure.s' ); + +} + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _global_.wTools.procedure; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocedure/proto/wtools/abase/l8_procedure/Include.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocedure/proto/wtools/abase/l8_procedure' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Include_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Include_s */ })(); + +/* */ /* begin of file Namespace_s */ ( function Namespace_s() { function Namespace_s_naked() { ( function _Namespace_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global.wTools; + +_.assert( !!_global.wTools, 'Does not have wTools' ); +_.assert( _global.wTools.procedure === undefined, 'wTools.procedure is already defined' ); +_.assert( _global.wTools.Procedure === undefined, 'wTools.Procedure is already defined' ); + +_.procedure = _.procedure || Object.create( null ); + +// _realGlobal_._ProcedureGlobals_ = _realGlobal_._ProcedureGlobals_ || []; +// _.arrayAppendOnce( _realGlobal_._ProcedureGlobals_, _global ); + +// -- +// event +// -- + +function on( o ) +{ + o = _.event.onHead( _.event.on, arguments ); + return _.event.on( _.procedure._edispatcher, o ); +} + +on.defaults = +{ + callbackMap : null, +} + +// + +function off( o ) +{ + + o = _.event.offHead( _.event.off, arguments ); + _.event.off( _.procedure._edispatcher, o ); + +} + +off.defaults = +{ + callbackMap : null, +} + +// + +function _eventTerminationBeginHandle() +{ + + _.procedure._edispatcher.events.terminationBegin.forEach( ( callback ) => + { + try + { + callback.call( _.procedure ); + } + catch( err ) + { + logger.error( _.errOnce( 'Error in callback of event "terminationBegin"\n', err ) ); + } + }); + +} + +// + +function _eventTerminationEndHandle() +{ + + _.procedure._edispatcher.events.terminationEnd.forEach( ( callback ) => + { + try + { + /* namespace should be in the context */ + callback.call( _.procedure ); + } + catch( err ) + { + logger.error( _.errOnce( 'Error in callback of event "terminationEnd"\n', err ) ); + } + }); + +} + +// + +function _eventProcessExitHandle() +{ + _.Procedure._Exiting = 1; + _.procedure.terminationBegin(); +} + +// -- +// termination +// -- + +/** + * @summary Prints report with number of procedures that are still working. + * @routine terminationReport + * @module Tools/base/Procedure + * @namespace Tools.procedure + */ + +function terminationReport() +{ + + let procedures = _.Procedure.Find({ _quasi : 0 }); + if( _.procedure._terminationListInvalidated ) + logger.log( _.Procedure.ExportInfo( procedures ) ); + + _.procedure._terminationListInvalidated = 0; + logger.log( `Waiting for ${procedures.length} procedure(s) ...` ); +} + +// + +/** + * @summary Starts procedure of termination. + * @routine terminationBegin + * @module Tools/base/Procedure + * @namespace Tools.procedure + */ + +function terminationBegin() +{ + + _.assert( this === _.procedure ); + + if( _.Procedure._Terminating ) + return; + + _.routine.options_( terminationBegin, arguments ); + _.Procedure._Terminating = 1; + _.procedure._terminationListInvalidated = 1; + + _.procedure._eventTerminationBeginHandle(); + _.procedure._terminationRestart(); + + _.each( _realGlobal_._globals_, ( global ) => + { + if( global.wTools && global.wTools.procedure && global.wTools.procedure.terminationBegin ) + global.wTools.procedure.terminationBegin(); + }); + +} + +terminationBegin.defaults = +{ +} + +// + +function _terminationIteration() +{ + _.assert( arguments.length === 1 ); + _.assert( _.Procedure._Terminating === 1 ); + + _.procedure._terminationTimer = null; + _.procedure.terminationReport(); + + _.procedure._terminationRestart(); + +} + +// + +function _terminationRestart() +{ + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( _.Procedure._Terminating >= 1 ); + + if( _.Procedure._Terminating === 2 ) + { + return; + } + + if( _.procedure._terminationTimer ) + _.time._cancel( _.procedure._terminationTimer ); + _.procedure._terminationTimer = null; + + let procedures = _.Procedure.Find({ _quasi : 0 }); + + if( procedures.length && !_.Procedure._Exiting ) + { + _.procedure._terminationTimer = _.time._begin( _.procedure.terminationPeriod, _.procedure._terminationIteration ); + } + else + { + _.procedure._terminationEnd(); + } + +} + +// + +function _terminationEnd() +{ + + try + { + + // console.log( '_terminationEnd' ); debugger; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( _.Procedure._Terminating === 1 ); + _.assert( _.procedure._terminationTimer === null ); + + _.Procedure._Terminating = 2; + + if( !_.Procedure._Exiting || _.Procedure.EntryProcedure === _.Procedure.ActiveProcedure ) + if( _.Procedure.EntryProcedure && _.Procedure.EntryProcedure.isAlive() ) + { + _.Procedure.EntryProcedure.activate( 0 ); + _.Procedure.EntryProcedure.end(); + } + + /* end all timers */ + + _.procedure._timersEnd(); + + /* end all timers */ + + _.procedure._eventTerminationEndHandle(); + + } + catch( err ) + { + _.error._handleUncaught2({ err, origination : 'uncaught error in procedures termination routine' }) + } + +} + +// + +function _timersEnd() +{ + + for( let p in _.Procedure.NamesMap ) + { + let procedure = _.Procedure.NamesMap[ p ]; + if( !_.timerIs( procedure._object ) ) + { + continue; + } + _.time.cancel( procedure._object ); + } + +} + +// -- +// time +// -- + +function _timeBegin( o ) +{ + + if( o.onTime === undefined ) + o.onTime = null; + if( o.onCancel === undefined ) + o.onCancel = o.onTime; + + _.routine.assertOptions( _timeBegin, arguments ); + + if( o.procedure === undefined || o.procedure === null ) + o.procedure = 0; + if( _.numberIs( o.procedure ) ) + { + _.assert( _.intIs( o.procedure ) ); + o.procedure += 1; + } + o.procedure = _.Procedure( o.procedure ); + o.procedure.nameElse( 'time.begin' ); + if( o.onTime !== null ) + o.procedure.routineElse( o.onTime ); + + let wasAlive = o.procedure.isAlive(); + if( !wasAlive ) + { + _.assert( o.procedure._waitTimer === null ); + o.procedure._waitTimer = false; + o.procedure.begin(); + } + let timer; + + // if( o.method.name === '_periodic' ) + // debugger; + timer = o.method.call( _.time, o.delay, o.onTime, o.onCancel ); + timer.procedure = o.procedure; + o.procedure.object( timer ); + + let _time = timer._time; + let _cancel = timer._cancel; + timer._time = o.method.name === '_periodic' ? timePeriodic : time; + timer._cancel = cancel; + + return timer; + + /* */ + + function time() + { + + if( !o.procedure.use() ) + o.procedure.activate( true ); + + try + { + return _time.apply( this, arguments ); + } + finally + { + o.procedure.unuse(); + // if( o.procedure.isUsed() ) + // return; + if( !o.procedure.isUsed() ) + { + o.procedure.activate( false ); + _.assert( !o.procedure.isActivated() ); + o.procedure.end(); + } + } + } + + /* */ + + function timePeriodic() + { + o.procedure.activate( true ); + try + { + return _time.apply( this, arguments ); + } + finally + { + // _.assert( !o.procedure.isFinited() ); + /* Dmytro : periodic timer finishes procedure if callback returns undefined */ + if( !o.procedure.isFinited() ) + { + o.procedure.activate( false ); + _.assert( !o.procedure.isActivated() ); + } + } + } + + /* */ + + function cancel() + { + + /* xxx aaa for Dmytro : look suspicious! */ /* Dmytro : add conditions to fix behavior of routine */ + // if( timer.state !== 0 && o.method.name !== '_periodic' ) + if( timer.state !== 0 && timer.state !== -2 && timer.state !== 2 && o.method.name !== '_periodic' ) + return; + + if( !o.procedure.use() && !o.procedure.isTopMost() ) + o.procedure.activate( true ); + + try + { + return _cancel( this, arguments ); + } + finally + { + o.procedure.unuse(); + // if( o.procedure.isUsed() ) + // return; + + if( !o.procedure.isUsed() ) + { + o.procedure.activate( false ); + _.assert( !o.procedure.isActivated() ); + o.procedure.end(); + } + } + + } + +} + +_timeBegin.defaults = +{ + delay : null, + procedure : null, + onTime : null, + onCancel : null, + method : _.time._begin, +} + +// + +function timeBegin( /* delay, procedure, onTime, onCancel */ ) +{ + let delay = arguments[ 0 ]; + let procedure = arguments[ 1 ]; + let onTime = arguments[ 2 ]; + let onCancel = arguments[ 3 ]; + + if( !_.procedureIs( procedure ) ) + { + onTime = arguments[ 1 ]; + onCancel = arguments[ 2 ]; + procedure = 1; + } + + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4 ); + _.assert( _.numberIs( delay ) ); + _.assert( _.routineIs( onTime ) || onTime === undefined || onTime === null ); + _.assert( _.routineIs( onCancel ) || onCancel === undefined || onCancel === null ); + + let o2 = Object.create( null ); + o2.delay = delay; + o2.procedure = procedure; + o2.onTime = onTime; + o2.onCancel = onCancel || null; + o2.method = _.time._begin; + + return _timeBegin.call( this, o2 ); +} + +// + +function timeFinally( delay, procedure, onTime ) +{ + _.assert( arguments.length === 2 || arguments.length === 3 ); + + if( !_.procedureIs( procedure ) ) + { + onTime = arguments[ 1 ]; + procedure = 1; + } + + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4 ); + _.assert( _.numberIs( delay ) ); + _.assert( _.routineIs( onTime ) || onTime === undefined || onTime === null ); + + let o2 = Object.create( null ); + o2.delay = delay; + o2.procedure = procedure; + o2.onTime = onTime; + o2.onCancel = onTime; + o2.method = _.time._begin; + + let timer = _timeBegin.call( this, o2 ); + return timer; +} + +// + +function timePeriodic( /* delay, procedure, onTime, onCancel */ ) +{ + let delay = arguments[ 0 ]; + let procedure = arguments[ 1 ]; + let onTime = arguments[ 2 ]; + let onCancel = arguments[ 3 ]; + + if( !_.procedureIs( procedure ) ) + { + onTime = arguments[ 1 ]; + onCancel = arguments[ 2 ]; + procedure = 1; + } + + _.assert( arguments.length === 2 || arguments.length === 3 || arguments.length === 4 ); + _.assert( _.numberIs( delay ) ); + _.assert( _.routineIs( onTime ) ); + _.assert( _.routineIs( onCancel ) || onCancel === undefined || onCancel === null ); + + let o2 = Object.create( null ); + o2.delay = delay; + o2.procedure = procedure; + o2.onTime = onTime; + o2.onCancel = onCancel || null; + o2.method = _.time._periodic; + + return _timeBegin.call( this, o2 ); +} + +// -- +// etc +// -- + +function begin( o ) +{ + o = _.Procedure.OptionsFrom( ... arguments ); + o._stack = _.Procedure.Stack( o._stack, 1 ); + let result = _.Procedure.From( o ); + result.begin(); + return result; +} + +// -- +// meta +// -- + +function _Setup1() +{ + _.assert( _.strIs( _.setup._entryProcedureStack ) ); + + _.assert( _.Procedure.InstancesArray.length === 0 ); + + if( !_.Procedure.EntryProcedure ) + _.Procedure.EntryProcedure = _.procedure.begin + ({ + _stack : _.setup._entryProcedureStack, + _object : null, + _name : 'entry', + _quasi : true, + _waitTimer : false, + }); + + _.assert( _.Procedure.ActiveProcedures.length === 0 ); + + _.Procedure.EntryProcedure.activate( true ); + + _.assert( !!_.process && !!_.process.on ); + + _.process.on( _.event.Chain( 'available', 'exit', 'exit' ), _.procedure._eventProcessExitHandle ); + // _.process.on( 'available', _.event.Name( 'exit' ), _.event.Name( 'exit' ), _.procedure._eventProcessExitHandle ); + + /* xxx : add explenation */ + /* xxx aaa for Dmytro : introduce mini-class _.event.Chain() // Dmytro : introduced, covered + _.process.on( 'available', _.event.Name( 'exit' ), _.event.Name( 'exit' ), _.procedure._eventProcessExitHandle ) + -> + _.process.on( _.event.Chain( 'available', 'exit', 'exit' ), _.procedure._eventProcessExitHandle ) + aaa for Dmytro : restrict routines _.*.on() to accept 2 arguments // Dmytro : done + */ + +} + +// -- +// relations +// -- + +let Events = +{ + terminationBegin : [], + terminationEnd : [], +} + +Object.freeze( Events ); + +let _edispatcher = +{ + events : Events, +} + +let TimeExtension = +{ + begin : timeBegin, + finally : timeFinally, + periodic : timePeriodic, +} + +let ProcedureExtension = +{ + + // event + + on, + off, + _eventTerminationBeginHandle, + _eventTerminationEndHandle, + _eventProcessExitHandle, + + // termination + + terminationReport, + terminationBegin, + _terminationIteration, + _terminationRestart, + _terminationEnd, + _timersEnd, + + // etc + + begin, + + // meta + + _Setup1, + + // fields + + _edispatcher, + +} + +// -- +// define namspeces +// -- + +_.assert( _.routineIs( _.accessor.define.getter.alias ) ); +_.assert( _.routineIs( _.accessor.define.suite.alias ) ); + +Object.assign( _.time, TimeExtension ); +Object.assign( _.procedure, ProcedureExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _.procedure; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocedure/proto/wtools/abase/l8_procedure/Namespace.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocedure/proto/wtools/abase/l8_procedure' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Namespace_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Namespace_s */ })(); + +/* */ /* begin of file Procedure_s */ ( function Procedure_s() { function Procedure_s_naked() { ( function _Procedure_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( !!_global_.wTools, 'Does not have wTools' ); +_.assert( _global_.wTools.Procedure === undefined, 'wTools.Procedure is already defined' ); + +// -- +// inter +// -- + +/** + *@summary Collection of cross-platform routines to launch, stop and track collection of asynchronous procedures. + @namespace wTools.procedure + @extends Tools + @module Tools/base/Procedure +*/ + +const Parent = null; +const Self = wProcedure; +function wProcedure( o ) +{ + + if( !( this instanceof Self ) ) + if( o instanceof Self ) + { + return o; + } + + o = Self.OptionsFrom( ... arguments ); + o._stack = _.Procedure.Stack( o._stack, 1 ); + + let args = [ o ]; + if( !( this instanceof Self ) ) + return new( _.constructorJoin( Self, args ) ); + return Self.prototype.init.apply( this, args ); +} + +Self.shortName = 'Procedure'; + +// -- +// instance +// -- + +function init( o ) +{ + let procedure = this; + + _.workpiece.initFields( procedure ); + Object.preventExtensions( procedure ); + procedure.copy( o ); + + _.assert( _.strIs( procedure._stack ) ); + _.assert( procedure._sourcePath === null ); + + procedure._sourcePath = procedure._stack.split( '\n' )[ 0 ]; + + procedure._longNameMake(); + + _.arrayAppendOnceStrictly( _.Procedure.InstancesArray, procedure ); + + _.assert( _.strIs( procedure._sourcePath ) ); + _.assert( arguments.length === 1 ); + _.assert( _.Procedure.NamesMap[ procedure._longName ] === procedure, () => `${procedure._longName} not found` ); + + return procedure; +} + +// + +function finit() +{ + let procedure = this; + + // if( procedure.id === 4 ) + // debugger; + + _.assert( !procedure.isFinited(), () => `${procedure._longName} not found is alread finited` ); + _.assert( _.Procedure.NamesMap[ procedure._longName ] === procedure, () => `${procedure._longName} not found` ); + _.assert( !procedure.isActivated(), `Cant finit ${procedure._longName}, it is activated` ); + + delete _.Procedure.NamesMap[ procedure._longName ]; + + _.arrayRemoveOnceStrictly( _.Procedure.InstancesArray, procedure ); + + if( _.Procedure._Terminating ) + { + _.procedure._terminationListInvalidated = 1; + _.procedure._terminationRestart(); + } + + return _.Copyable.prototype.finit.call( procedure ); +} + +// + +/** + * @summary Returns true if procedure is quasi. Quasi procedure procedure is not waited. + * @method isQuasi + * @class wProcedure + * @namespace Tools + * @module Tools/base/Procedure + */ + +function isQuasi() +{ + let procedure = this; + return procedure._quasi; +} + +// + +/** + * @summary Returns true if procedure is running. + * @method isAlive + * @class wProcedure + * @namespace Tools + * @module Tools/base/Procedure + */ + +function isAlive() +{ + let procedure = this; + return procedure._waitTimer !== null; +} + +// + +/** + * @summary Launches the procedure. + * @method begin + * @class wProcedure + * @namespace Tools + * @module Tools/base/Procedure + */ + +function begin() +{ + let procedure = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( !procedure.isFinited() ); + + if( procedure._waitTimer === null ) + procedure._waitTimer = _.time._begin( Infinity ); + + if( !procedure._longName ) + procedure._longNameMake(); + + _.assert( _.Procedure.NamesMap[ procedure._longName ] === procedure, () => `${procedure._longName} not found` ); + + return procedure; +} + +// + +/** + * @summary Stops the procedure. + * @method end + * @class wProcedure + * @namespace Tools + * @module Tools/base/Procedure + */ + +function end() +{ + let procedure = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( procedure._waitTimer !== null, `${procedure._longName} is not alive` ); + + // if( _.Procedure._Terminating ) + // { + // _.procedure._terminationListInvalidated = 1; + // _.procedure._terminationRestart(); + // } + + if( procedure._waitTimer ) + _.time._cancel( procedure._waitTimer ); + procedure._waitTimer = null; + procedure.finit(); + + return procedure; +} + +// + +function isTopMost() +{ + let procedure = this; + return procedure === _.Procedure.ActiveProcedure; +} + +// + +function isActivated() +{ + let procedure = this; + return _.longHas( _.Procedure.ActiveProcedures, procedure ); +} + +// + +function activate( val ) +{ + let procedure = this; + + if( val === undefined ) + val = true; + val = !!val; + + _.assert( !procedure.isFinited(), () => `${procedure._longName} is finited!` ); + + if( val ) + { + _.assert( procedure !== _.Procedure.ActiveProcedure, () => `${procedure._longName} is already active` ); + _.Procedure.ActiveProcedures.push( procedure ); + _.Procedure.ActiveProcedure = procedure; + } + else + { + _.assert + ( + procedure === _.Procedure.ActiveProcedure, + () => `Attempt to deactivate ${procedure._longName}\nBut active procedure is ` + + `${_.Procedure.ActiveProcedure ? _.Procedure.ActiveProcedure._longName : _.Procedure.ActiveProcedure}` + ); + _.Procedure.ActiveProcedures.pop(); + _.Procedure.ActiveProcedure = _.Procedure.ActiveProcedures[ _.Procedure.ActiveProcedures.length-1 ] || null; + } + + return procedure; +} + +// + +function Activate( procedure, val ) +{ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( procedure instanceof Self ); + + return procedure.activate( val ); +} + +// + +function use() +{ + let procedure = this; + let result = procedure.isUsed(); + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( procedure._counter >= 0 ); + _.assert( !procedure.isFinited() ); + procedure._counter += 1; + return result; +} + +// + +function unuse() +{ + let procedure = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( !procedure.isFinited() ); + procedure._counter -= 1; + _.assert( procedure._counter >= 0 ); + let result = procedure.isUsed(); + return result; +} + +// + +function isUsed() +{ + let procedure = this; + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( procedure._counter >= 0 ); + return procedure._counter > 0; +} + +// + +function object( timer ) +{ + let procedure = this; + if( arguments.length === 1 ) + { + _.assert( timer !== undefined ); + procedure._object = timer; + return procedure; + } + else + { + _.assert( arguments.length === 0, 'Expects no arguments' ); + return procedure._object; + } +} + +// + +function stack( stack ) +{ + let procedure = this; + + if( arguments.length === 0 ) + return procedure._stack; + + if( procedure._stack ) + return; + + _.assert( arguments.length === 1 ); + + procedure._stack = procedure.Stack( stack ); + + if( procedure._name ) + procedure._longNameMake(); + + return procedure; +} + +// + +function stackElse( stack ) +{ + let procedure = this; + + if( arguments.length === 0 ) + return procedure._stack; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( procedure._stack && procedure._explicit ) + return procedure; + procedure._explicit = true; + + return procedure.stack( stack ); +} + +// + +/** + * @summary Getter/Setter routine for `name` property. + * @description + * Returns name of the procedure if no args provided. Sets name of procedure if provided single argument `name`. + * @param {String} [name] Name of the procedure. + * @method name + * @class wProcedure + * @namespace Tools + * @module Tools/base/Procedure + */ + +function name( name ) +{ + let procedure = this; + + if( arguments.length === 0 ) + return procedure._name; + + _.assert( arguments.length === 1 ); + _.assert( _.strIs( name ), () => 'Expects string, but got ' + _.entity.strType( name ) ); + + procedure._name = name; + + if( procedure._longName ) + procedure._longNameMake(); + + return procedure; +} + +// + +function nameElse( name ) +{ + let procedure = this; + + if( arguments.length === 0 ) + return procedure._name; + + _.assert( arguments.length === 1 ); + + if( procedure._name ) + return procedure; + + return procedure.name( name ); +} + +// + +/** + * @summary Getter/Setter routine for `routine` property. + * @description + * Returns routine of the procedure if no args provided. Sets routine of procedure if provided single argument `routine`. + * @param {String} [routine] Name of the procedure. + * @method routine + * @class wProcedure + * @namespace Tools + * @module Tools/base/Procedure + */ + +function routine( routine ) +{ + let procedure = this; + + if( arguments.length === 0 ) + return procedure._routine; + + _.assert( arguments.length === 1 ); + _.assert( _.routineIs( routine ), () => 'Expects routine, but got ' + _.entity.strType( routine ) ); + + procedure._routine = routine; + + if( procedure._longName ) + procedure._longNameMake(); + + return procedure; +} + +// + +function routineElse( routine ) +{ + let procedure = this; + + if( arguments.length === 0 ) + return procedure._routine; + + _.assert( arguments.length === 1 ); + + if( procedure._routine ) + return procedure; + + return procedure.routine( routine ); +} + +// + +/** + * @summary Getter/Setter routine for `longName` property. + * @description + * Returns `longName` of the procedure if no args provided. Sets name of procedure if provided single argument `name`. + * @param {String} [longName] Full name of the procedure. + * @method longName + * @class wProcedure + * @namespace Tools + * @module Tools/base/Procedure + */ + +function longName( longName ) +{ + let procedure = this; + + if( arguments.length === 0 ) + return procedure._longName; + + _.assert( arguments.length === 1 ); + _.assert( _.strDefined( longName ) ); + _.assert( procedure.id > 0 ); + + if( procedure._longName ) + { + _.assert( _.Procedure.NamesMap[ procedure._longName ] === procedure, () => `${procedure._longName} not found` ); + delete _.Procedure.NamesMap[ procedure._longName ]; + procedure._longName = null; + } + + procedure._longName = longName; + _.assert( _.Procedure.NamesMap[ procedure._longName ] === undefined, () => `${procedure._longName} already exist` ); + _.Procedure.NamesMap[ procedure._longName ] = procedure; + + return procedure; +} + +// + +function _longNameMake() +{ + let procedure = this; + + let name = procedure._name || ''; + let sourcePath = procedure._sourcePath; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( _.strIs( name ) ); + + if( procedure.id === 0 ) + procedure.id = procedure._IdAlloc(); + + // if( procedure.id === 4 ) + // debugger; + + let result = 'procedure::' + name + '#' + procedure.id + ' @ ' + ( sourcePath ? sourcePath : '' ); + + procedure.longName( result ); + + _.assert( procedure.id > 0 ); + + + return result; +} + +// -- +// static +// -- + +/** + * @summary Find procedure using id/name/routine as key. + * @param {Number|String|Routine} filter Find to filter procedures. + * @routine Find + * @returns {Object|Array} Returns one or several instances of {@link module:Tools/base/Procedure.wProcedure}. + * @class wProcedure + * @namespace Tools + * @module Tools/base/Procedure + */ + +/** + * @summary Find procedure using id/name/routine as key. + * @param {Number|String|Routine} filter Find to filter procedures. + * @routine Find + * @returns {Object|Array} Returns one or several instances of {@link module:Tools/base/Procedure.wProcedure}. + * @module Tools/base/Procedure + * @namespace Tools.procedure + */ + +function Find( filter ) +{ + let Cls = this; + + _.assert( arguments.length === 1 ); + + if( _.arrayIs( filter ) ) + { + let result = filter.map( ( p ) => Cls.Find( p ) ); + result = _.arrayFlatten( result ); + return result; + } + + let result = filter; + let procedures = _.props.vals( _.Procedure.NamesMap ); + + if( _.mapIs( filter ) ) + { + if( filter._quasi === null ) + delete filter._quasi; + if( _.boolLike( filter._quasi ) ) + filter._quasi = !!filter._quasi; + + if( filter.procedures ) + procedures = filter.procedures; + delete filter.procedures; + + _.assert( _.arrayIs( procedures ) ); + result = _.filter_( null, procedures, filter ); + if( !result.length ) + return result; + } + + if( _.numberIs( filter ) ) + { + result = _.filter_( null, procedures, { id : filter } ); + if( !result.length ) + return result; + } + + if( _.strIs( filter ) ) + { + result = _.filter_( null, procedures, { _name : filter } ); + if( !result.length ) + return result; + } + + if( _.routineIs( filter ) ) + { + result = _.filter_( null, procedures, { _routine : filter } ); + if( !result.length ) + return result; + } + + if( _.arrayIs( result ) ) + _.assert( result.every( ( result ) => result instanceof Self, 'Not a filter' ) ); + else + _.assert( result instanceof Self, `${_.entity.strType( result )} is not a filter` ); + + return result; +} + +// + +function FindAlive() +{ + let cls = this; + let result = cls.InstancesArray.filter( ( procedure ) => procedure.isAlive() && !procedure.isQuasi() ); + return result; +} + +// + +function NativeWatchingEnable( o ) +{ + + o = _.routine.options( NativeWatchingEnable, o || null ); + _.assert( !!o.enable, 'not tested' ); + + let original = _.Procedure._OriginalTimeRoutines = _.Procedure._OriginalTimeRoutines || Object.create( null ); + + if( o.enable ) + { + _.assert( _.entity.lengthOf( original ) === 0 ); + + original.setTimeout = _global_.setTimeout; + original.clearTimeout = _global_.clearTimeout; + original.setInterval = _global_.setInterval; + original.clearInterval = _global_.clearInterval; + if( _global_.requestAnimationFrame ) + original.requestAnimationFrame = _global_.requestAnimationFrame; + if( _global_.cancelAnimationFrame ) + original.cancelAnimationFrame = _global_.cancelAnimationFrame; + + _global_.setTimeout = setTimeout; + _global_.clearTimeout = clearTimeout; + _global_.setInterval = setInterval; + _global_.clearInterval = clearInterval; + if( _global_.requestAnimationFrame ) + _global_.requestAnimationFrame = requestAnimationFrame; + if( _global_.cancelAnimationFrame ) + _global_.cancelAnimationFrame = cancelAnimationFrame; + + } + else + { + + for( let k in original ) + { + _.assert( _.routineIs( original[ k ] ) ); + _global_[ k ] = original[ k ]; + delete original[ k ]; + } + + } + + /* */ + + function setTimeout( onTime, ... args ) + { + let object = original.setTimeout.call( _global_, onTime2, ... args ); + let procedure = procedureMake({ _object : object }); + return object; + function onTime2() + { + procedureRemove( procedure ); + return onTime( ... arguments ); + } + } + + /* */ + + function clearTimeout( timer ) + { + let result = original.clearTimeout.call( _global_, ... arguments ); + let procedures = _.Procedure.Find({ _object : timer }) + if( procedures.length ) + procedureRemove( procedures[ 0 ] ); + return result; + } + + /* */ + + function setInterval( onTime, ... args ) + { + let object = original.setInterval.call( _global_, onTime, ... args ); + let procedure = procedureMake({ _object : object }); + return object; + } + + /* */ + + function clearInterval( timer ) + { + let result = original.clearInterval.call( _global_, ... arguments ); + let procedures = _.Procedure.Find({ _object : timer }) + if( procedures.length ) + procedureRemove( procedures[ 0 ] ); + return result; + } + + /* */ + + function requestAnimationFrame( onTime, ... args ) + { + let object = original.requestAnimationFrame.call( _global_, onTime, ... args ); + let procedure = procedureMake({ _object : object }); + return object; + } + + /* */ + + function cancelAnimationFrame( timer ) + { + let result = original.cancelAnimationFrame.call( _global_, ... arguments ); + let procedures = _.Procedure.Find({ _object : timer }) + if( procedures.length ) + procedureRemove( procedures[ 0 ] ); + return result; + } + + /* */ + + function procedureMake( o ) + { + let procedure = new _.Procedure + ({ + _waitTimer : false, + _stack : 2, + ... o, + }); + return procedure; + } + + /* */ + + function procedureRemove( procedure ) + { + procedure.finit(); + } + + /* */ + +} + +NativeWatchingEnable.defaults = +{ + enable : 1, +} + +// + +/** + * @summary Find procedure using id/name/routine as key. + * @param {Number|String|Routine} filter Find to filter procedures. + * @routine GetSingleMaybe + * @returns {Object} Returns single instance of {@link module:Tools/base/Procedure.wProcedure} or null. + * @class wProcedure + * @namespace Tools + * @module Tools/base/Procedure + */ + +/** + * @summary Find procedure using id/name/routine as key. + * @param {Number|String|Routine} filter Find to filter procedures. + * @routine getSingleMaybe + * @returns {Object} Returns single instance of {@link module:Tools/base/Procedure.wProcedure} or null. + * @module Tools/base/Procedure + * @namespace Tools.procedure + */ + +function GetSingleMaybe( filter ) +{ + _.assert( arguments.length === 1 ); + let result = this.Find( filter ); + if( _.arrayIs( result ) && result.length !== 1 ) + return null; + return result; +} + +// + +function ExportInfo( o ) +{ + let result = ''; + + if( _.longIs( arguments[ 0 ] ) ) + o = { procedures : o } + o = _.routine.options( ExportInfo, o || null ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + + let procedures = this.Find( o ); + + for( let p = 0 ; p < procedures.length ; p++ ) + { + let procedure = procedures[ p ]; + result += procedure._longName + '\n'; + } + + return result; +} + +ExportInfo.defaults = +{ + procedures : null, + _quasi : null, +} + +// + +function OptionsFrom( o ) +{ + if( _.strIs( o ) ) + o = { _name : o } + else if( _.numberIs( o ) ) + o = { _stack : o } + + _.assert( o === undefined || o === null || _.object.isBasic( o ) ); + _.assert( arguments.length === 0 || arguments.length === 1 ); + + if( o === undefined || o === null ) + o = Object.create( null ); + + return o; +} + +// + +function From( o ) +{ + o = Self.OptionsFrom( ... arguments ); + o._stack = _.Procedure.Stack( o._stack, 1 ); + let result = Self( o ); + return result; +} + +// + +/** + * @summary Short-cut for `begin` method. Creates instance of `wProcedure` and launches the routine. + * @param {Object} o Options map + * @param {String} o._name Name of procedure. + * @param {Number} o._waitTimer Timer for procedure. + * @param {Function} o._routine Routine to lauch. + * @routine Begin + * @returns {Object} Returns instance of {@link module:Tools/base/Procedure.wProcedure} + * @class wProcedure + * @namespace Tools + * @module Tools/base/Procedure + */ + +/** + * @summary Short-cut for `begin` method. Creates instance of `wProcedure` and launches the routine. + * @param {Object} o Options map + * @param {String} o._name Name of procedure. + * @param {Number} o._waitTimer Timer for procedure. + * @param {Function} o._routine Routine to lauch. + * @routine begin + * @returns {Object} Returns instance of {@link module:Tools/base/Procedure.wProcedure} + * @module Tools/base/Procedure + * @namespace Tools.procedure + */ + +function Begin( o ) +{ + o = Self.OptionsFrom( ... arguments ); + o._stack = _.Procedure.Stack( o._stack, 1 ); + let result = Self.From( o ); + // let result = Self.From( ... arguments ); + result.begin(); + return result; +} + +Begin.defaults = +{ + _name : null, + _waitTimer : null, + _routine : null, +} + +// + +/** + * @summary Short-cut for `end` method. Selects procedure using `get` routine and stops the execution. + * @param {Number|String|Routine} procedure Procedure selector. + * @routine End + * @returns {Object} Returns instance of {@link module:Tools/base/Procedure.wProcedure} + * @class wProcedure + * @namespace Tools + * @module Tools/base/Procedure + */ + +/** + * @summary Short-cut for `end` method. Selects procedure using `get` routine and stops the execution. + * @param {Number|String|Routine} procedure Procedure selector. + * @routine end + * @returns {Object} Returns instance of {@link module:Tools/base/Procedure.wProcedure} + * @module Tools/base/Procedure + * @namespace Tools.procedure + */ + +function End( procedure ) +{ + _.assert( arguments.length === 1 ); + procedure = _.procedure.find( procedure ); + /* Dmytro : routine find() ( linked to routine Find ) returns only arrays. I think that routine Find should be unchanged */ + _.assert( procedure.length === 1 ); + procedure = procedure[ 0 ]; + return procedure.end(); +} + +// + +/** + * @summary Increases counter of procedures and returns it value. + * @routine _IdAlloc + * @class wProcedure + * @namespace Tools + * @module Tools/base/Procedure + */ + +/** + * @summary Increases counter of procedures and returns it value. + * @routine _IdAlloc + * @module Tools/base/Procedure + * @namespace Tools.procedure + */ + +function _IdAlloc() +{ + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.Procedure.Counter += 1; + let result = _.Procedure.Counter; + + return result; +} + +// + +function WithObject( timer ) +{ + let result = _.filter_( null, _.Procedure.NamesMap, { _object : timer } ); + return _.props.vals( result )[ 0 ]; +} + +// + +function Stack( stack, delta ) +{ + + if( !Config.debug || !_.Procedure.UsingStack ) + return ''; + + if( _.numberIs( delta ) ) + delta += 1; + else if( delta === undefined ) + delta = 1; + + return _.introspector.stackRelative.call( this, stack, delta ); +} + +// -- +// relations +// -- + +let Composes = +{ +} + +let Associates = +{ + _name : null, + _stack : null, + _object : null, + _waitTimer : null, + _explicit : false, + _quasi : false, +} + +let Restricts = +{ + id : 0, + _counter : 0, + _sourcePath : null, + _longName : null, + _routine : null, + _waitTime : Infinity, +} + +// let Medials = +// { +// stackDelta : null, +// } + +let Statics = +{ + + // fields + + NamesMap : Object.create( null ), + InstancesArray : [], + _Terminating : 0, + _Exiting : 0, + _TerminationTimer : null, + _TerminationListInvalidated : 1, + TerminationPeriod : 7500, + UsingStack : 1, + Counter : 0, + ActiveProcedure : null, + ActiveProcedures : [], + EntryProcedure : null, + _OriginalTimeRoutines : null, + + // implementation + + NativeWatchingEnable, + + Find, /* qqq : cover please. one test routine per type of input data */ + FindAlive, + + GetSingleMaybe, + ExportInfo, + OptionsFrom, + From, + Begin, + End, + Activate, + + _IdAlloc, + WithObject, + Stack, + +} + +let Forbids = +{ + + namesMap : 'namesMap', + terminating : 'terminating', + terminationTimer : 'terminationTimer', + terminationPeriod : 'terminationPeriod', + terminationListInvalidated : 'terminationListInvalidated', + usingSourcePath : 'usingSourcePath', + counter : 'counter', + activeProcedure : 'activeProcedure', + activeProcedures : 'activeProcedures', + entryProcedure : 'entryProcedure', + _onTerminationBegin : '_onTerminationBegin', + _onTerminationEnd : '_onTerminationEnd', + _timer : '_timer', + +} + +// -- +// define class +// -- + +let ExtendClass = +{ + + // inter + + init, + finit, + + isQuasi, + isAlive, + begin, + end, + + isTopMost, + isActivated, + activate, + Activate, + + use, + unuse, + isUsed, + + object, + stack, + stackElse, + name, + nameElse, + routine, + routineElse, + longName, + _longNameMake, + + // + + NativeWatchingEnable, + + Find, /* qqq : cover please. one test routine per type of input data */ + FindAlive, + + GetSingleMaybe, + ExportInfo, + OptionsFrom, + From, + Begin, + End, + + _IdAlloc, + WithObject, + Stack, + + // relations + + Composes, + Associates, + Restricts, + // Medials, + Statics, + Forbids, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : ExtendClass, +}); + +_.Copyable.mixin( Self ); + +// -- +// define namspeces +// -- + +_.assert( _.routineIs( _.accessor.define.getter.alias ) ); +_.assert( _.routineIs( _.accessor.define.suite.alias ) ); + +// let alias = ( originalName ) => _.accessor.define.suite.alias({ originalName, container : Self }); +// let alias = ( originalName ) => _.define.alias( originalName ); +let alias = ( originalName ) => _.define.alias({ originalName, originalContainer : Self }); +let join = ( originalName ) => _.routineJoin( Self, Self[ originalName ] ); +let NamespaceBlueprint = +{ + + // fields + + namesMap : alias( 'NamesMap' ), + instancesArray : alias( 'InstancesArray' ), + + terminationPeriod : alias( 'TerminationPeriod' ), + usingSourcePath : alias( 'UsingStack' ), + counter : alias( 'Counter' ), + activeProcedure : alias( 'ActiveProcedure' ), + activeProcedures : alias( 'ActiveProcedures' ), + entryProcedure : alias( 'EntryProcedure' ), + + // implementation + + find : join( 'Find' ), + findAlive : join( 'FindAlive' ), + getSingleMaybe : join( 'GetSingleMaybe' ), + from : join( 'From' ), + // begin : join( 'Begin' ), + end : join( 'End' ), + activate : join( 'Activate' ), + stack : join( 'Stack' ), + exportString : join( 'ExportInfo' ), + +} + +// debugger; // _global_.debugger = 1; +_.construction.extend( _.procedure, NamespaceBlueprint ); +// debugger; + +_.assert( Self.TerminationPeriod > 0 ); +_.assert( _.procedure.terminationPeriod > 0 ); + +_[ Self.shortName ] = Self; +_.procedure[ Self.shortName ] = Self; + +_.procedure._Setup1(); + +_.assert( _.routineIs( _.procedure.find ) ); +_.assert( _.routineIs( Self.Find ) ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _.procedure; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocedure/proto/wtools/abase/l8_procedure/Procedure.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocedure/proto/wtools/abase/l8_procedure' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Procedure_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Procedure_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wprocess */ ( function wprocess() { function wprocess_naked() { +module.exports = require( '../wtools/abase/l4_process/module/Process.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wProcess', 'wprocess' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/node_modules/wprocess' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wprocess_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wprocess */ })(); + +/* */ /* begin of file Basic_s */ ( function Basic_s() { function Basic_s_naked() { ( function _Basic_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + + _.include( 'wPathBasic' ); + _.include( 'wGdf' ); + _.include( 'wBlueprint' ); + _.include( 'wConsequence' ); + _.include( 'wFilesBasic' ); + _.include( 'wIntrospectorExtra' ); + + if( Config.interpreter === 'browser' ) + _.include( 'wFilesHttp' ) + + module[ 'exports' ] = _global_.wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/include/Basic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Basic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Basic_s */ })(); + +/* */ /* begin of file Mid_s */ ( function Mid_s() { function Mid_s_naked() { ( function _Mid_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../node_modules/Tools' ); + + require( '../l1/Basic.s' ); + require( '../l2/Process.s' ); + require( '../l3/Execution.s' ); + require( '../l3/Io.s' ); + if( Config.interpreter === 'njs' ) + require( '../l3/Path.ss' ); + + module[ 'exports' ] = _global_.wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/include/Mid.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Mid_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Mid_s */ })(); + +/* */ /* begin of file Basic_s */ ( function Basic_s() { function Basic_s_naked() { ( function _Basic_s_() +{ + +'use strict'; + +let System, ChildProcess, StripAnsi, WindowsKill, WindowsProcessTree; +const _global = _global_; +const _ = _global_.wTools; +_.process = _.process || Object.create( null ); + +_.assert( !!_realGlobal_ ); + +// -- +// dichotomy +// -- + +function isNativeDescriptor( src ) +{ + if( !src ) + return false; + if( !ChildProcess ) + ChildProcess = require( 'child_process' ); + return src instanceof ChildProcess.ChildProcess; +} + +// + +function isSession( src ) +{ + if( !_.object.isBasic( src ) ) + return false; + return src.ipc !== undefined && src.procedure !== undefined && src.process !== undefined; +} + +// + +function pidFrom( src ) +{ + _.assert( arguments.length === 1 ); + + if( _.numberIs( src ) ) + return src; + if( _.object.isBasic( src ) ) + { + if( src.process ) + src = src.process; + if( src.pnd ) + src = src.pnd; + if( Config.debug ) + { + if( !ChildProcess ) + ChildProcess = require( 'child_process' ); + _.assert( src instanceof ChildProcess.ChildProcess ); + } + return src.pid; + } + + _.assert( 0, `Cant get PID from ${_.entity.strType( src )}` ); +} + +// -- +// temp +// -- + +let _tempFiles = []; + +/* qqq : for Vova : reuse _.program.* */ +function tempOpen_head( routine, args ) +{ + let o; + + if( _.strIs( args[ 0 ] ) || _.bufferRawIs( args[ 0 ] ) ) + o = { routineCode : args[ 0 ] }; + else + o = args[ 0 ]; + + o = _.routine.options_( routine, o ); + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1, 'Expects single argument' ); + + return o; +} + +// + +function tempOpen_body( o ) +{ + _.routine.assertOptions( tempOpen, arguments ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert + ( + _.strIs( o.routineCode ) || _.bufferRawIs( o.routineCode ), + 'Expects string or buffer raw {-o.routineCode-}, but got', _.entity.strType( o.routineCode ) + ); + + let tempDirPath = _.path.tempOpen( _.path.realMainDir(), 'ProcessTempOpen' ); + let filePath = _.path.join( tempDirPath, _.idWithDateAndTime() + '.ss' ); + _tempFiles.push( filePath ); + _.fileProvider.fileWrite( filePath, o.routineCode ); + return filePath; +} + +var defaults = tempOpen_body.defaults = Object.create( null ); +defaults.routineCode = null; + +let tempOpen = _.routine.uniteCloning_replaceByUnite( tempOpen_head, tempOpen_body ); + +// + +function tempClose_head( routine, args ) +{ + let o; + + if( _.strIs( args[ 0 ] ) ) + o = { filePath : args[ 0 ] }; + else + o = args[ 0 ]; + + if( !o ) + o = Object.create( null ); + + o = _.routine.options_( routine, o ); + + _.assert( arguments.length === 2 ); + _.assert( args.length <= 1, 'Expects single argument or none' ); + + return o; +} + +function tempClose_body( o ) +{ + _.routine.assertOptions( tempClose, arguments ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( o.filePath ) || o.filePath === null, 'Expects string or null {-o.filePath-}, but got', _.entity.strType( o.filePath ) ); + + if( o.filePath ) + { + let i = _.longLeftIndex( _tempFiles, o.filePath ); + _.assert( i !== -1, `Requested {-o.filePath-} ${o.filePath} is not a path of temp application.` ) + _.fileProvider.fileDelete( o.filePath ); + _tempFiles.splice( i, 1 ); + } + else + { + if( !_tempFiles.length ) + return; + + _.fileProvider.filesDelete( _tempFiles ); + _tempFiles.splice( 0 ); + } + // if( !o.filePath ) + // { + // if( !_tempFiles.length ) + // return; + // + // _.fileProvider.filesDelete( _tempFiles ); + // _tempFiles.splice( 0 ); + // } + // else + // { + // let i = _.longLeftIndex( _tempFiles, o.filePath ); + // _.assert( i !== -1, `Requested {-o.filePath-} ${o.filePath} is not a path of temp application.` ) + // _.fileProvider.fileDelete( o.filePath ); + // _tempFiles.splice( i, 1 ); + // } +} + +var defaults = tempClose_body.defaults = Object.create( null ); +defaults.filePath = null; + +let tempClose = _.routine.uniteCloning_replaceByUnite( tempClose_head, tempClose_body ); + +// -- +// eventer +// -- + +let _on = _.process.on; +function on() +{ + let o2 = _on.apply( this, arguments ); + if( o2.available ) /* Dmytro : use descriptor field in new implementation */ + _.process._eventAvailableHandle(); + return o2; +} + +on.defaults = +{ + callbackMap : null, +} + +// + +function _eventAvailableHandle() +{ + if( !_.process._edispatcher.events.available.length ) + return; + + let callbacks = _.process._edispatcher.events.available.slice(); + callbacks.forEach( ( callback ) => + { + try + { + _.arrayRemoveOnceStrictly( _.process._edispatcher.events.available, callback ); + callback.call( _.process ); + } + catch( err ) + { + throw _.err( `Error in handler::${callback.name} of an event::available of module::Process\n`, err ); + } + }); + +} + +// + +_realGlobal_._exitHandlerRepairDone = _realGlobal_._exitHandlerRepairDone || 0; +_realGlobal_._exitHandlerRepairTerminating = _realGlobal_._exitHandlerRepairTerminating || 0; +function _exitHandlerRepair() +{ + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( _realGlobal_._exitHandlerRepairDone ) + return; + _realGlobal_._exitHandlerRepairDone = 1; + + if( !_global.process ) + return; + + process.on( 'SIGHUP', handle_functor( 'SIGHUP', 1 ) ); + process.on( 'SIGQUIT', handle_functor( 'SIGQUIT', 3 ) ); + process.on( 'SIGINT', handle_functor( 'SIGINT', 2 ) ); + process.on( 'SIGTERM', handle_functor( 'SIGTERM', 15 ) ); + process.on( 'SIGUSR1', handle_functor( 'SIGUSR1', 16 ) ); + process.on( 'SIGUSR2', handle_functor( 'SIGUSR2', 17 ) ); + + function handle_functor( signal, signalCode ) + { + return function handle() + { + if( _.process._verbosity ) + console.log( signal ); + if( _realGlobal_._exitHandlerRepairTerminating ) + return; + _realGlobal_._exitHandlerRepairTerminating = 1; + if( !_.process.exitReason() ) + { + let err = _._err + ({ + args : [ `Exit signal : ${signal} ( 128+${signalCode} )` ], + concealed : { exitSignal : signal }, + reason : 'exit signal', + }); + _.process.exitReason( err ); + } + /* + short delay is required to set exit reason of the process + otherwise reason will be exit code, not exit signal + */ + _.time._begin( _.process._sanitareTime, () => + { + try + { + process.removeListener( signal, handle ); + if( !process._exiting ) + { + try + { + process._exiting = true; + process.emit( 'exit', 128 + signalCode ); + } + catch( err ) + { + console.error( _.err( err ) ); + } + process.kill( process.pid, signal ); + } + } + catch( err ) + { + console.log( `Error on signal ${signal}` ); + console.log( err.toString() ); + console.log( err.stack ); + process.removeAllListeners( 'exit' ); + process.exit( -1 ); + } + }); + } + } + +} + +// + +function _eventsSetup() +{ + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( !_global.process ) + return; + + if( !_.process._registeredExitHandler ) + { + _global.process.once( 'exit', _.process._eventExitHandle ); + _.process._registeredExitHandler = _.process._eventExitHandle; + } + + if( !_.process._registeredExitBeforeHandler ) + { + _global.process.on( 'beforeExit', _.process._eventExitBeforeHandle ); + _.process._registeredExitBeforeHandler = _.process._eventExitBeforeHandle; + } + +} + +// + +function _eventExitHandle() +{ + let args = arguments; + _.process.exiting = true; + process.removeListener( 'exit', _.process._registeredExitHandler ); + _.process._registeredExitHandler = null; + _.process.eventGive({ event : 'exit', args }); + _.process._edispatcher.events.exit.splice( 0, _.process._edispatcher.events.exit.length ); +} + +// + +function _eventExitBeforeHandle() +{ + let args = arguments; + _.process.eventGive({ event : 'exitBefore', args }); +} + +// -- +// exit +// -- + +/** + * @summary Allows to set/get exit reason of current process. + * @description Saves exit reason if argument `reason` was provided, otherwise returns current exit reason value. + * Returns `null` if reason was not defined yet. + * @function exitReason + * @module Tools/base/ProcessBasic + * @namespace Tools.process + */ + +function exitReason( reason ) +{ + if( !_realGlobal_.wTools ) + _realGlobal_.wTools = Object.create( null ); + if( !_realGlobal_.wTools.process ) + _realGlobal_.wTools.process = Object.create( null ); + if( _realGlobal_.wTools.process._exitReason === undefined ) + _realGlobal_.wTools.process._exitReason = null; + if( reason === undefined ) + return _realGlobal_.wTools.process._exitReason; + _realGlobal_.wTools.process._exitReason = reason; + return _realGlobal_.wTools.process._exitReason; +} + +// + +/** + * @summary Allows to set/get exit code of current process. + * @description Updates exit code if argument `status` was provided and returns previous exit code. Returns current exit code if no argument provided. + * Returns `0` if exit code was not defined yet. + * @function exitCode + * @module Tools/base/ProcessBasic + * @namespace Tools.process + */ + +function exitCode( status ) +{ + let result; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( status === undefined || _.numberIs( status ) ); + + if( _global.process ) + { + result = process.exitCode || 0; + if( status !== undefined ) + process.exitCode = status; + } + + return result; +} + +// + +function exit( exitCode ) +{ + + exitCode = exitCode === undefined ? _.process.exitCode() : exitCode; + // exitCode = exitCode !== undefined ? exitCode : _.process.exitCode(); + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( exitCode === undefined || _.numberIs( exitCode ) ); + + if( _global.process ) + { + process.exit( exitCode ); + } + else + { + /*debugger;*/ + } +} + +// + +function exitWithBeep() +{ + let exitCode = _.process.exitCode(); + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( exitCode === undefined || _.numberIs( exitCode ) ); + + _.diagnosticBeep(); + + if( exitCode ) + _.diagnosticBeep(); + + _.process.exit( exitCode ); + + return exitCode; +} + +// -- +// args +// -- + +function _argsForm( o ) +{ + + o.args = _.array.as( o.args ); + + let _argsLength = o.args.length; + + if( _.strIs( o.execPath ) ) + { + o.execPath2 = o.execPath; + let execArgs = execPathParse( o.execPath ); + if( o.mode !== 'shell' ) + execArgs = _.process._argsUnqoute( execArgs ); + o.execPath = null; + if( execArgs.length ) + { + o.execPath = execArgs.shift(); + o.args = _.arrayPrependArray( o.args || [], execArgs ); + } + } + + if( o.execPath === null ) + { + _.assert( o.args.length > 0, 'Expects {-args-} to have at least one argument if {-execPath-} is not defined' ); + o.execPath = o.args.shift(); + o.execPath2 = o.execPath; + _argsLength = o.args.length; + o.execPath = _.process._argUnqoute( o.execPath ); + } + + o.args2 = o.args.slice(); + + /* passingThrough */ + + if( o.passingThrough ) + { + let argumentsOwn = process.argv.slice( 2 ); + if( argumentsOwn.length ) + o.args2 = _.arrayAppendArray( o.args2 || [], argumentsOwn ); + } + + _.assert( o.interpreterArgs === null || _.arrayIs( o.interpreterArgs ) ); + if( o.interpreterArgs && o.mode !== 'fork' ) + o.args2 = _.arrayPrependArray( o.args2, o.interpreterArgs ); + + /* Escapes and quotes: + - Original args provided via o.args + - Arguments of parent process if o.passingThrough is enabled + Skips arguments parsed from o.execPath. + */ + + if( o.mode === 'shell' ) + { + let appendedArgs = o.passingThrough ? process.argv.length - 2 : 0; + let prependedArgs = o.args2.length - ( _argsLength + appendedArgs ); + for( let i = prependedArgs; i < o.args2.length; i++ ) + { + o.args2[ i ] = _.process._argEscape( o.args2[ i ] ); + o.args2[ i ] = _.strQuote( o.args2[ i ] ); + } + } + + /* */ + + function execPathParse( src ) + { + let strOptions = + { + src, + delimeter : [ ' ' ], + quoting : 1, + quotingPrefixes : [ '"', `'`, '`' ], + quotingPostfixes : [ '"', `'`, '`' ], + preservingEmpty : 0, + preservingQuoting : 1, + stripping : 1 + } + let args = _.strSplit( strOptions ); + + let quotes = [ '"', `'`, '`' ]; + for( let i = 0; i < args.length; i++ ) + { + let begin = _.strBeginOf( args[ i ], quotes ); /* xxx */ + let end = _.strEndOf( args[ i ], quotes ); + if( begin && end && begin === end ) + continue; + + if( _.longHas( quotes, args[ i ] ) ) + continue; + + let r = _.strQuoteAnalyze + ({ + src : args[ i ], + quote : strOptions.quotingPrefixes + }); + + quotes.forEach( ( quote ) => + { + let found = _.strFindAll( args[ i ], quote ); + if( found.length % 2 === 0 ) + return; + for( let k = 0 ; k < found.length ; k += 1 ) + { + let pos = found[ k ].charsRangeLeft[ 0 ]; + for( let j = 0 ; j < r.ranges.length ; j += 2 ) + if( pos >= r.ranges[ j ] && pos <= r.ranges[ j + 1 ] ) + break; + throw _.err( `Arguments string in execPath: ${src} has not closed quoting in argument: ${args[ i ]}` ); + } + }) + } + + return args; + } + +} + +_argsForm.defaults = +{ + args : null, + args2 : null, + execPath : null, + execPath2 : null, + mode : null, + interpreterArgs : null, + passingThrough : null, +} + +// + +function _argUnqoute( arg ) +{ + let quotes = [ '"', `'`, '`' ]; + let result = _.strInsideOf + ({ + src : arg, + begin : quotes, + end : quotes, + pairing : 1, + }) + if( result ) + return result; + return arg; +} + +// + +function _argsUnqoute( args ) +{ + for( let i = 0; i < args.length; i++ ) + args[ i ] = _.process._argUnqoute( args[ i ] ); + return args; +} + +// -- +// escape +// -- + +function _argsEscape( args ) +{ + /* xxx */ + + for( let i = 0 ; i < args.length ; i++ ) + { + let quotesToEscape = process.platform === 'win32' ? [ '"' ] : [ '"', '`' ]; + args[ i ] = _.process._argEscape( args[ i ] ); + args[ i ] = _.strQuote( args[ i ] ); + // args[ i ] = _.process._argEscape2( args[ i ] ); /* zzz for Vova : use this routine, review fails */ + } + + return args; +} + +// + +function _argEscape( arg, quote ) +{ + + if( quote === undefined ) + quote = process.platform === 'win32' ? [ '"' ] : [ '"', '`' ]; + + _.assert( _.strIs( arg ) ); + _.assert( !!quote ); + + // xxx : remove this if after fix of strReplaceAll + if( _.longIs( quote ) ) + { + quote.forEach( ( quote ) => arg = act( arg, quote ) ); + return arg; + } + return act( arg, quote ); + + function act( arg, quote ) + { + _.assert( _.strIs( arg ) ); + _.assert( _.strIs( quote ) ); + return _.strReplaceAll( arg, quote, ( match, it ) => + { + if( it.input[ it.charsRangeLeft[ 0 ] - 1 ] === '\\' ) + return match; + return '\\' + match; + }); + } +} + +// + +function _argEscape2( arg ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.strIs( arg ) ); + + if( process.platform === 'win32' ) + { + //Sequence of backslashes followed by a double quote: + //double up all the backslashes and escape the double quote + arg = arg.replace( /(\\*)"/g, '$1$1\\"' ); + + // Sequence of backslashes followed by the end of the string + // (which will become a double quote later): + // double up all the backslashes + arg = arg.replace( /(\\*)$/, '$1$1' ); + + // All other backslashes occur literally + + // Quote the whole thing: + arg = `"${arg}"`; + + // Escape shell metacharacters: + arg = arg.replace( /([()\][%!^"`<>&|;, *?])/g, '^$1' ); + } + else + { + // Backslash-escape any hairy characters: + arg = arg.replace( /([^a-zA-Z0-9_])/g, '\\$1' ); + } + + // if( process.platform !== 'win32' ) + // { + // // Backslash-escape any hairy characters: + // arg = arg.replace( /([^a-zA-Z0-9_])/g, '\\$1' ); + // } + // else + // { + // //Sequence of backslashes followed by a double quote: + // //double up all the backslashes and escape the double quote + // arg = arg.replace( /(\\*)"/g, '$1$1\\"' ); + // + // // Sequence of backslashes followed by the end of the string + // // (which will become a double quote later): + // // double up all the backslashes + // arg = arg.replace( /(\\*)$/,'$1$1' ); + // + // // All other backslashes occur literally + // + // // Quote the whole thing: + // arg = `"${arg}"`; + // + // // Escape shell metacharacters: + // arg = arg.replace( /([()\][%!^"`<>&|;, *?])/g, '^$1' ); + // } + + return arg; +} + +// + +function _argProgEscape( prog ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.strIs( prog ) ); + + // Windows cmd.exe: needs special treatment + if( process.platform === 'win32' ) + { + // Escape shell metacharacters: + prog = prog.replace( /([()\][%!^"`<>&|;, *?])/g, '^$1' ); + } + else + { + // Unix shells: same procedure as for arguments + prog = _.process._argEscape2( prog ); + } + + return prog; +} + + +// + +function _argCmdEscape( prog, args ) +{ + _.assert( arguments.length === 2 ); + _.assert( _.strIs( prog ) ); + _.assert( _.arrayIs( args ) ); + + prog = _.process._argProgEscape( prog ); + + if( !args.length ) + return prog; + + args = args.map( ( arg ) => _.process._argEscape2( arg ) ); + + return `${prog} ${args.join( ' ' )}`; +} + +// -- +// meta +// -- + +function _Setup1() +{ + if( _.path && _.path.current ) + this._initialCurrentPathGet = _initialCurrentPathGet_functor(); + this._initialCurrentPathGet.functor = _initialCurrentPathGet_functor; + + _.process._eventAvailableHandle(); + _.process._exitHandlerRepair(); + _.process._eventsSetup(); + + /* */ + + function _initialCurrentPathGet_functor() + { + const currentPath = _.path.current(); + return () => currentPath; + } +} + +// -- +// declare +// -- + +let Events = +{ + available : [], + exit : [], + exitBefore : [], +} + +let Extension = +{ + + // etc + + isNativeDescriptor, + isSession, + pidFrom, + + // temp + + tempOpen, + tempClose, + + // eventer + + on, + _eventAvailableHandle, + + // event + + _exitHandlerRepair, + _eventsSetup, + _eventExitHandle, + _eventExitBeforeHandle, + + // exit + + exitReason, + exitCode, + exit, + exitWithBeep, + + // args + + _argsForm, + _argUnqoute, + _argsUnqoute, + + // escape + + _argsEscape, + _argEscape, + _argEscape2, + _argProgEscape, + _argCmdEscape, + + // meta + + _Setup1, + + // fields + + _verbosity : 1, + _sanitareTime : 1, + _exitReason : null, + exiting : false, + + _tempFiles, + _registeredExitHandler : null, + _registeredExitBeforeHandler : null, + _initialCurrentPathGet : null, + +} + +Object.assign( _.process, Extension ); +_.props.supplement( _.process._edispatcher.events, Events ); +_.assert( !_.process.start ); +_.process._Setup1(); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/l1/Basic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Basic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Basic_s */ })(); + +/* */ /* begin of file Process_s */ ( function Process_s() { function Process_s_naked() { ( function _Process_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +const Self = _.process = _.process || Object.create( null ); + +_.assert( !!_realGlobal_ ); + +// -- +// dichotomy +// -- + +let ProcessMinimalInput = _.Blueprint +({ + typed : _.trait.typed( true ), + + execPath : null, + currentPath : null, + args : null, + interpreterArgs : null, + passingThrough : 0, + + sync : 0, + deasync : 0, + when : 'instant', /* instant / afterdeath / time / delay */ + dry : 0, + + mode : 'shell', /* fork / spawn / shell */ + stdio : 'pipe', /* pipe / ignore / inherit */ + ipc : null, + + logger : null, + procedure : null, + stack : null, + sessionId : 0, + + ready : null, + conStart : null, + conTerminate : null, + conDisconnect : null, + + env : null, + detaching : 0, + hiding : 1, + uid : null, + gid : null, + streamSizeLimit : null, + timeOut : null, + + throwingExitCode : 'full', /* [ bool-like, 'full', 'brief' ] */ /* must be on by default */ /* qqq for junior : cover */ + applyingExitCode : 0, + + verbosity : 2, + outputPrefixing : 0, + outputPiping : null, + outputCollecting : 0, + outputAdditive : null, /* qqq for junior : cover the option */ + outputColoring : 1, + outputGraying : 0, + inputMirroring : 1, + +}); + +let ProcessMinimal = _.Blueprint +({ + inherit : _.define.inherit( ProcessMinimalInput ), + + disconnect : null, + _end : null, + state : null, /* `initial`, `starting`, `started`, `terminating`, `terminated`, `disconnected` */ + exitReason : null, + exitCode : null, + exitSignal : null, + error : null, + args2 : null, + pnd : null, + execPath2 : null, + output : null, + ended : false, + _handleProcedureTerminationBegin : false, + streamOut : null, + streamErr : null, + +}); + +let ProcessMultipleInput = _.Blueprint +({ + // xxx + // inherit : _.define.inherit( ProcessMinimalInput ), + // but : _.define.but( 'sessionId' ), + + typed : _.trait.typed( true ), + + execPath : null, + currentPath : null, + args : null, + interpreterArgs : null, + passingThrough : 0, + + sync : 0, + deasync : 0, + when : 'instant', /* instant / afterdeath / time / delay */ + dry : 0, + + mode : 'shell', /* fork / spawn / shell */ + stdio : 'pipe', /* pipe / ignore / inherit */ + ipc : null, + + logger : null, + procedure : null, + stack : null, + + ready : null, + conStart : null, + conTerminate : null, + conDisconnect : null, + + env : null, + detaching : 0, + hiding : 1, + uid : null, + gid : null, + streamSizeLimit : null, + timeOut : null, + + throwingExitCode : 'full', /* [ bool-like, 'full', 'brief' ] */ /* must be on by default */ /* qqq for junior : cover */ + applyingExitCode : 0, + + verbosity : 2, + outputPrefixing : 0, + outputPiping : null, + outputCollecting : 0, + outputAdditive : null, /* qqq for junior : cover the option */ + outputColoring : 1, + outputGraying : 0, + inputMirroring : 1, + +}); + +let ProcessMultiple = _.Blueprint +({ + inherit : _.define.inherit( ProcessMultipleInput ), + + sessions : null, + state : null, + exitReason : null, + exitCode : null, + exitSignal : null, + error : null, + output : null, + ended : null, + + streamOut : null, + streamErr : null, + +}); + +// -- +// declare +// -- + +let ToolsExtension = +{ + + ProcessMinimalInput, + ProcessMinimal, + + ProcessMultipleInput, + ProcessMultiple, + +} + +_.props.extend( _, ToolsExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/l2/Process.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/l2' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Process_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Process_s */ })(); + +/* */ /* begin of file Execution_s */ ( function Execution_s() { function Execution_s_naked() { ( function _Execution_s_() +{ + +'use strict'; + +let System, ChildProcess, WindowsProcessTree, Stream; +const _global = _global_; +const _ = _global_.wTools; +_.process = _.process || Object.create( null ); + +_.assert( !!_realGlobal_ ); + +// -- +// starter +// -- + +/* Return values of routine start for each combination of options sync and deasync: + + Single process + | Combination | Options map | Consequence | + | ---------------- | ----------- | ----------- | + | sync:0 deasync:0 | + | + | + | sync:1 deasync:1 | + | - | + | sync:0 deasync:1 | + | + | + | sync:1 deasync:0 | + | - | + + Multiple processes + | Combination | Array of maps of options | Single options map | Consequence | + | ---------------- | ------------------------ | ------------------ | ----------- | + | sync:0 deasync:0 | + | - | + | + | sync:1 deasync:1 | + | - | - | + | sync:0 deasync:1 | + | - | + | + | sync:1 deasync:0 | - | + | - | +*/ + +// + +function startMinimalHeadCommon( routine, args ) +{ + let o; + + if( _.strIs( args[ 0 ] ) || _.arrayIs( args[ 0 ] ) ) + o = { execPath : args[ 0 ] }; + else + o = args[ 0 ]; + + o = _.routine.options_( routine, o ); + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1, 'Expects single argument' ); + _.assert( _.longHas( [ 'fork', 'spawn', 'shell' ], o.mode ), `Supports mode::[ 'fork', 'spawn', 'shell' ]. Unknown mode ${o.mode}` ); + _.assert( !!o.args || !!o.execPath, 'Expects {-args-} either {-execPath-}' ) + _.assert + ( + o.args === null || _.arrayIs( o.args ) || _.strIs( o.args ) || _.routineIs( o.args ) + , () => `If defined option::arg should be either [ string, array, routine ], but it is ${_.entity.strType( o.args )}` + ); + + /* timeOut */ + + _.assert + ( + o.timeOut === null || _.numberIs( o.timeOut ), + () => `Expects null or number {-o.timeOut-}, but got ${_.entity.strType( o.timeOut )}` + ); + _.assert + ( + o.timeOut === null || !o.sync || !!o.deasync, `Option::timeOut should not be defined if option::sync:1 and option::deasync:0` + ); + + _.assert + ( + !o.detaching || !_.longHas( _.array.as( o.stdio ), 'inherit' ), + `Unsupported stdio: ${o.stdio} for process detaching. Parent will wait for child process.` /* zzz : check */ + ); + _.assert( !o.detaching || _.longHas( [ 'fork', 'spawn', 'shell' ], o.mode ), `Unsupported mode: ${o.mode} for process detaching` ); + _.assert( o.conStart === null || _.routineIs( o.conStart ) ); + _.assert( o.conTerminate === null || _.routineIs( o.conTerminate ) ); + _.assert( o.conDisconnect === null || _.routineIs( o.conDisconnect ) ); + _.assert( o.ready === null || _.routineIs( o.ready ) ); + _.assert( o.mode !== 'fork' || !o.sync || !!o.deasync, 'Mode::fork is available only if either sync:0 or deasync:1' ); + + if( _.boolLike( o.throwingExitCode ) ) + o.throwingExitCode = o.throwingExitCode ? 'full' : false; + _.assert + ( + _.longHasAny( [ false, 'full', 'brief' ], o.throwingExitCode ) + , `Unknown value of option::throwingExitCode, acceptable : [ false, 'full', 'brief' ]` + ); + + if( o.outputColoring === null || _.boolLikeTrue( o.outputColoring ) ) + o.outputColoring = { out : 1, err : 1 }; + if( _.boolLikeFalse( o.outputColoring ) ) + o.outputColoring = { out : 0, err : 0 }; + _.assert( _.object.isBasic( o.outputColoring ) ); + _.assert + ( + _.boolLike( o.outputColoring.out ), + `o.outputColoring.out expects BoolLike, but got ${o.outputColoring.out}` + ); + _.assert + ( + _.boolLike( o.outputColoring.err ), + `o.outputColoring.err expects BoolLike, but got ${o.outputColoring.err}` + ); + + if( !_.numberIs( o.verbosity ) ) + o.verbosity = o.verbosity ? 1 : 0; + if( o.verbosity < 0 ) + o.verbosity = 0; + if( o.outputPiping === null ) + { + if( o.stdio === 'pipe' || o.stdio[ 1 ] === 'pipe' ) + o.outputPiping = o.verbosity >= 2; + } + o.outputPiping = !!o.outputPiping; + _.assert( _.numberIs( o.verbosity ) ); + _.assert( _.boolLike( o.outputPiping ) ); + _.assert( _.boolLike( o.outputCollecting ) ); + + if( Config.debug ) + if( o.outputPiping || o.outputCollecting ) + _.assert + ( + o.stdio === 'pipe' || o.stdio[ 1 ] === 'pipe' || o.stdio[ 2 ] === 'pipe' + , '"stdout" is not available to collect output or pipe it. Set stdout/stderr channel(s) or option::stdio to "pipe", please' + ); + + if( o.outputAdditive === null ) + o.outputAdditive = true; /* yyy */ + o.outputAdditive = !!o.outputAdditive; + _.assert( _.boolLike( o.outputAdditive ) ); + + if( o.ipc === null ) + o.ipc = o.mode === 'fork'; + _.assert( _.boolLike( o.ipc ) ); + + if( _.strIs( o.stdio ) ) + o.stdio = _.dup( o.stdio, 3 ); + if( o.ipc ) + { + if( !_.longHas( o.stdio, 'ipc' ) ) + o.stdio.push( 'ipc' ); + } + + _.assert( _.longIs( o.stdio ) ); + _.assert( !o.ipc || _.longHas( [ 'fork', 'spawn' ], o.mode ), `Mode::${o.mode} doesn't support inter process communication.` ); + _.assert( o.mode !== 'fork' || !!o.ipc, `In mode::fork option::ipc must be true. Such subprocess can not have no ipc.` ); + + if( _.strIs( o.interpreterArgs ) ) + o.interpreterArgs = _.strSplitNonPreserving({ src : o.interpreterArgs }); + _.assert( o.interpreterArgs === null || _.arrayIs( o.interpreterArgs ) ); + + _.assert + ( + ( _.numberIs( o.streamSizeLimit ) && o.streamSizeLimit > 0 ) || o.streamSizeLimit === null, + 'Option::streamSizeLimit must be a positive Number which is greater than zero' + ) + + if( o.streamSizeLimit !== null ) + _.assert + ( + o.sync && ( o.mode === 'spawn' || o.mode === 'shell' ), + 'Option::streamSizeLimit is supported in mode::spawn and mode::shell with sync::1' + ) + + return o; +} + +// + +function startMinimal_head( routine, args ) +{ + let o = startMinimalHeadCommon( routine, args ); + + _.assert( arguments.length === 2 ); + + _.assert( _.longHas( [ 'instant' ], o.when ) || _.object.isBasic( o.when ), `Unsupported starting mode: ${o.when}` ); + + _.assert + ( + o.execPath === null || _.strIs( o.execPath ) + , () => `Expects string or strings {-o.execPath-}, but got ${_.entity.strType( o.execPath )}` + ); + + _.assert + ( + o.currentPath === null || _.strIs( o.currentPath ) + , () => `Expects string or strings {-o.currentPath-}, but got ${_.entity.strType( o.currentPath )}` + ); + + return o; +} + +// + +function startMinimal_body( o ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + + /* qqq for junior : use buffer instead */ + let _errOutput = ''; + let _decoratedOutOutput = ''; + let _outAdditive = ''; + let _decoratedErrOutput = ''; + let _errAdditive = ''; + let _errPrefix = null; + let _outPrefix = null; + let _readyCallback; + + form1(); + form2(); + + return run1(); + + /* subroutines : + + form1, + form2, + form3, + run1, + run2, + run3, + runFork, + runSpawn, + runShell, + end1, + end2, + end3, + + handleClose, + handleExit, + handleError, + handleDisconnect, + disconnect, + timeOutForm, + pipe, + inputMirror, + argsForm, + optionsForSpawn, + optionsForFork, + execPathForFork, + _handleProcedureTerminationBegin, + exitCodeSet, + infoGet, + handleStreamOutput, + log, + +*/ + + /* */ + + function form1() + { + + if( o.ready === null ) + { + o.ready = new _.Consequence().take( null ); + } + else if( !_.consequenceIs( o.ready ) ) + { + _readyCallback = o.ready; + _.assert( _.routineIs( _readyCallback ) ); + o.ready = new _.Consequence().take( null ); + } + + _.assert( !_.consequenceIs( o.ready ) || o.ready.resourcesCount() <= 1 ); + + /* procedure */ + + if( o.procedure === null || _.boolLikeTrue( o.procedure ) ) /* xxx : qqq : for junior : bad | aaa : fixed. */ + o.stack = _.Procedure.Stack( o.stack, 4 ); /* delta : 4 to not include info about `routine.unite` in the stack */ + + } + + /* */ + + function form2() + { + + o.logger = o.logger || _global.logger; + + /* consequences */ + + if( o.conStart === null ) + { + o.conStart = new _.Consequence(); + } + else if( !_.consequenceIs( o.conStart ) ) + { + o.conStart = new _.Consequence().finally( o.conStart ); + } + + if( o.conTerminate === null ) + { + o.conTerminate = new _.Consequence(); + } + else if( !_.consequenceIs( o.conTerminate ) ) + { + o.conTerminate = new _.Consequence({ _procedure : false }).finally( o.conTerminate ); + } + + if( o.conDisconnect === null ) + { + o.conDisconnect = new _.Consequence(); + } + else if( !_.consequenceIs( o.conDisconnect ) ) + { + o.conDisconnect = new _.Consequence({ _procedure : false }).finally( o.conDisconnect ); + } + + _.assert( o.conStart !== o.conTerminate ); + _.assert( o.conStart !== o.conDisconnect ); + _.assert( o.conTerminate !== o.conDisconnect ); + _.assert( o.ready !== o.conStart && o.ready !== o.conDisconnect && o.ready !== o.conTerminate ); + _.assert( o.conStart.resourcesCount() === 0 ); + _.assert( o.conDisconnect.resourcesCount() === 0 ); + _.assert( o.conTerminate.resourcesCount() === 0 ); + + /* output */ + + _.assert( _.object.isBasic( o.outputColoring ) ); + _.assert( _.boolLike( o.outputCollecting ) ); + + /* ipc */ + + _.assert( _.boolLike( o.ipc ) ); + _.assert( _.longIs( o.stdio ) ); + _.assert( !o.ipc || _.longHas( [ 'fork', 'spawn' ], o.mode ), `Mode::${o.mode} doesn't support inter process communication.` ); + _.assert( o.mode !== 'fork' || !!o.ipc, `In mode::fork option::ipc must be true. Such subprocess can not have no ipc.` ); + + /* etc */ + + _.assert( !_.arrayIs( o.execPath ) && !_.arrayIs( o.currentPath ) ); + + /* */ + + if( !_.strIs( o.when ) ) + { + if( Config.debug ) + { + let keys = _.props.keys( o.when ); + _.assert( _.mapIs( o.when ) ); + _.assert( keys.length === 1 && _.longHas( [ 'time', 'delay' ], keys[ 0 ] ) ); + _.assert( _.numberIs( o.when.delay ) || _.numberIs( o.when.time ) ) + } + if( o.when.time !== undefined ) + o.when.delay = Math.max( 0, o.when.time - _.time.now() ); + _.assert + ( + o.when.delay >= 0, + `Wrong value of {-o.when.delay } or {-o.when.time-}. Starting delay should be >= 0, current : ${o.when.delay}` + ); + } + + /* */ + + // xxx + // _.assert( _.mapIs( o ) ); + // let o3 = _.ProcessMinimal.Retype( o ); + // _.assert( o3 === o ); + // _.assert( !Object.isExtensible( o ) ); + + /* */ + + o.disconnect = disconnect; + o._end = end3; + o.state = 'initial'; /* `initial`, `starting`, `started`, `terminating`, `terminated`, `disconnected` */ + o.exitReason = null; + o.exitCode = null; + o.exitSignal = null; + o.error = o.error || null; + o.args2 = null; + o.pnd = null; + o.execPath2 = null; + o.output = o.outputCollecting ? '' : null; + o.ended = false; + o._handleProcedureTerminationBegin = false; + o.streamOut = null; + o.streamErr = null; + + Object.preventExtensions( o ); + } + + /* */ + + function form3() + { + + if( o.procedure === null || _.boolLikeTrue( o.procedure ) ) + { + o.procedure = _.Procedure({ _stack : o.stack }); + } + + if( _.routineIs( o.args ) ) + o.args = o.args( o ); + if( o.args === null ) + o.args = []; + + _.assert + ( + _.arrayIs( o.args ) || _.strIs( o.args ) + , () => `If defined option::arg should be either [ string, array ], but it is ${_.entity.strType( o.args )}` + ); + + argsForm(); + + /* */ + + o.currentPath = _.path.resolve( o.currentPath || '.' ); + + _.assert( _.boolLike( o.outputAdditive ) ); + _.assert( _.numberIs( o.verbosity ) ); + _.assert( _.boolLike( o.outputPiping ) ); + _.assert( _.boolLike( o.outputCollecting ) ); + + /* dependencies */ + + if( !ChildProcess ) + ChildProcess = require( 'child_process' ); + + // if( o.outputGraying ) + // if( !StripAnsi ) + // StripAnsi = require( 'strip-ansi' ); + + if( o.outputColoring.err || o.outputColoring.out && typeof module !== 'undefined' ) + try + { + _.include( 'wColor' ); + } + catch( err ) + { + o.outputColoring.err = 0; + o.outputColoring.out = 0; + if( o.verbosity >= 2 ) + log( _.errOnce( err ), 'err' ); + } + + /* prefixing */ + + if( o.outputPrefixing ) + { + _errPrefix = `${ ( o.outputColoring.err ? _.ct.format( 'err', { fg : 'dark red' } ) : 'err' ) } : `; + _outPrefix = `${ ( o.outputColoring.out ? _.ct.format( 'out', { fg : 'dark white' } ) : 'out' ) } : `; + } + + /* handler of event terminationBegin */ + + if( o.detaching ) + { + let handler = _.procedure.on( 'terminationBegin', _handleProcedureTerminationBegin ); /* zzz : use handler instead of callback */ + o._handleProcedureTerminationBegin = _handleProcedureTerminationBegin; + } + + /* if session already has error, running should not start */ + if( o.error ) + throw o.error; + } + + /* */ + + function run1() + { + + if( o.sync && !o.deasync ) + { + try + { + o.ready.deasync(); + o.ready.thenGive( 1 ); + if( o.when.delay ) + _.time.sleep( o.when.delay ); + run2(); + } + catch( err ) + { + if( !o.ended ) + end2( err ); + throw err; + } + _.assert( o.state === 'terminated' || o.state === 'disconnected' ); + end2( undefined ); + } + else + { + /* qqq for Dmytro : ! */ + // console.log( 'run1', o.ready.exportString() ); + if( o.when.delay ) + o.ready.delay( o.when.delay ); + o.ready.thenGive( run2 ); + } + + return end1(); + } + + /* */ + + function run2() + { + // console.log( 'run2', o.ready.exportString() ); + + try + { + + form3(); + run3(); + timeOutForm(); + pipe(); + disconnectMaybe(); + + /* qqq for Dmytro : ! */ + // console.log( 'run2:1' ); + if( o.dry ) + { + // console.log( 'run2:2' ); + if( o.error ) + handleError( o.error ); + else + handleClose( null, null ); + // console.log( 'run2:3' ); + } + else + { + if( o.sync && !o.deasync ) + { + if( o.pnd.error ) + handleError( o.pnd.error ); + else + handleClose( o.pnd.status, o.pnd.signal ); + } + } + // console.log( 'run2:4' ); + + } + catch( err ) + { + handleError( err ); + } + + } + + /* */ + + function run3() + { + + _.assert( o.state === 'initial' ); + o.state = 'starting'; + + if( Config.debug ) + _.assert + ( + _.fileProvider.resolvedIsDir( o.currentPath ), + () => `Current path ( ${o.currentPath} ) doesn\'t exist or it\'s not a directory.\n> ${o.execPath2}` + ); + + if( o.mode === 'fork') + runFork(); + else if( o.mode === 'spawn' ) + runSpawn(); + else if( o.mode === 'shell' ) + runShell(); + else _.assert( 0, `Unknown mode ${o.mode} to start process at path ${o.currentPath}` ); + + /* procedure */ + + if( o.procedure ) + { + if( o.pnd ) + { + let name = 'PID:' + o.pnd.pid; + if( Config.debug ) + { + let result = _.procedure.find( name ); + _.assert( result.length === 0, `No procedure expected for child process with pid:${o.pnd.pid}` ); + } + o.procedure.name( name ); + } + o.procedure._object = o.pnd; + o.procedure.begin(); + } + + /* state */ + + o.state = 'started'; + + if( o.detaching !== 2 ) + o.conStart.take( o ); + + } + + /* */ + + function runFork() + { + let execPath = o.execPath; + + let o2 = optionsForFork(); + execPath = execPathForFork( execPath ); + + execPath = _.path.nativize( execPath ); + + o.execPath2 = _.strConcat([ execPath, ... o.args2 ]); + inputMirror(); + + if( o.dry ) + return; + + o.pnd = ChildProcess.fork( execPath, o.args2, o2 ); + + } + + /* */ + + function runSpawn() + { + let execPath = o.execPath; + + execPath = _.path.nativizeMinimal( execPath ); + + let o2 = optionsForSpawn(); + + o.execPath2 = _.strConcat([ execPath, ... o.args2 ]); + inputMirror(); + + if( o.dry ) + return; + + if( o.sync && !o.deasync ) + o.pnd = ChildProcess.spawnSync( execPath, o.args2, o2 ); + else + o.pnd = ChildProcess.spawn( execPath, o.args2, o2 ); + + } + + /* */ + + function runShell() + { + let execPath = o.execPath; + + execPath = _.path.nativizeEscaping( execPath ); + /* execPath = _.process._argProgEscape( execPath ); */ + /* zzz for Vova: use this routine, review fails */ + + let shellPath = process.platform === 'win32' ? 'cmd' : 'sh'; + let arg1 = process.platform === 'win32' ? '/c' : '-c'; + let arg2 = execPath; + let o2 = optionsForSpawn(); + + /* + + windowsVerbatimArguments allows to have arguments with space(s) in shell on Windows + Following calls will not work as expected( argument will be splitted by space ), if windowsVerbatimArguments is disabled: + + _.process.start( 'node path/to/script.js "path with space"' ); + _.process.start({ execPath : 'node path/to/script.js', args : [ "path with space" ] }); + + */ + + o2.windowsVerbatimArguments = true; + + if( o.args2.length ) + arg2 = arg2 + ' ' + o.args2.join( ' ' ); + + o.execPath2 = arg2; + + /* zzz for Vova : Fixes problem with space in path on windows and makes behavior similar to unix + Examples: + win: shell({ execPath : '"/path/with space/node.exe"', throwingExitCode : 0 }) - works + unix: shell({ execPath : '"/path/with space/node"', throwingExitCode : 0 }) - works + both: shell({ execPath : 'node -v && node -v', throwingExitCode : 0 }) - prints version twice + both: shell({ execPath : '"node -v && node -v"', throwingExitCode : 0 }) - expected error about unknown command + */ + + if( process.platform === 'win32' ) + arg2 = _.strQuote( arg2 ); + + inputMirror(); + + if( o.dry ) + return; + + if( o.sync && !o.deasync ) + o.pnd = ChildProcess.spawnSync( shellPath, [ arg1, arg2 ], o2 ); + else + o.pnd = ChildProcess.spawn( shellPath, [ arg1, arg2 ], o2 ); + } + + /* */ + + function end1() + { + if( _readyCallback ) + o.ready.finally( _readyCallback ); + if( o.deasync ) + o.ready.deasync(); + if( o.sync ) + return o.ready.sync(); + return o.ready; + } + + /* */ + + function end2( err ) + { + + if( Config.debug ) + try + { + _.assert( o.state === 'terminated' || o.state === 'disconnected' || !!o.error ); + _.assert( o.ended === false ); + } + catch( err2 ) + { + err = err || err2; + } + + if( err ) + o.error = o.error || err; + + return end3(); + } + + /* */ + + function end3() + { + + if( o.procedure ) + if( o.procedure.isAlive() ) + o.procedure.end(); + else + o.procedure.finit(); + + if( o._handleProcedureTerminationBegin ) + { + _.procedure.off( 'terminationBegin', o._handleProcedureTerminationBegin ); + o._handleProcedureTerminationBegin = false; + } + + if( !o.outputAdditive ) + { + if( _decoratedOutOutput ) + o.logger.log( _decoratedOutOutput ); + if( _decoratedErrOutput ) + o.logger.error( _decoratedErrOutput ); + } + + if( o.exitReason === null && o.error ) + o.exitReason = 'error'; + + o.ended = true; + Object.freeze( o ); + + let consequence1 = o.state === 'disconnected' ? o.conDisconnect : o.conTerminate; + let consequence2 = o.state === 'disconnected' ? o.conTerminate : o.conDisconnect; + + if( o.error ) + { + if( o.state === 'initial' || o.state === 'starting' ) + o.conStart.error( o.error ); + consequence1.error( o.error ); + consequence2.error( o.error ); + o.ready.error( o.error ); + if( o.sync && !o.deasync ) + throw _.err( o.error ); + } + else + { + consequence1.take( o ); + consequence2.error( _.dont ); + o.ready.take( o ); + } + + return o; + } + + /* */ + + function handleClose( exitCode, exitSignal ) + { + // /* + // console.log( 'handleClose', _.process.realMainFile(), o.ended, ... arguments ); + // */ + + if( o.outputAdditive && _outAdditive ) + { + o.logger.log( _outAdditive ); + _outAdditive = ''; + } + + if( o.ended ) + return; + + o.state = 'terminated'; + + exitCodeSet( exitCode ); + o.exitSignal = exitSignal; + if( o.pnd && o.pnd.signalCode === undefined ) + o.pnd.signalCode = exitSignal; + + if( o.error ) + throw err; + + if( exitSignal ) + o.exitReason = 'signal'; + else if( exitCode ) + o.exitReason = 'code'; + else if( exitCode === 0 ) + o.exitReason = 'normal'; + + if( o.verbosity >= 5 && o.inputMirroring ) + { + log( ` < Process returned error code ${exitCode}\n`, 'out' ); + if( exitCode ) + log( infoGet(), 'out' ); + } + + if( !o.error && o.throwingExitCode ) + if( exitSignal || exitCode ) /* should be not strict condition to handle properly value null */ + { + if( _.numberIs( exitCode ) ) + o.error = _._err({ args : [ 'Process returned exit code', exitCode, '\n', infoGet() ], reason : 'exit code' }); + else if( o.reason === 'time' ) + o.error = _._err({ args : [ 'Process timed out, killed by exit signal', exitSignal, '\n', infoGet() ], reason : 'time out' }); + else + o.error = _._err({ args : [ 'Process was killed by exit signal', exitSignal, '\n', infoGet() ], reason : 'exit signal' }); + if( o.throwingExitCode === 'brief' ) + o.error = _.errBrief( o.error ); + } + + if( o.error ) + { + end2( o.error ); + } + else if( !o.sync || o.deasync ) + { + end2( undefined ); + } + + } + + /* */ + + function handleExit( exitCode, exitSignal ) + { + /* xxx : use handleExit */ + // /* + // console.log( 'handleExit', _.process.realMainFile(), o.ended, ... arguments ); + // */ + // handleClose( exitCode, exitSignal ); + } + + /* */ + + function handleError( err ) + { + err = _.err + ( + err + , `\nError starting the process` + , `\n Exec path : ${o.execPath2 || o.execPath}` + , `\n Current path : ${o.currentPath}` + ); + + if( o.outputAdditive && _errAdditive ) + { + o.logger.error( _errAdditive ); + _errAdditive = ''; + } + + if( o.ended ) + { + throw err; + } + + exitCodeSet( -1 ); + + o.exitReason = 'error'; + o.error = err; + if( o.verbosity ) + log( _.errOnce( o.error ), 'err' ); + + end2( o.error ); + } + + /* */ + + function handleDisconnect( arg ) + { + /* + console.log( 'handleDisconnect', _.process.realMainFile(), o.ended ); + */ + + /* + event "disconnect" may come just before event "close" + so need to give a chance to event "close" to come first + */ + + /* + if( !o.ended ) + _.time.begin( 1000, () => + { + if( !o.ended ) + { + o.state = 'disconnected'; + o.conDisconnect.take( this ); + end2( undefined ); + throw _.err( 'not tested' ); + } + }); + */ + + /* bad solution + subprocess waits what does not let emit event "close" in parent process + */ + + if( o.detaching === 2 ) + o.conStart.take( o ); + + } + + /* */ + + function disconnect() + { + /* + console.log( 'disconnect', _.process.realMainFile(), this.ended ); + */ + + _.assert( !!this.pnd, 'Process is not started. Cant disconnect.' ); + + /* + close event will not be called for regular/detached process + */ + + if( this.pnd.stdin ) + this.pnd.stdin.end(); + if( this.pnd.stdout ) + this.pnd.stdout.destroy(); + if( this.pnd.stderr ) + this.pnd.stderr.destroy(); + + this.pnd.unref(); + + if( this.pnd.disconnect ) + if( this.pnd.connected ) + this.pnd.disconnect(); + + if( !this.ended ) + { + this.state = 'disconnected'; + end2( undefined ); + } + + return true; + } + + /* */ + + function timeOutForm() + { + + if( o.timeOut && !o.dry ) + if( !o.sync || o.deasync ) + _.time.begin( o.timeOut, () => + { + if( o.state === 'terminated' || o.error ) + return; + o.exitReason = 'time'; + _.process.terminate + ({ + pnd : o.pnd, + withChildren : 1, + ignoringErrorPerm : 1, + }); + }); + + } + + /* */ + + function pipe() + { + if( o.dry ) + return; + + _.assert + ( + ( !o.outputPiping && !o.outputCollecting ) || !!o.pnd.stdout || !!o.pnd.stderr, + 'stdout is not available to collect output or pipe it. Set option::stdio to "pipe"' + ); + + if( _.streamIs( o.pnd.stdout ) ) + o.streamOut = o.pnd.stdout; + if( _.streamIs( o.pnd.stderr ) ) + o.streamErr = o.pnd.stderr; + + /* piping out channel */ + + if( o.outputPiping || o.outputCollecting ) + if( o.pnd.stdout ) + if( o.sync && !o.deasync ) + handleStreamOutput( o.pnd.stdout, 'out' ); + else + o.pnd.stdout.on( 'data', ( data ) => handleStreamOutput( data, 'out' ) ); + + /* piping error channel */ + + /* + there is no if options here because algorithm should collect error output in _errOutput anyway + */ + if( o.pnd.stderr ) + if( o.sync && !o.deasync ) + handleStreamOutput( o.pnd.stderr, 'err' ); + else + o.pnd.stderr.on( 'data', ( data ) => handleStreamOutput( data, 'err' ) ); + + /* handling */ + + if( !o.sync || o.deasync ) + { + o.pnd.on( 'error', handleError ); + o.pnd.on( 'close', handleClose ); + o.pnd.on( 'exit', handleExit ); + o.pnd.on( 'disconnect', handleDisconnect ); + } + + } + + /* */ + + function inputMirror() + { + /* logger */ + try + { + + if( !o.inputMirroring ) + return; + + if( o.verbosity >= 3 ) + { + let output = ' @ '; + if( o.outputColoring.out ) + output = _.ct.format( output, { fg : 'bright white' } ) + _.ct.format( o.currentPath, 'path' ); + else + output = output + o.currentPath + log( output + '\n', 'out' ); + } + + if( o.verbosity ) + { + let prefix = ' > '; + if( o.outputColoring.out ) + prefix = _.ct.format( prefix, { fg : 'bright white' } ); + log( prefix + o.execPath2 + '\n', 'out' ); + } + + } + catch( err ) + { + log( _.errOnce( err ), 'err' ); + } + } + + /* */ + + function argsForm() + { + _.process._argsForm( o ); + } + + /* */ + + function optionsForSpawn() + { + let o2 = Object.create( null ); + if( o.stdio ) + o2.stdio = o.stdio; + o2.detached = !!o.detaching; + if( o.env ) + o2.env = o.env; + if( o.currentPath ) + o2.cwd = _.path.nativize( o.currentPath ); + if( o.timeOut && o.sync ) + o2.timeout = o.timeOut; + o2.windowsHide = !!o.hiding; + if( o.streamSizeLimit ) + o2.maxBuffer = o.streamSizeLimit; + + if( process.platform !== 'win32' ) + { + o2.uid = o.uid; + o2.gid = o.gid; + } + return o2; + } + + /* */ + + function optionsForFork() + { + let o2 = + { + detached : !!o.detaching, + env : o.env, + stdio : o.stdio, + execArgv : o.interpreterArgs || process.execArgv, + } + if( o.currentPath ) + o2.cwd = _.path.nativize( o.currentPath ); + if( process.platform !== 'win32' ) + { + o2.uid = o.uid; + o2.gid = o.gid; + } + return o2; + } + + /* */ + + function execPathForFork( execPath ) + { + return _.process._argUnqoute( execPath ); + } + + /* */ + + function _handleProcedureTerminationBegin() + { + o.disconnect(); + } + + /* */ + + function exitCodeSet( exitCode ) + { + /* + console.log( _.process.realMainFile(), 'exitCodeSet', exitCode ); + */ + if( o.exitCode ) + return; + if( exitCode === null ) + return; + o.exitCode = exitCode; + if( o.pnd ) + if( o.pnd.exitCode === undefined || o.pnd.exitCode === null ) + o.pnd.exitCode = exitCode; + exitCode = _.numberIs( exitCode ) ? exitCode : -1; + if( o.applyingExitCode ) + _.process.exitCode( exitCode ); + } + + /* */ + + function infoGet() + { + let result = ''; + result += `Launched as ${_.strQuote( o.execPath2 )} \n`; + result += `Launched at ${_.strQuote( o.currentPath )} \n`; + if( _errOutput.length ) + result += `\n -> Stderr\n - ${_.strLinesIndentation( _errOutput, ' - ' )} '\n -< Stderr\n`; + return result; + } + + /* */ + + function handleStreamOutput( data, channel ) + { + if( _.bufferNodeIs( data ) ) + data = data.toString( 'utf8' ); + + if( !_.strIs( data ) ) + data = String( data ); + + if( o.outputGraying ) + data = _.ct.stripAnsi( data ); + // data = StripAnsi( data ); + + if( channel === 'err' ) + _errOutput += data; + + // if( Object.isFrozen( o ) ) /* xxx */ + // debugger; + if( o.outputCollecting ) + o.output += data; + + if( !o.outputPiping ) + return; + + /* yyy qqq for junior : cover and complete */ + // data = _.strRemoveEnd( data, '\n' ); + + let splits; + if( o.outputPrefixing || ( channel === 'err' && o.outputColoring.err ) || ( channel === 'out' && o.outputColoring.out ) ) + splits = data.split( '\n' ); + + /* qqq for junior : changed how option outputPrefixing works | aaa : Done. */ + if( o.outputPrefixing ) + { + let prefix = channel === 'err' ? _errPrefix : _outPrefix; + splits = splits.map( ( split, i ) => ( i < splits.length-1 || split.length ) ? prefix + split : split ); + // data = prefix + _.strLinesIndentation( data, prefix ); + } + + if( channel === 'err' ) + { + if( o.outputColoring.err ) + splits = splits.map( ( data ) => data ? _.ct.format( data, 'pipe.negative' ) : data ); + // data = _.ct.format( data, 'pipe.negative' ); + } + else if( channel === 'out' ) + { + if( o.outputColoring.out ) + splits = splits.map( ( data ) => data ? _.ct.format( data, 'pipe.neutral' ) : data ); + // data = _.ct.format( data, 'pipe.neutral' ); + } + else _.assert( 0 ); + + if( splits !== undefined ) + data = splits.join( '\n' ) + + log( data, channel ); + } + + /* */ + + function log( msg, channel ) + { + _.assert( channel === 'err' || channel === 'out' ); + + if( msg === undefined ) + return; + + if( !_.strIs( msg ) ) + { + msg = String( msg ); + if( !_.strEnds( msg, '\n' ) ) + msg = msg + '\n'; + } + + if( o.outputAdditive ) + { + + if( _.strEnds( msg, '\n' ) ) + { + // msg = _.strRemoveEnd( msg, '\n' ); + if( channel === 'err' ) + { + msg = _errAdditive + _.strRemoveEnd( msg, '\n' ); + _errAdditive = ''; + } + else + { + msg = _outAdditive + _.strRemoveEnd( msg, '\n' ); + _outAdditive = ''; + } + } + else + { + /* xxx yyy qqq for junior : not implemeted yet | aaa : Implemented. */ + if( _.strHas( msg, '\n' ) ) + { + let lastBreak = msg.lastIndexOf( '\n' ); + let left = msg.slice( lastBreak + 1 ); + msg = msg.slice( 0, lastBreak ); + if( channel === 'err' ) + _errAdditive += left; + else + _outAdditive += left; + } + else + { + if( channel === 'err' ) + _errAdditive += msg; + else + _outAdditive += msg; + return; + } + // if( !_.strHas( msg, '\n' ) ) + // { + // if( channel === 'err' ) + // _errAdditive += msg; + // else + // _outAdditive += msg; + // return; + // } + // else + // { + // let lastBreak = msg.lastIndexOf( '\n' ); + // let left = msg.slice( lastBreak + 1 ); + // msg = msg.slice( 0, lastBreak ); + // if( channel === 'err' ) + // _errAdditive += left; + // else + // _outAdditive += left; + // } + } + /* qqq : for junior : bad : it cant be working */ + if( channel === 'err' ) + o.logger.error( msg ); + else + o.logger.log( msg ); + } + else + { + _decoratedOutOutput += msg; + if( channel === 'err' ) + _decoratedErrOutput += msg; + /* yyy qqq for junior : cover */ + // _decoratedOutOutput += msg + '\n'; + // if( channel === 'err' ) + // _decoratedErrOutput += msg + '\n'; + } + + } + + /* */ + + function disconnectMaybe() + { + if( o.detaching === 2 ) + o.disconnect(); + } + +} + +startMinimal_body.defaults = +{ + + execPath : null, + currentPath : null, + args : null, + interpreterArgs : null, + passingThrough : 0, + + sync : 0, + deasync : 0, + when : 'instant', /* instant / afterdeath / time / delay */ + dry : 0, + + mode : 'shell', /* fork / spawn / shell */ + stdio : 'pipe', /* pipe / ignore / inherit */ + ipc : null, + + logger : null, + procedure : null, + stack : null, + sessionId : 0, + + ready : null, + conStart : null, + conTerminate : null, + conDisconnect : null, + + env : null, + detaching : 0, + hiding : 1, + uid : null, + gid : null, + streamSizeLimit : null, + timeOut : null, + + throwingExitCode : 'full', /* [ bool-like, 'full', 'brief' ] */ /* must be on by default */ /* qqq for junior : cover | aaa : Done. */ + applyingExitCode : 0, + + verbosity : 2, + outputPrefixing : 0, + outputPiping : null, + outputCollecting : 0, + outputAdditive : null, /* qqq for junior : cover the option | aaa : Done. */ + outputColoring : 1, + outputGraying : 0, + inputMirroring : 1, + +} + +/* xxx : move advanced options to _.process.startSingle() */ + +let startMinimal = _.routine.uniteCloning_replaceByUnite( startMinimal_head, startMinimal_body ); + +// + +function startSingle_head( routine, args ) +{ + let o = startMinimalHeadCommon( routine, args ); + + _.assert( arguments.length === 2 ); + + _.assert( _.longHas( [ 'instant', 'afterdeath' ], o.when ) || _.object.isBasic( o.when ), `Unsupported starting mode: ${o.when}` ); + + return o; +} + +// + +function startSingle_body( o ) +{ + let _readyCallback; + + if( o.when === 'afterdeath' ) + formAfterDeath(); + + /* */ + + form1(); + + let result = _.process.startMinimal.body.call( _.process, o ); + + if( o.when === 'afterdeath' ) + runAfterDeath(); + + return result; + + /* subroutines : + + form1, + run2, + end1, + +*/ + + function form1() + { + + if( o.ready === null ) + { + o.ready = new _.Consequence().take( null ); + } + else if( !_.consequenceIs( o.ready ) ) + { + _readyCallback = o.ready; + _.assert( _.routineIs( _readyCallback ) ); + o.ready = new _.Consequence().take( null ); + } + + _.assert( !_.consequenceIs( o.ready ) || o.ready.resourcesCount() <= 1 ); + + /* procedure */ + + if( o.procedure === null || _.boolLikeTrue( o.procedure ) ) + o.stack = _.Procedure.Stack( o.stack, 4 ); /* delta : 4 to not include info about `routine.unite` in the stack */ + + } + + /* */ + + function run1() + { + + if( o.sync && !o.deasync ) + { + try + { + o.ready.deasync(); + o.ready.thenGive( 1 ); + if( o.when.delay ) + _.time.sleep( o.when.delay ); + run2(); + } + catch( err ) + { + err = _.err( err ); + if( !o.ended ) + { + o.error = o.error || err; + o._end(); + } + throw err; + } + _.assert( o.state === 'terminated' || o.state === 'disconnected' ); + o._end(); + } + else + { + if( o.when.delay ) + o.ready.delay( o.when.delay ); + o.ready.thenGive( run2 ); + } + + return end1(); + } + + /* */ + + function run2() + { + return _.process.startMinimal.body.call( _.process, o ); + } + + /* */ + + function end1() + { + if( _readyCallback ) + o.ready.finally( _readyCallback ); + if( o.deasync ) + o.ready.deasync(); + if( o.sync ) + return o.ready.sync(); + return o.ready; + } + + /* */ + + function formAfterDeath() + { + let toolsPath = _.path.nativize( _.path.join( __dirname, '../../../../node_modules/Tools' ) ); + let excludeOptions = + { + ready : null, + conStart : null, + conTerminate : null, + conDisconnect : null, + logger : null, + procedure : null, + when : null, + sessionId : null + } + let locals = { toolsPath, o : _.mapBut_( null, o, excludeOptions ), parentPid : process.pid }; + let secondaryProcessRoutine = _.program.preform({ entry : afterDeathSecondaryProcess, locals }) + let secondaryFilePath = _.process.tempOpen({ routineCode : secondaryProcessRoutine.entry.routineCode }); + + o.execPath = _.path.nativize( secondaryFilePath ); + o.mode = 'fork'; + o.ipc = true; + o.args = []; + o.detaching = true; + o.stdio = _.dup( 'ignore', 3 ); + o.stdio.push( 'ipc' ); + o.inputMirroring = 0; + o.outputPiping = 0; + o.outputCollecting = 0; + + } + + /* */ + + function afterDeathSecondaryProcess() + { + const _ = require( toolsPath ); + _.include( 'wProcess' ); + _.include( 'wFilesBasic' ); + // let ipc = require( ipcPath ); + + let ready = _.Consequence(); + let terminated = false; + + waitForParent( 1000 ); + + // setupIpc(); + + ready.then( () => + { + // if( ipc.server.stop ) + // ipc.server.stop(); + + return _.process.startMultiple( o ); + }) + + process.send( 'ready' ); + + /* */ + + function waitForParent( period ) + { + return _.time.periodic( period, () => + { + if( terminated ) + return; + if( _.process.isAlive( parentPid ) ) + return true; + ready.take( true ) + terminated = true; + }) + } + + // function setupIpc() + // { + // ipc.config.id = 'afterdeath.' + process.pid; + // ipc.config.retry= 1500; + // ipc.config.silent = true; + // ipc.serve( () => + // { + // ipc.server.on( 'exit', () => + // { + // waitForParent( 150 ); + // }); + // }); + + // ipc.server.start(); + + // process.send( ipc.config.id ) + // } + + } + + /* */ + + function runAfterDeath() + { + o.conStart.then( ( op ) => + { + let disconnected = _.Consequence(); + + o.pnd.on( 'message', () => + { + o.pnd.on( 'disconnect', () => disconnected.take( op ) ); + o.disconnect(); + }) + + return disconnected; + + // let ipc = require( 'node-ipc' ); + + // o.pnd.on( 'message', ( ipcHostId ) => + // { + // o.disconnect(); + + // ipc.config.id = 'afterdeath.parent:' + process.pid; + // ipc.config.retry = 1500; + // ipc.config.silent = true; + + // _.process.on( 'exit', () => + // { + // ipc.connectTo( ipcHostId, () => + // { + // ipc.of[ ipcHostId ].emit( 'exit', true ); + // ipc.disconnect( ipcHostId ); + // }); + // }) + // }) + }) + } + +} + +startSingle_body.defaults = +{ + + ... _.mapBut_( null, startMinimal.defaults, [ 'onStart', 'onTerminate', 'onDisconnect' ] ), + + when : 'instant', + + ready : null, + conStart : null, + conTerminate : null, + conDisconnect : null, + +} + +let startSingle = _.routine.uniteCloning_replaceByUnite( startSingle_head, startSingle_body ); + +// + +function startMultiple_head( routine, args ) +{ + let o = startMinimalHeadCommon( routine, args ); + + _.assert( arguments.length === 2 ); + + _.assert( _.longHas( [ 'instant', 'afterdeath' ], o.when ) || _.object.isBasic( o.when ), `Unsupported starting mode: ${o.when}` ); + _.assert + ( + !o.concurrent || !o.sync || !!o.deasync + , () => `option::concurrent should be 0 if sync:1 and deasync:0` + ); + _.assert + ( + o.execPath === null || _.strIs( o.execPath ) || _.strsAreAll( o.execPath ) + , () => `Expects string or strings {-o.execPath-}, but got ${_.entity.strType( o.execPath )}` + ); + _.assert + ( + o.currentPath === null || _.strIs( o.currentPath ) || _.strsAreAll( o.currentPath ) + , () => `Expects string or strings {-o.currentPath-}, but got ${_.entity.strType( o.currentPath )}` + ); + + return o; +} + +// + +/** + * @summary Executes command in a controled child process. + * + * @param {Object} o Options map + * @param {String} o.execPath Command to execute, path to application, etc. + * @param {String} o.currentPath Current working directory of child process. + + * @param {Boolean} o.sync=0 Execute command in synchronous mode. + There are two synchrounous modes: first uses sync method of `ChildProcess` module , second uses async method, but in combination with {@link https://www.npmjs.com/package/deasync deasync} and `wConsequence` to turn async execution into synchrounous. + Which sync mode will be selected depends on value of `o.deasync` option. + Sync mode returns options map. + Async mode returns instance of {@link module:Tools/base/Consequence.Consequence wConsequence} with gives a message( options map ) when execution of child process is finished. + * @param {Boolean} o.deasync=1 Controls usage of `deasync` module in synchrounous mode. Allows to run command synchrounously in modes( o.mode ) that don't support synchrounous execution, like `fork`. + + * @param {Array} o.args=null Arguments for command. + * @param {Array} o.interpreterArgs=null Arguments for node. Used only in `fork` mode. {@link https://nodejs.org/api/cli.html Command Line Options} + * @param {String} o.mode='shell' Execution mode. Possible values: `fork`, `spawn`, `shell`. {@link https://nodejs.org/api/child_process.html Details about modes} + * @param {Object} o.ready=null `wConsequence` instance that gives a message when execution is finished. + * @param {Object} o.logger=null `wLogger` instance that prints output during command execution. + + * @param {Object} o.env=null Environment variables( key-value pairs ). + * @param {String/Array} o.stdio='pipe' Controls stdin,stdout configuration. {@link https://nodejs.org/api/child_process.html#child_process_options_stdio Details} + * @param {Boolean} o.ipc=0 Creates `ipc` channel between parent and child processes. + * @param {Boolean} o.detaching=0 Creates independent process for a child. Allows child process to continue execution when parent process exits. Platform dependent option. {@link https://nodejs.org/api/child_process.html#child_process_options_detached Details}. + * @param {Boolean} o.hiding=1 Hide the child process console window that would normally be created on Windows. {@link https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options Details}. + * @param {Boolean} o.passingThrough=0 Allows to pass arguments of parent process to the child process. + * @param {Boolean} o.concurrent=0 Allows paralel execution of several child processes. By default executes commands one by one. + * @param {Number} o.timeOut=null Time in milliseconds before execution will be terminated. + + * @param {Boolean} o.throwingExitCode='full' Throws an Error if child process returns non-zero exit code. Child returns non-zero exit code if it was terminated by parent, timeOut or when internal error occurs. + + * @param {Boolean} o.applyingExitCode=0 Applies exit code to parent process. + + * @param {Number} o.verbosity=2 Controls amount of output, `0` disables output at all. + * @param {Boolean|Object} o.outputColoring=1 Logger prints with styles applied for both channels. + * Option can be specified more precisely via map of the form { out : 1, err : 0 } + * Coloring is applied to a corresponding channel. + * @param {Boolean} o.outputPrefixing=0 Add prefix with name of output channel( stderr, stdout ) to each line. + * @param {Boolean} o.outputPiping=null Handles output from `stdout` and `stderr` channels. Is enabled by default if `o.verbosity` levels is >= 2 and option is not specified explicitly. This option is required by other "output" options that allows output customization. + * @param {Boolean} o.outputCollecting=0 Enables coullection of output into sinle string. Collects output into `o.output` property if enabled. + * @param {Boolean} o.outputAdditive=null Prints output during execution. Enabled by default if shell executes only single command and option is not specified explicitly. + * @param {Boolean} o.inputMirroring=1 Print complete input line before execution: path to command, arguments. + * + * @return {Object} Returns `wConsequence` instance in async mode. In sync mode returns options map. Options map contains not only input options, but child process descriptor, collected output, exit code and other useful info. + * + * @example //short way, command and arguments in one string + * + * const _ = require( 'wTools' ) + * _.include( 'wProcessBasic' ) + * _.include( 'wConsequence' ) + * _.include( 'wLogger' ) + * + * let con = _.process.startMultiple( 'node -v' ); + * + * con.then( ( op ) => + * { + * console.log( 'ExitCode:', op.exitCode ); + * return op; + * }) + * + * @example //command and arguments as options + * + * const _ = require( 'wTools' ) + * _.include( 'wProcessBasic' ) + * _.include( 'wConsequence' ) + * _.include( 'wLogger' ) + * + * let con = _.process.startMultiple({ execPath : 'node', args : [ '-v' ] }); + * + * con.then( ( op ) => + * { + * console.log( 'ExitCode:', op.exitCode ); + * return op; + * }) + * + * @function startMultiple + * @module Tools/base/ProcessBasic + * @namespace Tools.process + */ + +function startMultiple_body( o ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + + let _processPipeCounter = 0; + let _readyCallback; + + form0(); + + if( _.arrayIs( o.execPath ) || _.arrayIs( o.currentPath ) ) + return run1(); + + return _.process.startSingle.body.call( this, o ); + + /* subroutines index : + + form0, + form1, + form2, + run1, + run2, + end1, + end2, + + formStreams, + processPipe, + streamPipe, + handleStreamOut, + +*/ + + /* */ + + function form0() + { + if( o.procedure === null || _.boolLikeTrue( o.procedure ) ) /* xxx : qqq : for junior : bad | aaa : fixed. */ + o.stack = _.Procedure.Stack( o.stack, 4 ); /* delta : 4 to not include info about `routine.unite` in the stack */ + } + + /* */ + + function form1() + { + + if( o.ready === null ) + { + o.ready = new _.Consequence().take( null ); + } + else if( !_.consequenceIs( o.ready ) ) + { + _readyCallback = o.ready; + _.assert( _.routineIs( _readyCallback ) ); + o.ready = new _.Consequence().take( null ); + } + + _.assert( !_.consequenceIs( o.ready ) || o.ready.resourcesCount() <= 1 ); + + o.logger = o.logger || _global.logger; + + } + + /* */ + + function form2() + { + + if( o.conStart === null ) + { + o.conStart = new _.Consequence(); + } + else if( !_.consequenceIs( o.conStart ) ) + { + o.conStart = new _.Consequence().finally( o.conStart ); + } + + if( o.conTerminate === null ) + { + o.conTerminate = new _.Consequence(); + } + else if( !_.consequenceIs( o.conTerminate ) ) + { + o.conTerminate = new _.Consequence({ _procedure : false }).finally( o.conTerminate ); + } + + _.assert( _.object.isBasic( o.outputColoring ) ); + _.assert( _.boolLike( o.outputCollecting ) ); + + if( o.outputAdditive === null ) + o.outputAdditive = _.arrayIs( o.execPath ) && o.execPath.length > 1 && o.concurrent; + _.assert( _.boolLike( o.outputAdditive ) ); + o.currentPath = o.currentPath || _.path.current(); + + // xxx + // _.assert( _.mapIs( o ) ); + // let o3 = _.ProcessMultiple.Retype( o ); + // _.assert( o3 === o ); + // _.assert( !Object.isExtensible( o ) ); + + o.sessions = []; + o.state = 'initial'; /* `initial`, `starting`, `started`, `terminating`, `terminated`, `disconnected` */ + o.exitReason = null; + o.exitCode = null; + o.exitSignal = null; + o.error = o.error || null; + o.output = o.outputCollecting ? '' : null; + o.ended = false; + + o.streamOut = null; + o.streamErr = null + + Object.preventExtensions( o ); + + } + + /* */ + + function run1() + { + + try + { + + form1(); + form2(); + + if( o.stdio[ 1 ] !== 'ignore' || o.stdio[ 2 ] !== 'ignore' ) + formStreams(); + + if( o.procedure === null || _.boolLikeTrue( o.procedure ) ) + { + o.procedure = _.procedure.begin({ _object : o, _stack : o.stack }); + } + else if( o.procedure ) + { + if( !o.procedure.isAlive() ) + o.procedure.begin(); + } + + if( o.sync && !o.deasync ) + o.ready.deasync(); + + } + catch( err ) + { + err = _.err( err ); + end2( err, undefined ); + } + + o.ready + .then( run2 ) + .finally( end2 ); + + return end1(); + } + + /* */ + + function run2() + { + let execPath = _.array.as( o.execPath ); + let currentPath = _.array.as( o.currentPath ); + let sessionId = 0; + + for( let p = 0 ; p < execPath.length ; p++ ) + for( let c = 0 ; c < currentPath.length ; c++ ) + { + let currentReady = new _.Consequence(); + sessionId += 1; + let o2 = _.props.extend( null, o ); + o2.conStart = null; + o2.conTerminate = null; + o2.conDisconnect = null; + o2.execPath = execPath[ p ]; + o2.args = _.arrayIs( o.args ) ? o.args.slice() : o.args; + o2.currentPath = currentPath[ c ]; + o2.ready = currentReady; + o2.sessionId = sessionId; + delete o2.sessions; + delete o2.output; + delete o2.exitReason; + delete o2.exitCode; + delete o2.exitSignal; + delete o2.error; + delete o2.ended; + delete o2.concurrent; + delete o2.state; + + if( o.procedure ) + o2.procedure = _.Procedure({ _stack : o.stack }); + + if( o.deasync ) + { + o2.deasync = 0; + o2.sync = 0; + } + + o.sessions.push( o2 ); + } + + /* xxx : introduce concurrent.limit */ + /* xxx qqq : cover sessionsRun */ + + let o2; + if( o.sessions.length ) /* Dmytro : for empty sessions creates procedure that never ended. In new PR added assertion for it */ + { + o2 = _.sessionsRun + ({ + concurrent : o.concurrent, + sessions : o.sessions, + conBeginName : 'conStart', + conEndName : 'conTerminate', + readyName : 'ready', + onRun : ( session ) => + { + _.map.assertHasAll( session, _.process.startSingle.defaults ); + _.process.startSingle.body.call( _.process, session ); + if( !o.dry ) + if( o.streamOut || o.streamErr ) + processPipe( session ); + }, + onBegin : ( err, o2 ) => + { + if( !o.ended ) + o.state = o.concurrent ? 'started' : 'starting'; + o.conStart.take( err, err ? undefined : o ); + }, + onEnd : ( err, o2 ) => + { + if( !o.ended ) + o.state = 'terminating'; + o.conTerminate.take( err, err ? undefined : o ); + }, + onError : ( err ) => + { + o.error = o.error || err; + if( o.state !== 'terminated' ) + serialEnd(); + throw err; + }, + ready : null, + }); + + return o2.ready; + } + + return _.take( null ); + } + + /* */ + + function end1() + { + if( _readyCallback ) + o.ready.finally( _readyCallback ); + if( o.deasync ) + o.ready.deasync(); + if( o.sync ) + return o.ready.sync(); + return o.ready; + } + + /* */ + + function end2( err, arg ) + { + o.state = 'terminated'; + o.ended = true; + + if( !o.error && err ) + o.error = err; + + if( o.procedure ) + if( o.procedure.isAlive() ) + o.procedure.end(); + else + o.procedure.finit(); + + if( o.exitCode === null && o.exitSignal === null ) + for( let a = 0 ; a < o.sessions.length ; a++ ) + { + let o2 = o.sessions[ a ]; + if( o2.exitCode || o2.exitSignal ) + { + o.exitCode = o2.exitCode; + o.exitSignal = o2.exitSignal; + o.exitReason = o2.exitReason; + break; + } + } + + if( o.exitCode === null && o.exitSignal === null ) + for( let a = 0 ; a < o.sessions.length ; a++ ) + { + let o2 = o.sessions[ a ]; + if( o2.exitCode !== null || o2.exitSignal !== null ) + { + o.exitCode = o2.exitCode; + o.exitSignal = o2.exitSignal; + o.exitReason = o2.exitReason; + break; + } + } + + if( !o.error ) + for( let a = 0 ; a < o.sessions.length ; a++ ) + { + let o2 = o.sessions[ a ]; + if( o2.error ) + { + o.error = o2.error; + if( !o.exitReason ) + o.exitReason = o2.exitReason; + break; + } + } + + if( o.outputCollecting ) + if( o.sync && !o.deasync ) + for( let a = 0 ; a < o.sessions.length ; a++ ) + { + let o2 = o.sessions[ a ]; + o.output += o2.output; + } + + if( !o.exitReason ) + o.exitReason = o.error ? 'error' : 'normal'; + + if( err && !o.concurrent ) + serialEnd(); + + Object.freeze( o ); + if( err ) + throw err; + return o; + } + + /* */ + + /* + forward error to the the next process descriptor + */ + + function serialEnd() + { + o.sessions.forEach( ( o2 ) => + { + if( o2.ended ) + return; + try + { + o2.error = o2.error || o.error; + if( !o2.state ) + return; + o2._end(); + _.assert( !!o2.ended ); + } + catch( err2 ) + { + o.logger.error( _.err( err2 ) ); + } + }); + } + + /* */ + + function formStreams() + { + + if( !Stream ) + Stream = require( 'stream' ); + + if( o.stdio[ 1 ] !== 'ignore' ) + if( !o.sync || o.deasync ) + { + o.streamOut = new Stream.PassThrough(); + _.assert( o.streamOut._pipes === undefined ); + o.streamOut._pipes = []; + } + + if( o.stdio[ 2 ] !== 'ignore' ) + if( !o.sync || o.deasync ) + { + o.streamErr = new Stream.PassThrough(); + _.assert( o.streamErr._pipes === undefined ); + o.streamErr._pipes = []; + } + + /* piping out channel */ + + if( o.outputCollecting ) + if( o.streamOut ) + o.streamOut.on( 'data', handleStreamOut ); + + /* piping error channel */ + + if( o.outputCollecting ) + if( o.streamErr ) + o.streamErr.on( 'data', handleStreamOut ); + + } + + /* */ + + function processPipe( o2 ) + { + + o2.conStart.tap( ( err, op2 ) => + { + _processPipeCounter += 1; + if( err ) + return; + if( o2.pnd.stdout ) + streamPipe( o.streamOut, o2.pnd.stdout ); + if( o2.pnd.stderr ) + streamPipe( o.streamErr, o2.pnd.stderr ); + }); + + } + + /* */ + + function streamPipe( dst, src ) + { + + _.assert( !o.sync || !!o.deasync ); + + if( _.longHas( dst._pipes, src ) ) + { + return; + } + + _.assert( !!src && !!src.pipe ); + _.arrayAppendOnceStrictly( dst._pipes, src ); + src.pipe( dst, { end : false } ); + + src.on( 'end', () => + { + _.arrayRemoveOnceStrictly( dst._pipes, src ); + if( dst._pipes.length === 0 ) + if( _processPipeCounter === o.sessions.length ) + { + dst.end(); + } + }); + + } + + /* */ + + function handleStreamOut( data ) + { + if( _.bufferNodeIs( data ) ) + data = data.toString( 'utf8' ); + if( o.outputGraying ) + data = _.ct.stripAnsi( data ); + // data = StripAnsi( data ); + if( o.outputCollecting ) + o.output += data; + } + + /* */ + +} + +startMultiple_body.defaults = +{ + + ... _.mapBut_( null, startSingle.defaults, [ 'sessionId' ] ), + + concurrent : 0, + +} + +let startMultiple = _.routine.uniteCloning_replaceByUnite( startMultiple_head, startMultiple_body ); + +// + +let startPassingThrough = _.routine.uniteCloning_replaceByUnite( startMultiple_head, startMultiple_body ); + +var defaults = startPassingThrough.defaults; + +defaults.verbosity = 0; +defaults.passingThrough = 1; +defaults.applyingExitCode = 1; +defaults.throwingExitCode = 0; +defaults.outputPiping = 1; +defaults.stdio = 'inherit'; +defaults.mode = 'spawn'; + +// + +/** + * @summary Short-cut for {@link module:Tools/base/ProcessBasic.Tools.process.start start} routine. Executes provided script in with `node` runtime. + * @description + * Expects path to javascript file in `o.execPath` option. Automatically prepends `node` prefix before script path `o.execPath`. + * @param {Object} o Options map, see {@link module:Tools/base/ProcessBasic.Tools.process.start start} for detailed info about options. + * @param {Boolean} o.passingThrough=0 Allows to pass arguments of parent process to the child process. + * @param {Boolean} o.maximumMemory=0 Allows `node` to use all available memory. + * @param {Boolean} o.applyingExitCode=1 Applies exit code to parent process. + * @param {String|Array} o.stdio='inherit' Prints all output through stdout,stderr channels of parent. + * + * @return {Object} Returns `wConsequence` instance in async mode. In sync mode returns options map. Options map contains not only input options, but child process descriptor, collected output, exit code and other useful info. + * + * @example + * + * const _ = require( 'wTools' ) + * _.include( 'wProcessBasic' ) + * _.include( 'wConsequence' ) + * _.include( 'wLogger' ) + * + * let con = _.process.startNjs({ execPath : 'path/to/script.js' }); + * + * con.then( ( op ) => + * { + * console.log( 'ExitCode:', op.exitCode ); + * return op; + * }) + * + * @function startNjs + * @module Tools/base/ProcessBasic + * @namespace Tools.process + */ + +function startNjs_body( o ) +{ + + if( !System ) + System = require( 'os' ); + + _.routine.assertOptions( startNjs_body, o ); + _.assert( !o.code ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + _.assert( _.arrayIs( o.interpreterArgs ) || o.interpreterArgs === null ); + + /* + 1024*1024 for megabytes + 1.4 factor found empirically for windows + implementation of nodejs for other OSs could be able to use more memory + */ + + let logger = o.logger || _global.logger; + let interpreterArgs = ''; + if( o.maximumMemory ) + { + let totalmem = System.totalmem(); + if( o.verbosity >= 3 ) + logger.log( 'System.totalmem()', _.strMetricFormatBytes( totalmem ) ); + if( totalmem < 1024*1024*1024 ) + Math.floor( ( totalmem / ( 1024*1024*1.4 ) - 1 ) / 256 ) * 256; + else + Math.floor( ( totalmem / ( 1024*1024*1.1 ) - 1 ) / 256 ) * 256; + interpreterArgs = '--expose-gc --stack-trace-limit=999 --max_old_space_size=' + totalmem; + interpreterArgs = _.strSplitNonPreserving({ src : interpreterArgs }); + } + + let execPath = o.execPath || ''; + + if( interpreterArgs !== '' ) + o.interpreterArgs = _.arrayAppendArray( o.interpreterArgs, interpreterArgs ); + + if( o.mode === 'spawn' || o.mode === 'shell' ) + execPath = _.strConcat([ 'node', execPath ]); + + o.execPath = execPath; + + let result = _.process.startMultiple.body.call( _.process, o ); + + return result; +} + +var defaults = startNjs_body.defaults = Object.create( startMultiple.defaults ); + +defaults.passingThrough = 0; +defaults.maximumMemory = 0; +defaults.applyingExitCode = 1; +defaults.stdio = 'inherit'; +defaults.mode = 'fork'; + +let startNjs = _.routine.uniteCloning_replaceByUnite( startMultiple_head, startNjs_body ); + +// + +/** + * @summary Short-cut for {@link module:Tools/base/ProcessBasic.Tools.process.startNjs startNjs} routine. + * @description + * Passes arguments of parent process to the child and allows `node` to use all available memory. + * Expects path to javascript file in `o.execPath` option. Automatically prepends `node` prefix before script path `o.execPath`. + * @param {Object} o Options map, see {@link module:Tools/base/ProcessBasic.Tools.process.start start} for detailed info about options. + * @param {Boolean} o.passingThrough=1 Allows to pass arguments of parent process to the child process. + * @param {Boolean} o.maximumMemory=1 Allows `node` to use all available memory. + * @param {Boolean} o.applyingExitCode=1 Applies exit code to parent process. + * + * @return {Object} Returns `wConsequence` instance in async mode. In sync mode returns options map. Options map contains not only input options, but child process descriptor, collected output, exit code and other useful info. + * + * @example + * + * const _ = require( 'wTools' ) + * _.include( 'wProcessBasic' ) + * _.include( 'wConsequence' ) + * _.include( 'wLogger' ) + * + * let con = _.process.startNjsPassingThrough({ execPath : 'path/to/script.js' }); + * + * con.then( ( op ) => + * { + * console.log( 'ExitCode:', op.exitCode ); + * return op; + * }) + * + * @function startNjsPassingThrough + * @module Tools/base/ProcessBasic + * @namespace Tools.process + */ + +let startNjsPassingThrough = _.routine.uniteCloning_replaceByUnite( startMultiple_head, startNjs.body ); + +var defaults = startNjsPassingThrough.defaults; + +defaults.verbosity = 0; +defaults.passingThrough = 1; +defaults.maximumMemory = 1; +defaults.applyingExitCode = 1; +defaults.throwingExitCode = 0; +defaults.mode = 'fork'; + +// + +/** + * @summary Generates start routine that reuses provided option on each call. + * @description + * Routine vectorize `o.execPath` and `o.args` options. `wConsequence` instance `o.ready` can be reused to run several starts in a row, see examples. + * @param {Object} o Options map + * + * @return {Function} Returns start routine with options saved as inner state. + * + * @example //single command execution + * + * const _ = require( 'wTools' ) + * _.include( 'wProcessBasic' ) + * _.include( 'wConsequence' ) + * _.include( 'wLogger' ) + * + * let start = _.process.starter({ execPath : 'node' }); + * + * let con = start({ args : [ '-v' ] }); + * + * con.then( ( op ) => + * { + * console.log( 'ExitCode:', op.exitCode ); + * return op; + * }) + * + * @example //multiple commands execution with same args + * + * const _ = require( 'wTools' ) + * _.include( 'wProcessBasic' ) + * _.include( 'wConsequence' ) + * _.include( 'wLogger' ) + * + * let start = _.process.starter({ args : [ '-v' ]}); + * + * let con = start({ execPath : [ 'node', 'npm' ] }); + * + * con.then( ( op ) => + * { + * console.log( 'ExitCode:', op.exitCode ); + * return op; + * }) + * + * @example + * //multiple commands execution with same args, using sinle consequence + * //second command will be executed when first is finished + * + * const _ = require( 'wTools' ) + * _.include( 'wProcessBasic' ) + * _.include( 'wConsequence' ) + * _.include( 'wLogger' ) + * + * let ready = new _.Consequence().take( null ); + * let start = _.process.starter({ args : [ '-v' ], ready }); + * + * start({ execPath : 'node' }); + * + * ready.then( ( op ) => + * { + * console.log( 'node ExitCode:', op.exitCode ); + * return op; + * }) + * + * start({ execPath : 'npm' }); + * + * ready.then( ( op ) => + * { + * console.log( 'npm ExitCode:', op.exitCode ); + * return op; + * }) + * + * @function starter + * @module Tools/base/ProcessBasic + * @namespace Tools.process + */ + +function starter( o0 ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 ); + if( _.strIs( o0 ) ) + o0 = { execPath : o0 } + o0 = _.routine.options_( starter, o0 || null ); + o0.ready = o0.ready || new _.Consequence().take( null ); + + _.routineExtend( er, _.process.startMultiple ); + _.assert( er.defaults !== _.process.startMultiple.defaults ); + er.predefined = o0; + + for( let k in o0 ) + if( _.primitive.is( o0[ k ] ) ) + er.defaults[ k ] = o0[ k ]; + + return er; + + /* */ + + function er() + { + /* + non-primitive options : + + - execPath( in multiple runs ) : array + - currentPath( in multiple runs ) : array + - args : array + - interpreterArgs : array + - stdio : array + - logger : object + - procedure : object + - ready : routine + - conStart : routine + - conTerminate : routine + - conDisconnect : routine + - outputColoring : aux + - env : aux + */ + let o = optionsFrom( arguments[ 0 ] ); + let o00 = _.props.extend( null, o0 ); + for( let k in o00 ) + { + if( _.arrayIs( o00[ k ] ) ) + o00[ k ] = o00[ k ].slice(); + else if( _.aux.is( o00[ k ] ) ) + o00[ k ] = _.props.extend( null, o00[ k ] ); + } + merge( o00, o ); + _.props.extend( o, o00 ) + + for( let a = 1 ; a < arguments.length ; a++ ) + { + let o1 = optionsFrom( arguments[ a ] ); + merge( o, o1 ); + _.props.extend( o, o1 ); + } + + /* + if o.stack to starter is number add it to the delta, + if not, overwrite with o.stack passed to instance + */ + /* xxx : qqq : for junior : bad | aaa : fixed. */ + if( _.numberIs( o0.stack ) ) + o.stack = _.Procedure.Stack( o.stack, 1 + o0.stack ); + else + o.stack = _.Procedure.Stack( o.stack, 1 ); + + return _.process.startMultiple( o ); + } + + function optionsFrom( options ) + { + if( _.strIs( options ) || _.arrayIs( options ) ) + options = { execPath : options } + options = options || Object.create( null ); + _.map.assertHasOnly( options, starter.defaults ); + return options; + } + + function merge( dst, src ) + { + if( _.strIs( src ) || _.arrayIs( src ) ) + src = { execPath : src } + _.map.assertHasOnly( src, starter.defaults ); + + if( src.execPath !== null && src.execPath !== undefined && dst.execPath !== null && dst.execPath !== undefined ) + { + _.assert + ( + _.arrayIs( src.execPath ) || _.strIs( src.execPath ), + () => `Expects string or array, but got ${_.entity.strType( src.execPath )}` + ); + if( _.arrayIs( src.execPath ) ) + src.execPath = _.arrayFlatten( src.execPath ); + + /* + condition required, otherwise vectorization of results will be done what is not desirable + */ + + if( _.arrayIs( dst.execPath ) || _.arrayIs( src.execPath ) ) + dst.execPath = _.permutation.eachSample( [ dst.execPath, src.execPath ] ).map( ( path ) => path.join( ' ' ) ); + else + dst.execPath = dst.execPath + ' ' + src.execPath; + + delete src.execPath; + } + + _.props.extend( dst, src ); + + return dst; + } + +} + +starter.defaults = _.mapBut_( null, startMultiple.defaults, [ 'procedure' ] ); + +// -- +// children +// -- + +function isAlive( src ) +{ + let pid = _.process.pidFrom( src ); + _.assert( arguments.length === 1 ); + _.assert( _.numberIs( pid ), `Expects process id as number, but got:${pid}` ); + + try + { + return process.kill( pid, 0 ); + } + catch( err ) + { + return err.code === 'EPERM' + } + +} + +// + +function statusOf( src ) +{ + _.assert( arguments.length === 1 ); + let isAlive = _.process.isAlive( src ); + return isAlive ? 'alive' : 'dead'; +} + +// + +function signal_head( routine, args ) +{ + let o = args[ 0 ]; + + _.assert( args.length === 1 ); + + if( _.numberIs( o ) ) + o = { pid : o }; + else if( _.process.isNativeDescriptor( o ) ) + o = { pnd : o }; + + o = _.routine.options_( routine, o ); + + if( o.pnd ) + { + _.assert( o.pid === o.pnd.pid || o.pid === null ); + o.pid = o.pnd.pid; + _.assert( _.intIs( o.pid ) ); + } + + return o; +} + +// + +function signal_body( o ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.numberIs( o.timeOut ), 'Expects number as option {-timeOut-}' ); + _.assert( _.strIs( o.signal ), 'Expects signal to be provided explicitly as string' ); + _.assert( _.intIs( o.pid ) ); + + let isWindows = process.platform === 'win32'; + let ready = _.Consequence().take( null ); + let cons = []; + let signal = o.signal; + + if( o.withChildren ) + { + ready.then( () => _.process.children({ pid : o.pid, format : 'list' }) ); + ready.catch( ( err ) => { _.error.attend( err ); return [ { pid : o.pid, pnd : o.pnd } ] } ); + } + else + { + ready.then( () => { return { pid : o.pid, pnd : o.pnd } } ); + } + ready.then( processKill ); + ready.then( handleResult ); + ready.catch( handleError1 ); + + return end(); + + /* - */ + + function end() + { + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + return ready; + } + + /* */ + + function signalSend( p ) + { + _.assert( _.intIs( p.pid ) ); + + if( !_.process.isAlive( p.pid ) ) + { + if( o.ignoringErrorEsrch ) + return true; + throw _.err( `Target process: ${_.strQuote( p.pid )} does not exist.` ); + } + + let pnd = p.pnd; + if( !pnd && o.pnd && o.pnd.pid === p.pid ) + pnd = o.pnd; + + try + { + process.kill( pnd ? pnd.pid : p.pid, o.signal ); + } + catch( err ) + { + console.error( 'signalSend.error :', err.code ); /* xxx : remove later */ + console.error( processInfoGet( p ) ); + if( o.ignoringErrorEsrch && err.code === 'ESRCH' ) + return true; + if( o.ignoringErrorPerm && err.code === 'EPERM' ) + return true; + throw handleError2( p, err ); + } + + let con = waitForDeath( p ); + cons.push( con ); + } + + /* */ + + function processKill( processes ) + { + + _.assert( !o.withChildren || o.pid === processes[ 0 ].pid, 'Something wrong, first process must be the leader' ); + + /* + leader of the group of processes should receive the signal first + so progression sould be positive + it gives chance terminal to terminate child processes properly + otherwise more fails appear in shell mode for OS spawing extra process for applications + */ + + if( o.withChildren ) + for( let i = 0 ; i < processes.length ; i++ ) + { + let process = processes[ i ]; + + /* Dmytro : the solution was before, I uncommented it. + The reasons: + - conhost.exe is the layer of back-compatibility to WindowsXP + - actually, conhost.exe is not a child process like the POSIX child process, it looks like a shared host + More about conhost.exe: https://www.howtogeek.com/howto/4996/what-is-conhost.exe-and-why-is-it-running/ + + The parent process closes its conhost.exe process. + If we try to close the process manually, then OS permitted the signal and the program will wait for the result forever. + + I've watched the Windows Task Manager during testing : + - number of processes 'conhost.exe' was a constant value; + - the memory usage does not grow.. + */ + + if( isWindows && i && process.name === 'conhost.exe' ) + continue; + + if( _.process._windowsSystemLike( process ) ) + console.error( `Attemp to send signal to Windows system process.\n${processInfoGet( process )}` ) + + signalSend( process ); + } + else + { + signalSend( processes ); + } + + if( !cons.length ) + return true; + + return _.Consequence.AndKeep( ... cons ); + } + + /* - */ + + function waitForDeath( p ) + { + let timeOut = signal === 'SIGKILL' ? 5000 : o.timeOut; + + if( timeOut === 0 ) + return kill( p ); + + let ready = _.process.waitForDeath({ pid : p.pid, timeOut }) + + ready.catch( ( err ) => + { + + if( err.reason === 'time out' ) + { + _.errAttend( err ); + if( signal === 'SIGKILL' ) + err = _.err( `Target process is still alive after kill. Waited for ${o.timeOut} ms.` ); + else + return kill( p ); + } + + err = _.err( err, processInfoGet( p ) ); + + throw err; + }) + + return ready; + } + + /* - */ + + function kill( p ) + { + return _.process.kill + ({ + pid : p.pid, + pnd : p.pnd, + withChildren : 0, + // ignoringErrorPerm : 1, /* xxx : enable? */ + }); + } + + /* - */ + + function handleError1( err ) + { + console.log( 'handleError1' ); /* xxx : remove later */ + throw handleError2( o, err ); + } + + /* - */ + + function handleError2( p, err ) + { + console.log( 'handleError2' ); /* xxx : remove later */ + // if( err.code === 'EINVAL' ) + // err = _.err( err, '\nAn invalid signal was specified:', _.strQuote( o.signal ) ) + if( err.code === 'EPERM' ) + err = _.err( err, `\nCurrent process does not have permission to kill target process: ${o.pid}` ); + if( err.code === 'ESRCH' ) + err = _.err( err, `\nTarget process does not exist.` ); + + if( !err.processInfo && p ) + // if( p ) + { + let processInfo = processInfoGet( p ); + _.error.concealedSet( err, { processInfo } ); + _.err( err, processInfo ); + // console.log( 'handleError2 :', processInfo ); + } + // else + // { + // console.log( 'handleError2 :', 'no p' ); + // } + + if( err && err.processInfo ) + console.log( 'handleError2 :', err.processInfo ); + + if( !p ) + console.log( 'handleError2 : no p' ); + + return _.err( err ); + } + + /* - */ + + function processInfoGet( p ) + { + let info; + + try + { + if( p.pnd ) + { + info = `\nPID : ${p.pnd.pid}\nExecPath : ${p.pnd.spawnfile}\nArgs : ${p.pnd.spawnargs}`; /* qqq for junior : seems not covered */ + } + else + { + let execPath = _.process.execPathOf({ pid : p.pid, sync : 1, throwing : 0 }); + info = `\nPID : ${p.pid}\nExecPath : ${execPath}`; /* qqq for junior : seems not covered */ + } + } + catch( err ) + { + console.error( err ); + info = `\nFailed to get ExecPath of proces with pid::${p.pnd.pid}` + } + + return info; + } + + /* - */ + + function handleResult( result ) + { + result = _.array.as( result ); + for( let i = 0 ; i < result.length ; i++ ) + { + if( result[ i ] !== true ) + return result[ i ]; + } + return true; + } + +} + +signal_body.defaults = +{ + pid : null, + pnd : null, + withChildren : 1, + timeOut : 5000, + signal : null, + ignoringErrorPerm : 0, + ignoringErrorEsrch : 1, + sync : 0, +}; + +let _signal = _.routine.uniteCloning_replaceByUnite( signal_head, signal_body ); + +// + +function kill_body( o ) +{ + _.assert( arguments.length === 1 ); + let o2 = _.props.extend( null, o ); + o2.signal = 'SIGKILL'; + o2.timeOut = 5000; + return _.process._signal.body( o2 ); +} + +kill_body.defaults = +{ + ... _.mapBut_( null, _signal.defaults, [ 'signal', 'timeOut' ] ), +} + +let kill = _.routine.uniteCloning_replaceByUnite( signal_head, kill_body ); + + +// + +/* + zzz for Vova: shell mode have different behaviour on Windows, OSX and Linux + look for solution that allow to have same behaviour on each mode +*/ + +function terminate_body( o ) +{ + _.assert( arguments.length === 1 ); + o.signal = o.timeOut ? 'SIGTERM' : 'SIGKILL'; + return _.process._signal.body( o ); +} + +terminate_body.defaults = +{ + ... _.mapBut_( null, _signal.defaults, [ 'signal' ] ), +} + +let terminate = _.routine.uniteCloning_replaceByUnite( signal_head, terminate_body ); + +// + +function waitForDeath_body( o ) +{ + _.assert( arguments.length === 1 ); + _.assert( _.numberIs( o.pid ) ); + _.assert( _.numberIs( o.timeOut ) ); + + let isWindows = process.platform === 'win32'; + let interval = isWindows ? 250 : 25; + + /* + zzz : hangs up on Windows with interval below 150 if run in sync mode. see test routine killSync + */ + + let ready = _.Consequence().take( true ); + + // console.log( `waitForDeath ${o.pid} ${_.process.isAlive( o.pid )}` ); + + if( !_.process.isAlive( o.pid ) ) + return end(); + + if( isWindows ) + ready.then( () => _.process.spawnTimeOf({ pid : o.pid }) ) + + ready.then( _waitForDeath ); + + return end(); + + /* */ + + function end() + { + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + return ready; + } + + /* */ + + function _waitForDeath( spawnTime ) + { + let ready = _.Consequence(); + let timer = _.time.periodic( interval, () => + { + if( _.process.isAlive( o.pid ) ) + return true; + ready.take( true ); + }); + + let timeOutError = _.time.outError( o.timeOut ) + + ready.orKeeping( [ timeOutError ] ); /* zzz : implement option::cenceling for consequence? */ + + ready.finally( ( err, arg ) => + { + if( !err || err.reason !== 'time out' ) + timeOutError.error( _.dont ); + + if( !err ) + return arg; + + timer.cancel(); + + if( err.reason === 'time out' ) + { + err = _.err( err, `\nTarget process: ${_.strQuote( o.pid )} is still alive. Waited ${o.timeOut} ms.` ); + if( isWindows ) + { + let spawnTime2 = _.process.spawnTimeOf({ pid : o.pid }) + if( spawnTime === spawnTime2 ) + { + let execPath = _.process.execPathOf({ pid : o.pid, sync : 1, throwing : 0 }); + let info = `waitForDeath: Spawn time of process:${o.pid} did not change after time out.` + + `\nspawnTime:${spawnTime} spawnTime2:${spawnTime2}\nExec path:${execPath}`; + console.error( info ); + } + else + { + _.errAttend( err ); + return null; + } + // if( spawnTime != spawnTime2 ) + // { + // _.errAttend( err ); + // return null; + // } + // else + // { + // let execPath = _.process.execPathOf({ pid : o.pid, sync : 1, throwing : 0 }); + // let info = `waitForDeath: Spawn time of process:${o.pid} did not change after time out.` + // + `\nspawnTime:${spawnTime} spawnTime2:${spawnTime2}\nExec path:${execPath}`; + // console.error( info ); + // } + } + } + + throw err; + }) + + return ready; + } +} + +waitForDeath_body.defaults = +{ + pid : null, + pnd : null, + timeOut : 5000, + sync : 0 +} + +let waitForDeath = _.routine.uniteCloning_replaceByUnite( signal_head, waitForDeath_body ) + +// + +function children( o ) +{ + if( _.numberIs( o ) ) + o = { pid : o }; + else if( _.process.isNativeDescriptor( o ) ) + o = { process : o } + + _.routine.options_( children, o ) + _.assert( arguments.length === 1 ); + _.assert( _.numberIs( o.pid ) ); + _.assert( _.longHas( [ 'list', 'tree' ], o.format ) ); + + if( o.pnd ) + { + _.assert( o.pid === null ); + o.pid = o.pnd.pid; + } + + let result; + + if( !_.process.isAlive( o.pid ) ) + { + /* Dmytro : maybe it's overhead, the caller should know what children it needs or simply return empty container */ + let err = _.err( `\nTarget process: ${_.strQuote( o.pid )} does not exist.` ); + return new _.Consequence().error( err ); + } + + if( process.platform === 'win32' ) + { + if( !WindowsProcessTree ) + { + try + { + WindowsProcessTree = require( 'w.process.tree.windows' ); + } + catch( err ) + { + throw _.err( err, '\nFailed to get child process list.' ); + } + } + + let con = new _.Consequence(); + if( o.format === 'list' ) + { + WindowsProcessTree.getProcessList( o.pid, ( result ) => con.take( result ) ); + } + else + { + WindowsProcessTree.getProcessTree( o.pid, ( list ) => + { + result = Object.create( null ); + handleWindowsResult( result, list ); + con.take( result ); + }) + } + return con; + } + else + { + if( o.format === 'list' ) + result = []; + else + result = Object.create( null ); + + if( process.platform === 'darwin' ) + return childrenOf( 'pgrep -P', o.pid, result ); + else + return childrenOf( 'ps -o pid --no-headers --ppid', o.pid, result ); + /* zzz for Vova : use optimal solution */ + } + + /* */ + + function childrenOf( command, pid, _result ) + { + return _.process.startSingle + ({ + execPath : command + ' ' + pid, + outputCollecting : 1, + outputPiping : 0, + throwingExitCode : 0, + inputMirroring : 0, + stdio : 'pipe', + }) + .then( ( op ) => + { + if( o.format === 'list' ) + _result.push({ pid : _.numberFrom( pid ) }); + else + _result[ pid ] = Object.create( null ); + if( op.exitCode !== 0 ) + return result; + let ready = new _.Consequence().take( null ); + let pids = _.strSplitNonPreserving({ src : op.output, delimeter : '\n' }); + _.each( pids, ( cpid ) => ready.then( () => childrenOf( command, cpid, o.format === 'list' ? _result : _result[ pid ] ) ) ) + return ready; + }) + } + + function handleWindowsResult( tree, result ) + { + tree[ result.pid ] = Object.create( null ); + if( result.children && result.children.length ) + _.each( result.children, ( child ) => handleWindowsResult( tree[ result.pid ], child ) ) + return tree; + } + +} + +children.defaults = +{ + process : null, + pid : null, + format : 'list', +} + +// + +function execPathOf( o ) +{ + _.assert( arguments.length === 1 ); + + if( _.numberIs( o ) ) + o = { pid : o }; + else if( _.process.isNativeDescriptor( o ) ) + o = { pnd : o }; + + o = _.routine.options_( execPathOf, o ); + + if( o.pnd ) + { + _.assert( o.pid === o.pnd.pid || o.pid === null ); + o.pid = o.pnd.pid; + _.assert( _.intIs( o.pid ) ); + } + + let ready = _.Consequence() + + if( !_.process.isAlive( o.pid ) ) + { + if( !o.throwing ) + { + ready.take( null ); + return end(); + } + let err = _.err( `\nTarget process: ${_.strQuote( o.pid )} does not exist.` ); + if( o.sync ) + throw err; + return ready.error( err ); + } + + if( process.platform === 'win32' ) + { + if( !WindowsProcessTree ) + { + try + { + WindowsProcessTree = require( 'w.process.tree.windows' ); + } + catch( err ) + { + err = _.err( err, '\nFailed to get process name.' ); + if( o.sync ) + throw err; + return ready.error( err ); + } + } + + WindowsProcessTree.getProcessList( o.pid, ( list ) => + { + ready.take( list[ 0 ].commandLine ); + }, WindowsProcessTree.ProcessDataFlag.CommandLine ) + } + else + { + let op = + { + execPath : `ps -p ${o.pid} -o command`, + mode : 'shell', + stdio : 'pipe', + outputPiping : 0, + outputCollecting : 1, + inputMirroring : 0, + ready + } + + _.process.start( op ); + + ready.then( ( op ) => + { + let lines = _.strSplitNonPreserving({ src : op.output, delimeter : '\n' }); + return lines[ lines.length - 1 ]; + }) + + ready.catch( ( err ) => + { + throw _.err( `Failed to get exec path of process:${o.pid}.`, err ); + }) + + ready.take( null ); + } + + return end(); + + function end() + { + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + return ready; + } +} + + +execPathOf.defaults = +{ + pid : null, + pnd : null, + throwing : 1, + sync : 1, /* qqq for junior : cover option::sync. don't forget all cases thorwing error and option::throwing */ +} + +// + +function spawnTimeOf( o ) +{ + _.assert( arguments.length === 1 ); + + if( _.numberIs( o ) ) + o = { pid : o }; + else if( _.process.isNativeDescriptor( o ) ) + o = { pnd : o }; + + o = _.routine.options_( spawnTimeOf, o ); + + if( o.pnd ) + { + _.assert( o.pid === o.pnd.pid || o.pid === null ); + o.pid = o.pnd.pid; + _.assert( _.intIs( o.pid ) ); + } + + _.assert( process.platform === 'win32', 'Implemented only for Windows' ); + + if( !WindowsProcessTree ) + { + try + { + WindowsProcessTree = require( 'w.process.tree.windows' ); + } + catch( err ) + { + throw _.err( err, '\nFailed to get process name.' ); + } + } + + return WindowsProcessTree.getProcessCreationTime( o.pid ); +} + +spawnTimeOf.defaults = +{ + pid : null, + pnd : null +} + +// + +function _windowsSystemLike( pnd ) +{ + if( process.platform !== 'win32' ) + return false; + + let list = + [ + 'csrss.exe', + 'wininit.exe', + 'services.exe', + 'smartscreen.exe', + 'ShellExperienceHost.exe', + 'SearchUI.exe', + 'RuntimeBroker.exe', + 'taskhostw.exe', + 'provisioner.exe', + 'conhost.exe', + 'Runner.Listener.exe', + 'Runner.Worker.exe', + 'spoolsv.exe', + 'sihost.exe', + 'WaAppAgent.exe', + 'WaSecAgentProv.exe', + 'SMSvcHost.exe', + 'IpOverUsbSvc.exe', + 'WindowsAzureGuestAgent.exe', + 'MsMpEng.exe', + 'WindowsAzureNetAgent.exe', + 'mqsvc.exe', + 'SMSvcHost.exe', + 'ctfmon.exe', + 'vds.exe', + 'msdtc.exe', + 'svchost.exe', + 'lsass.exe', + 'fontdrvhost.exe', + ] + + _.assert( arguments.length === 1 ); + _.assert( _.number.is( pnd.pid ) ); + // _.assert( _.strDefined( pnd.name ) ); + + return list.indexOf( pnd.name ) !== -1; +} + +// + +function _startTree( o ) +{ + o = o || {}; + + _.routine.options_( _startTree, o ); + + if( o.executionTime === null ) + o.executionTime = [ 50, 100 ]; + + if( o.spawnPeriod === null ) + o.spawnPeriod = [ 25, 50 ]; + + let locals = + { + toolsPath : _.module.resolve( 'wTools'), + ... o + }; + + /* qqq : for Vova : reuse _.program.* */ + let preformedChild = _.program.preform({ entry : child, locals }); + let preformedChildPath = _.process.tempOpen({ routineCode : preformedChild.entry.routineCode }); + locals.childPath = preformedChildPath; + let preformed = _.program.preform({ entry : program, locals }); + let preformedFilePath = _.process.tempOpen({ routineCode : preformed.entry.routineCode }); + + o.list = []; + + let op = o.rootOp = + { + execPath : preformedFilePath, + mode : 'fork', + inputMirroring : 0, + throwingExitCode : 0, + } + + _.process.startSingle( op ); + + o.ready = _.Consequence(); + + op.pnd.on( 'message', ( pnd ) => + { + o.list.push( pnd ); + + if( o.list.length === o.max ) + o.ready.take( null ); + }) + + // o.ready.then( () => + // { + // let cons = [ op.conTerminate ]; + // o.list.forEach( ( pnd ) => + // { + // if( !_.process.isAlive( pnd.pid ) ) + // return; + // cons.push( _.process.waitForDeath({ pid : pnd.pid }) ) + // }) + // return _.Consequence.AndKeep( ... cons ); + // }) + + o.ready.then( () => o.rootOp.ready ); + o.ready.then( () => o ); + + return o.ready; + + /* */ + + function program() + { + const _ = require( toolsPath ); + _.include( 'wProcess' ); + _.include( 'wFilesBasic' ); + + process.send({ pid : process.pid, ppid : process.ppid }); + + let c = 0; + + _.time.periodic( _.numberRandom( spawnPeriod ), () => + { + if( c === max ) + return; + + c += 1; + + let op = + { + execPath : childPath, + mode : 'fork', + // detaching : 1, + inputMirroring : 0, + throwingExitCode : 0, + } + _.process.startSingle( op ); + + op.conStart.tap( () => + { + process.send({ pid : op.pnd.pid, ppid : process.pid }); + // op.disconnect(); + }) + + return true; + }) + } + + /* */ + + function child() + { + const _ = require( toolsPath ); + _.include( 'wProcess' ); + _.include( 'wFilesBasic' ); + + let timeOut = _.numberRandom( executionTime ); + setTimeout( () => + { + process.exit( 0 ) + }, timeOut ); + } + + /* */ + + function calculateNumberOfProcesses() + { + let expectedNumberOfNodes = 1; + let prev = 1; + for( let i = 1; i < o.depth; i++ ) + { + prev = prev * o.breadth; + expectedNumberOfNodes += prev; + } + return expectedNumberOfNodes; + } +} + +_startTree.defaults = +{ + max : 20, + spawnPeriod : null, + executionTime : null, +} + +// -- +// declare +// -- + +let Extension = +{ + + // start + + startMinimal, + startSingle, + startMultiple, + start : startMultiple, + + startPassingThrough, + startNjs, + startNjsPassingThrough, + starter, + + // children + + isAlive, + statusOf, + + _signal, + kill, + terminate, + waitForDeath, + + children, + execPathOf, + spawnTimeOf, + + _windowsSystemLike, + _startTree + + // fields + +} + +/* _.props.extend */Object.assign( _.process, Extension ); +_.assert( _.routineIs( _.process.start ) ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/l3/Execution.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Execution_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Execution_s */ })(); + +/* */ /* begin of file Io_s */ ( function Io_s() { function Io_s_naked() { ( function _Io_s_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; +_.process = _.process || Object.create( null ); + +_.assert( !!_realGlobal_ ); + +// -- +// +// -- + +/** + * @summary Parses arguments of current process. + * @description + * Supports processing of regular arguments, options( key:value pairs), commands and arrays. + * @param {Object} o Options map. + * @param {Boolean} o.keyValDelimeter=':' Delimeter for key:value pairs. + * @param {String} o.commandsDelimeter=';' Delimeneter for commands, for example : `.build something ; .exit ` + * @param {Array} o.argv=null Arguments array. By default takes arguments from `process.argv`. + * @param {Boolean} o.caching=true Caches results for speedup next calls. + * @param {Boolean} o.parsingArrays=true Enables parsing of array from arguments. + * + * @return {Object} Returns map with parsed arguments. + * + * @example + * + * const _ = require('wTools') + * _.include( 'wProcessBasic' ) + * let result = _.process.input(); + * console.log( result ); + * + * @function input + * @module Tools/base/ProcessBasic + * @namespace Tools.process + */ + +let _inputCache; +let _inputInSamFormatDefaults = Object.create( null ) +var defaults = _inputInSamFormatDefaults.defaults = Object.create( null ); + +defaults.keyValDelimeter = ':'; +defaults.commandsDelimeter = ';'; +defaults.caching = true; +defaults.parsingArrays = true; + +defaults.interpreterPath = null; +defaults.interpreterArgs = null; +defaults.scriptPath = null; +defaults.scriptArgs = null; + +// + +/* xxx : redo caching using _Setup1 */ + +function _inputInSamFormatNodejs( o ) +{ + + _.assert( arguments.length === 0 || arguments.length === 1 ); + o = _.routine.options_( _inputInSamFormatNodejs, arguments ); + + if( _.boolLike( o.keyValDelimeter ) ) + o.keyValDelimeter = !!o.keyValDelimeter; + + let isStandardOptions = + o.keyValDelimeter === _inputInSamFormatNodejs.defaults.keyValDelimeter + && o.commandsDelimeter === _inputInSamFormatNodejs.defaults.commandsDelimeter + && o.parsingArrays === _inputInSamFormatNodejs.defaults.parsingArrays + && o.interpreterPath === _inputInSamFormatNodejs.defaults.interpreterPath + && o.interpreterArgs === _inputInSamFormatNodejs.defaults.interpreterArgs + && o.scriptPath === _inputInSamFormatNodejs.defaults.scriptPath + && o.scriptArgs === _inputInSamFormatNodejs.defaults.scriptArgs; + + if( o.caching ) + if( _inputCache ) + if( isStandardOptions ) + return _inputCache; + + // let result = Object.create( null ); + let result = o; + + if( o.caching ) + // if( o.keyValDelimeter === _inputInSamFormatNodejs.defaults.keyValDelimeter ) + if( isStandardOptions ) + _inputCache = result; + + // if( !_global.process ) + // { + // result.subject = ''; + // result.map = Object.create( null ); + // result.subjects = []; + // result.maps = []; + // return result; + // } + + // o.argv = o.argv || process.argv; + // result.interpreterArgs = o.interpreterArgs; + + // if( result.applicationArgs === null ) + // result.applicationArgs = process.argv; + + if( result.interpreterArgs === null ) + result.interpreterArgs = _global_.process ? _global_.process.execArgv : []; + result.interpreterArgsStrings = argsToString( result.interpreterArgs ); + + let argv = _global_.process ? _global_.process.argv : [ '', '' ]; + _.assert( _.longIs( argv ) ); + if( result.interpreterPath === null ) + result.interpreterPath = argv[ 0 ]; + result.interpreterPath = _.path.normalize( result.interpreterPath ); + if( result.scriptPath === null ) + result.scriptPath = argv[ 1 ]; + result.scriptPath = _.path.normalize( result.scriptPath ); + if( result.scriptArgs === null ) + result.scriptArgs = argv.slice( 2 ); + result.scriptArgsString = argsToString( result.scriptArgs ); + + let r = _.strRequestParse + ({ + src : result.scriptArgsString, + keyValDelimeter : o.keyValDelimeter, + commandsDelimeter : o.commandsDelimeter, + parsingArrays : o.parsingArrays, + severalValues : 1, + subjectWinPathsMaybe : process.platform === 'win32', + }); + + _.props.extend( result, r ); + + return result; + + /* */ + + function argsToString( args ) + { + + return args.map( ( e ) => + { + if( !_.strHas( e, /\s/ ) ) + return e; + + let quotes = _.strQuoteAnalyze( e ); + if( quotes.ranges.length ) + return e; + + if( o.keyValDelimeter ) + { + let mapSplits = _.strIsolateLeftOrAll( e, o.keyValDelimeter ); + if( mapSplits[ 1 ] !== undefined ) + if( !_.strHas( mapSplits[ 0 ], /\s/ ) ) + return `${ mapSplits[ 0 ] }:${ mapSplits[ 2 ] }` + } + + return `"${e}"`; + }) + .join( ' ' ) + .trim(); + + // return args.map( e => _.strHas( e, /\s/ ) ? `"${e}"` : e ).join( ' ' ).trim(); + } +} + +_inputInSamFormatNodejs.defaults = Object.create( _inputInSamFormatDefaults.defaults ); + +// + +function _inputInSamFormatBrowser( o ) +{ + // debugger; /* xxx */ + + _.assert( arguments.length === 0 || arguments.length === 1 ); + o = _.routine.options_( _inputInSamFormatBrowser, arguments ); + + if( o.caching ) + if( _inputCache && o.keyValDelimeter === _inputCache.keyValDelimeter ) + return _inputCache; + + let result = Object.create( null ); + + result.map = Object.create( null ); + result.subject = ''; + result.original = ''; + + if( o.caching ) + if( o.keyValDelimeter === _inputInSamFormatBrowser.defaults.keyValDelimeter ) + _inputCache = result; + + return result; +} + +_inputInSamFormatBrowser.defaults = Object.create( _inputInSamFormatDefaults.defaults ); + +// + +/** + * @summary Reads options from arguments of current process and copy them on target object `o.dst`. + * @description + * Checks if found options are expected using map `o.namesMap`. Throws an Error if arguments contain unknown option. + * + * @param {Object} o Options map. + * @param {Object} o.dst=null Target object. + * @param {Object} o.propertiesMap=null Map with parsed options. By default routine gets this map using {@link module:Tools/base/ProcessBasic.Tools.process.input args} routine. + * @param {Object} o.namesMap=null Map of expected options. + * @param {Object} o.removing=1 Removes copied options from result map `o.propertiesMap`. + * @param {Object} o.only=1 Check if all option are expected. Throws error if not. + * + * @return {Object} Returns map with parsed options. + * + * @function inputReadTo + * @module Tools/base/ProcessBasic + * @namespace Tools.process + */ + +/* xxx : qqq : deprecate? */ +function inputReadTo( o ) +{ + + if( arguments[ 1 ] !== undefined ) + o = { dst : arguments[ 0 ], namesMap : arguments[ 1 ] }; + + o = _.routine.options_( inputReadTo, o ); + + if( !o.propertiesMap ) + o.propertiesMap = _.process.input().map; + + if( _.arrayIs( o.namesMap ) ) + { + let namesMap = Object.create( null ); + for( let n = 0 ; n < o.namesMap.length ; n++ ) + namesMap[ o.namesMap[ n ] ] = o.namesMap[ n ]; + o.namesMap = namesMap; + } + + _.assert( arguments.length === 1 || arguments.length === 2 ) + _.assert( _.object.isBasic( o.dst ), 'Expects map {-o.dst-}' ); + _.assert( _.object.isBasic( o.namesMap ), 'Expects map {-o.namesMap-}' ); + + /* + Dmytro : keeps the order of properties in command if ordered map is used + Also, number of properties in propertiesMap < number of properties in namesMap + */ + for( let n in o.propertiesMap ) + { + if( o.propertiesMap[ n ] !== undefined ) + if( n in o.namesMap ) + { + set( o.namesMap[ n ], o.propertiesMap[ n ] ); + if( o.removing ) + delete o.propertiesMap[ n ]; + } + } + + // for( let n in o.namesMap ) + // { + // if( o.propertiesMap[ n ] !== undefined ) + // { + // set( o.namesMap[ n ], o.propertiesMap[ n ] ); + // if( o.removing ) + // delete o.propertiesMap[ n ]; + // } + // } + + if( o.only ) + { + let but = Object.keys( _.mapBut_( null, o.propertiesMap, o.namesMap ) ); + if( but.length ) + { + throw _.err( `Unknown application arguments : ${but.join( ', ' )}` ); + } + } + + return o.propertiesMap; + + /* */ + + function set( k, v ) + { + let dstValue = o.dst[ k ] + _.assert( dstValue !== undefined, () => `Entry ${k} is not defined` ); + if( _.numberIs( dstValue ) ) + { + v = Number( v ); + _.assert( !isNaN( v ) ); + o.dst[ k ] = v; + } + else if( _.boolIs( dstValue ) ) + { + v = !!v; + o.dst[ k ] = v; + } + else + { + o.dst[ k ] = v; + } + } + +} + +inputReadTo.defaults = +{ + dst : null, + propertiesMap : null, + namesMap : null, + removing : 1, + only : 1, +} + +// + +function anchor( o ) +{ + o = o || {}; + + _.routine.options_( anchor, arguments ); + + let a = _.strStructureParse + ({ + src : _.strRemoveBegin( window.location.hash, '#' ), + keyValDelimeter : ':', + entryDelimeter : ';', + }); + + if( o.extend ) + { + _.props.extend( a, o.extend ); + } + + if( o.del ) + { + _.mapDelete( a, o.del ); + } + + if( o.extend || o.del ) + { + + let newHash = '#' + _.mapToStr + ({ + src : a, + keyValDelimeter : ':', + entryDelimeter : ';', + }); + + if( o.replacing ) + history.replaceState( undefined, undefined, newHash ) + else + window.location.hash = newHash; + + } + + return a; +} + +anchor.defaults = +{ + extend : null, + del : null, + replacing : 0, +} + +// + +/** + * Returns path for main module (module that running directly by node). + * @returns {String} + * @function realMainFile + * @namespace Tools.process + * @module Tools/base/ProcessBasic + */ + +let _pathRealMainFile; +function realMainFile() +{ + if( _pathRealMainFile ) + return _pathRealMainFile; + _pathRealMainFile = _.path.normalize( require.main.filename ); + return _pathRealMainFile; +} + +// + +/** + * Returns path dir name for main module (module that running directly by node). + * @returns {String} + * @function realMainDir + * @namespace Tools.process + * @module Tools/base/ProcessBasic + */ + +let _pathRealMainDir; +function realMainDir() +{ + if( _pathRealMainDir ) + return _pathRealMainDir; + + if( require.main ) + _pathRealMainDir = _.path.normalize( _.path.dir( require.main.filename ) ); + else + return this.effectiveMainFile(); + + return _pathRealMainDir; +} + +// + +/** + * Returns absolute path for file running directly by node + * @returns {String} + * @throws {Error} If passed any argument. + * @function effectiveMainFile + * @namespace Tools.process + * @module Tools/base/ProcessBasic + */ + +let _effectiveMainFilePath = ''; +function effectiveMainFile() /* qqq2 : move to process, review */ +{ + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( _effectiveMainFilePath ) + return _effectiveMainFilePath; + + if( process.argv[ 0 ] || process.argv[ 1 ] ) + { + _effectiveMainFilePath = _.path.join( this._initialCurrentPathGet(), process.argv[ 1 ] || process.argv[ 0 ] ); + _effectiveMainFilePath = _.path.resolve( _effectiveMainFilePath ); + } + + if( !_.fileProvider.fileExists( _effectiveMainFilePath ) ) + { + //xxx : review + console.error( `process.argv : ${process.argv.join( ', ' )}` ); + console.error( `currentAtBegin : ${this._initialCurrentPathGet()}` ); + console.error + ( + `effectiveMainFile.raw : ` + + `${this.join( this._initialCurrentPathGet(), process.argv[ 1 ] || process.argv[ 0 ] )}` + ); + console.error( `effectiveMainFile : ${_effectiveMainFilePath}` ); + _effectiveMainFilePath = this.realMainFile(); + } + + return _effectiveMainFilePath; +} + +// + +function pathsRead() +{ + if( !_global_.process ) + return []; + + let paths = _global_.process.env.PATH; + + if( _global_.process.platform === 'win32' ) + paths = paths.split( ';' ); + else + paths = paths.split( ':' ); + + return _.path.s.normalize( paths ); +} + +// + +function systemEntryAdd( o ) +{ + + // if( !_.mapIs( o ) ) + // o = { appPath : arguments[ 0 ] } + _.assert( _.mapIs( o ), `Expects option map {- o -}, but got: ${_.entity.strType( o )} ` ) + + _.routine.options_( systemEntryAdd, o ); + + if( _.boolLikeTrue( o.logger ) ) + o.logger = _.LoggerPrime(); + + if( o.platform === 'multiple' ) + o.platform = [ 'windows', 'posix' ]; + + if( o.platform === null ) + o.platform = process.platform === 'win32' ? 'windows' : 'posix'; + + o.platform = _.array.as( o.platform ); + + if( o.allowingMissed === null ) + o.allowingMissed = !!o.forcing; + if( o.allowingNotInPath === null ) + o.allowingNotInPath = !!o.forcing; + + _.assert( _.path.isAbsolute( o.appPath ), () => `Expects absolute path o.appPath, but got ${o.appPath}` ); + + o.appPath = _.path.normalize( o.appPath ); + if( o.name === null ) + o.name = _.path.name( o.appPath ); + + _.assert( _.longHasAll( [ 'windows', 'posix' ], o.platform ), `Unknown platforms : ${o.platform.join( ' ' )}` ); + _.assert( _.path.isAbsolute( o.entryDirPath ), () => `Expects absolute path o.entryDirPath, but got ${o.entryDirPath}` ); + _.assert( _.strIs( o.prefix ) ); + _.sure( _.strDefined( o.entryDirPath ), `Neither {-o.entryDirPath-} is defined nor config has defined path::entry` ); + _.sure( _.fileProvider.isDir( o.entryDirPath ), `Not a dir : ${o.entryDirPath}` ); + _.sure + ( + o.allowingMissed || ( _.fileProvider.fileExists( o.appPath ) && !_.fileProvider.isDir( o.appPath ) ), + () => `Does not exist file : ${o.appPath}` + ); + _.sure + ( + o.allowingNotInPath || _.longHas( _.process.pathsRead(), o.entryDirPath ) + , () => `entryDirPath is not in the environment variable $PATH` + + `\nentryDirPath : ${o.entryDirPath}` + + `\n$PATH :\n ${_.process.pathsRead().join( '\n ' )}` + ); + + let appPath = o.appPath; + if( o.relative ) + appPath = _.path.relative( o.entryDirPath, o.appPath ); + + appPath = _.path.nativize( appPath ); + + let counter = 0; + + o.platform.forEach( ( platform ) => installFor( platform ) ); + + if( o.logger && o.verbosity === 1 ) + o.logger.log( ` + Added ${counter} entrie(s) ${_.path.moveTextualReport( o.entryDirPath, o.appPath )}` ); + + return counter; + + function shellRelativePosix() + { + return ` +#!/bin/bash +dirPath=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +# dirPath=$0; +# dirPath=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P ) +# dirPath=$( cd "$(dirname "\${BASH_SOURCE[0]}")" ; pwd -P ) +# echo BASH_SOURCE[0]:\${BASH_SOURCE[0]} +# echo dirPath:\${dirPath} +# echo appPath:${appPath} +# ${o.prefix}\${dirPath}/${appPath} "$@" +${o.prefix}\${dirPath}/${appPath} "$@" +` + } + + function shellRelativeWindows() + { + return ` +@echo off +${o.prefix}%~dp0${appPath} %* +` + } + + function installFor( platform ) + { + let entryTerminalPath = _.path.join( o.entryDirPath, o.name ); + if( platform === 'windows' ) + entryTerminalPath += '.bat'; + let shellFile = shellRelativePosix(); + if( platform === 'windows' ) + shellFile = shellRelativeWindows(); + + if( o.logger && o.verbosity >= 2 ) + o.logger.log( ` + Add entry ${_.path.moveTextualReport( entryTerminalPath, o.appPath )}` ); + + _.fileProvider.fileWrite( entryTerminalPath, shellFile ); + + if( o.addingRights !== null ) + _.fileProvider.rightsAdd( entryTerminalPath, o.addingRights ); + + counter += 1; + } + +} + +systemEntryAdd.defaults = +{ + logger : 0, + verbosity : 0, + entryDirPath : null, // where to add + appPath : null, // where to run + prefix : 'node ', + name : null, + platform : null, + relative : 1, // whether path is relative, other test routine + addingRights : 0o777, // rights to be able to run this file ( all rights ) + allowingMissed : null, // ( test routine ) error if program is absent + allowingNotInPath : null, // error if entryDirPath is not in PATH + forcing : 0, // make all to run the routine ( test routine ) +} + +// -- +// declare +// -- + +let Extension = +{ + + _inputInSamFormatNodejs, + _inputInSamFormatBrowser, + + // argsInSamFormat : Config.interpreter === 'njs' ? _inputInSamFormatNodejs : _inputInSamFormatBrowser, + input : Config.interpreter === 'njs' ? _inputInSamFormatNodejs : _inputInSamFormatBrowser, + inputReadTo, + anchor, + + realMainFile, /* qqq : rewrite test. start process in test */ + realMainDir, /* qqq : rewrite test. start process in test */ + effectiveMainFile, /* qqq : rewrite test. start process in test */ + pathsRead, /* qqq : cover | aaa : Done. Yevhen S. */ + + systemEntryAdd, /* qqq : cover | aaa : Done. Yevhen S. */ + /* xxx qqq : implement stetemEntryRemove */ + +} + +/* _.props.extend */Object.assign( _.process, Extension ); +_.assert( _.routineIs( _.process.start ) ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/l3/Io.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Io_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Io_s */ })(); + +/* */ /* begin of file Path_ss */ ( function Path_ss() { function Path_ss_naked() { ( function _Path_ss_() +{ + +'use strict'; + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( _.object.isBasic( _.path ) ); + +// -- +// path +// -- + +/** + * Returns path for main module (module that running directly by node). + * @returns {String} + * @function realMainFile + * @namespace wTools.path + * @module Tools/mid/Files + */ + +function realMainFile() +{ + return _.process.realMainFile(); +} + +// + +/** + * Returns path dir name for main module (module that running directly by node). + * @returns {String} + * @function realMainDir + * @namespace wTools.path + * @module Tools/mid/Files + */ + +function realMainDir() +{ + return _.process.realMainDir(); +} + +// + +/** + * Returns absolute path for file running directly by node + * @returns {String} + * @throws {Error} If passed any argument. + * @function effectiveMainFile + * @namespace wTools.path + * @module Tools/mid/Files + */ + +function effectiveMainFile() +{ + return _.process.effectiveMainFile(); +} + +// + +/** + * Returns path dirname for file running directly by node + * @returns {String} + * @throws {Error} If passed any argument. + * @function effectiveMainDir + * @namespace wTools.path + * @module Tools/mid/Files + */ + +function effectiveMainDir() +{ + _.assert( arguments.length === 0, 'Expects no arguments' ); + + let result = this.dir( this.effectiveMainFile() ); + + return result; +} + +// -- +// declare +// -- + +let Extension = +{ + realMainFile, + realMainDir, + + effectiveMainFile, + effectiveMainDir, +}; + +Object.assign( _.path, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _.path; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/l3/Path.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Path_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Path_ss */ })(); + +/* */ /* begin of file Process_s */ ( function Process_s() { function Process_s_naked() { ( function _Process_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + require( './ProcessBasic.s' ); + module[ 'exports' ] = _global_.wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/module/Process.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/module' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Process_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Process_s */ })(); + +/* */ /* begin of file ProcessBasic_s */ ( function ProcessBasic_s() { function ProcessBasic_s_naked() { ( function _ProcessBasic_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to execute system commands, run shell, batches, launch external processes from JavaScript application. Module Process leverages not only outputting data from an application but also inputting, makes application arguments parsing and accounting easier. Use the module to get uniform experience from interaction with an external processes on different platforms and operating systems. + @module Tools/base/ProcessBasic +*/ + +if( typeof module !== 'undefined' ) +{ + require( '../include/Basic.s' ); + require( '../include/Mid.s' ); + module[ 'exports' ] = _global_.wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/module/ProcessBasic.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wprocess/proto/wtools/abase/l4_process/module' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, ProcessBasic_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file ProcessBasic_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wremote */ ( function wremote() { function wremote_naked() { +const _ = module.exports = require( '../wtools/amid/l3/remote/include/Mid.s' ); +_.module.predeclare +({ + alias : [ 'wRemote', 'wremote' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/node_modules/wremote' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wremote_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wremote */ })(); + +/* */ /* begin of file Base_s */ ( function Base_s() { function Base_s_naked() { ( function _Base_s_( ) { + +'use strict'; + +/* remote */ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../../../node_modules/Tools' ); + + _.include( 'wCopyable' ); + _.include( 'wEventHandler' ); + _.include( 'wConsequence' ); + _.include( 'wProcess' ); + _.include( 'wGdf' ); + +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/include/Base.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Base_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Base_s */ })(); + +/* */ /* begin of file Mid_s */ ( function Mid_s() { function Mid_s_naked() { ( function _Mid_s_( ) { + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + + require( './Base.s' ); + + require( '../l1/Namespace.s' ); + + require( '../l3/Agent.s' ); + require( '../l3/Flock.s' ); + require( '../l3/Representative.s' ); + + require( '../l5/Master.s' ); + require( '../l5/Slave.s' ); + +} + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _global_.wTools; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/include/Mid.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Mid_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Mid_s */ })(); + +/* */ /* begin of file Namespace_s */ ( function Namespace_s() { function Namespace_s_naked() { ( function _Namespace_s_( ) { + +'use strict'; + +const _ = _global_.wTools; +const Self = _.remote = _.remote || Object.create( null ); + +// -- +// inter +// -- + +function agentPathIs( agentPath ) +{ + + if( !_.strDefined( agentPath ) ) + return false; + + if( !_.strBegins( agentPath, '/master' ) && !_.strBegins( agentPath, '/slave' ) ) + return false; + + return true; +} + +// + +function roleFromAgentPath( agentPath ) +{ + _.assert( this.agentPathIs( agentPath ) ); + if( _.strBegins( agentPath, '/master' ) ) + return 'master'; + if( _.strBegins( agentPath, '/slave' ) ) + return 'slave'; + return undefined; +} + +// + +function idFromAgentPath( agentPath ) +{ + _.assert( this.agentPathIs( agentPath ) ); + if( _.strBegins( agentPath, '/master' ) ) + return Number( _.strRemoveBegin( agentPath, '/master' ) ); + if( _.strBegins( agentPath, '/slave' ) ) + return Number( _.strRemoveBegin( agentPath, '/slave' ) ); + return undefined; +} + +// + +function agentPathFromRole( role, id ) +{ + if( role === 'master' ) + if( id === null || id === undefined ) + { + id = 1; + } + + _.assert( id >= 1 ); + _.assert( ( role === 'master' ) ^ !( id === 1 ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.longHas( [ 'master', 'slave' ], role ) ); + + return `/${role}${id}`; +} + +// + +const attemptDefaults = +{ + attemptLimit : 3, + attemptDelay : 100, + attemptDelayMultiplier : 1, +}; + +_.assert( attemptDefaults.attemptLimit >= 1 ); +_.assert( attemptDefaults.attemptDelay >= 0 ); +_.assert( attemptDefaults.attemptDelay >= 1 ); + +// -- +// declare +// -- + +let Extension = +{ + + agentPathIs, + roleFromAgentPath, + idFromAgentPath, + agentPathFromRole, + + attemptDefaults, + +}; + +_.mapExtend( Self, Extension ); + +// + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _global_.wTools; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/l1/Namespace.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Namespace_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Namespace_s */ })(); + +/* */ /* begin of file Agent_s */ ( function Agent_s() { function Agent_s_naked() { ( function _Agent_s_() { + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + var Net = require( 'net' ); +} + +// + +const _ = _global_.wTools; +const Parent = null; +const Self = wRemoteAgent; +function wRemoteAgent( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'Agent'; + +// -- +// inter +// -- + +function finit() +{ + let agent = this; + agent.unform(); + _.Copyable.prototype.finit.call( agent ); +} + +// + +function init( o ) +{ + let agent = this; + + _.assert( arguments.length === 1 ); + + _.workpiece.initFields( agent ); + Object.preventExtensions( agent ); + + if( o ) + agent.copy( o ); + + return agent; +} + +// + +function unform() +{ + let agent = this; + let flock = agent.flock; + + agent.close(); + +/* +qqq : cover, please +*/ + +} + +// + +function form() +{ + let agent = this; + let flock = agent.flock; + + _.assert( agent.flock instanceof _.remote.Flock ); + + return agent._form(); +} + +// -- +// send +// -- + +function send( body ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + return agent._send + ({ + deserialized : { body }, + }); + +} + +// + +function _send( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.routineOptions( _send, arguments ); + _.mapOptionsApplyDefaults( o.deserialized, agent.Packet ); + _.assert( o.deserialized.recipient === null || _.remote.agentPathIs( o.deserialized.recipient ) ); + + if( o.deserialized.recipient ) + { + if( o.deserialized.recipient === agent.agentPath ) + { + _.assert( flock.role === 'master' ); + agent.masterRecieveGot({ deserialized : o.deserialized }); + return; + } + } + + if( o.connection === null ) + o.connection = flock.connectionDefaultGet(); + + if( o.serialized === null ) + { + o.serialized = agent._serialize( o.deserialized ); + } + + o.connection.write( o.serialized ); + +} + +_send.defaults = +{ + connection : null, + deserialized : null, + serialized : null, +} + +// + +function requestCall( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.assert( _.remote.agentPathIs( o.recipient ) ); + _.assert( _.longIs( o.args ) ); + _.assert( _.strDefined( o.routine ) ); + + if( o.context !== null ) + o.context = flock.handleFrom( o.context ); + o.object = flock.handleFrom( o.object ); + + if( o.context === o.object ) + o.context = null; + + _.assert( o.context === null || flock.PrimitiveHandleIs( o.context ) ); + _.assert( flock.PrimitiveHandleIs( o.object ) ); + + o.context = agent._pack({ structure : o.context }); + o.object = agent._pack({ structure : o.object }); + o.args = agent._pack({ structure : o.args }); + + let body = + { + object : o.object, + routine : o.routine, + args : o.args, + context : o.context, + } + + return agent.request + ({ + deserialized : + { + channel : 'call', + recipient : o.recipient, + body : body, + }, + }); + +} + +requestCall.defaults = +{ + recipient : null, + object : null, + routine : null, + args : null, + context : null, +} + +// + +function request( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + let request = agent._requestOpen( ... arguments ); + + agent._send( o ); + + return request; +} + +request.defaults = +{ + ... _send.defaults, +} + +// + +function _requestOpen( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.routineOptions( _requestOpen, arguments ); + _.mapOptionsApplyDefaults( o.deserialized, agent.Packet ); + _.assert( arguments.length === 1 ); + _.assert( o.deserialized.requestId === null ); + + agent.requestCounter += 1; + let id = agent.requestCounter; + o.deserialized.requestId = id; + + let request = + { + id, + deserialized : o.deserialized, + ready : _.Consequence(), + status : 1, + returned : _.undefined, + } + + _.assert( agent.requests[ id ] === undefined ); + + agent.requests[ id ] = request; + + return request; +} + +_requestOpen.defaults = +{ + ... request.defaults, +} + +// + +function _requestClose( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.routineOptions( _requestClose, arguments ); + + let request = agent.requests[ o.id ]; + _.assert( !!request, `Unknown request id ${o.id}` ); + _.assert( request.status === 1 ); + + if( o.unpacked === _.undefined ) + o.unpacked = agent._unpack({ structure : o.packed }); + + request.unpacked = o.unpacked; + request.packed = o.packed; + request.status = 2; + request.ready.take( o.unpacked ); + + delete agent.requests[ o.id ]; + + return request; +} + +_requestClose.defaults = +{ + id : null, + packed : _.undefined, + unpacked : _.undefined, +} + +// + +function _requestPerform( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.routineOptions( _requestPerform, arguments ); + + return _.Consequence.Try( () => + { + + if( o.unpacked === _.undefined ) + o.unpacked = agent._unpack({ structure : o.packed }); + + _.assert( _.longIs( o.unpacked.args ) ); + _.assert( o.id >= 1 ); + + let object = flock.localHandleToObject( o.unpacked.object ); + + _.assert( _.routineIs( object[ o.unpacked.routine ] ), `No such routine::${o.unpacked.routine}` ); + + let result = object[ o.unpacked.routine ]( ... o.unpacked.args ); + if( result === undefined ) + result = _.undefined; + return result; + }) + .then( ( result ) => + { + + let packet = + { + channel : 'response', + body : agent._pack({ structure : result }), + requestId : o.id, + } + + let o2 = + { + connection : o.connection || flock.connectionDefaultGet(), + deserialized : packet, + } + + agent._send( o2 ); + + return result; + }); +} + +_requestPerform.defaults = +{ + id : null, + packed : _.undefined, + unpacked : _.undefined, + connection : null, +} + +// + +function _serialize( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + let serialized; + try + { + _.assert( _.strDefined( o.channel ), 'Channel is not specified' ); + serialized = _.entity.exportJson( o ); + serialized = serialized.length + ' ' + serialized; + } + catch( err ) + { + err = _.err( err, `Agent::{${agent.agentPath}} failed to _serialize structure` ); + } + return serialized; +} + +_serialize.defaults = +{ + channel : null, + data : null, +} + +// + +function _deserialize( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + let converter = _.gdf.selectSingleContext({ inFormat : 'string', outFormat : 'structure', ext : 'json', single : 1 }) + let result = []; + + if( _.bufferAnyIs( o.data ) ) + o.data = _.bufferToStr( o.data ); + + let left = o.data; + + do + { + try + { + let size = parseFloat( left ); + _.assert( size > 0, () => `Failed to parse prologue of the package "${left.substring( 0, Math.max( left.length, 30 ) )}..."` ); + let sizeStr = String( size ); + let current = left.substring( sizeStr.length + 1, sizeStr.length + size + 1 ); + left = left.substring( sizeStr.length + size + 1, left.length ); + debugger; + let deserialized = converter.encode({ data : current }); + _.assert( _.mapIs( deserialized.data ) ); + // let deserialized = JSON.parse( o.data ); + result.push( deserialized.data ); + } + catch( err ) + { + err = _.err( err, `\nagent::{${agent.agentPath}} failed to parse recieved packet\n` ); + debugger; + throw err; + } + } + while( left.length ); + + return result; +} + +_deserialize.defaults = +{ + data : null, +} + +// + +function _pack( o ) +{ + let agent = this; + let flock = agent.flock; + return o.structure; +} + +_pack.defaults = +{ + structure : null, +} + +// + +function _unpack( o ) +{ + let agent = this; + let flock = agent.flock; + return o.structure; +} + +_unpack.defaults = +{ + structure : null, +} + +// -- +// common +// -- + +function close() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + return agent._close(); +} + +// + +function commonRecieveGot( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.routineOptions( commonRecieveGot, arguments ); + + if( o.deserialized === null ) + o.deserialized = agent._deserialize({ data : o.serialized }); + + if( _.longIs( o.deserialized ) ) + { + for( let d = 0 ; d < o.deserialized.length ; d++ ) + agent.commonRecieveGot + ({ + deserialized : o.deserialized[ d ], + connection : o.connection, + }); + return; + } + + if( o.deserialized.recipient ) + { + if( o.deserialized.recipient !== agent.agentPath ) + { + agent._send + ({ + deserialized : o.deserialized, + }); + flock.log( -5, `resend . ${o.deserialized.body}` ); + return; + } + } + + if( o.deserialized.channel !== null ) + { + _.assert( _.strDefined( o.deserialized.channel ) ); + let methodName = `_channel${_.strCapitalize( o.deserialized.channel )}`; + _.sure( _.routineIs( agent[ methodName ] ), `Unknown channel ${o.deserialized.channel}` ); + agent[ methodName ]( o ); + } + + flock.log( -5, `recieved . ${o.deserialized.channel} . ${o.deserialized.body}` ); +} + +commonRecieveGot.defaults = +{ + serialized : null, + deserialized : null, + connection : null, +} + +// + +function commonErrorGot( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + logger.error( _.errOnce( `Error of ${agent.agentPath || flock.role}\n`, o.err ) ); + + agent.masterCloseSoonMaybe(); + + flock.eventGive + ({ + kind : 'errorGot', + representative : !o.connection ? null : flock.connectionToRepresentative( o.connection ), + err : o.err, + }); + +} + +commonErrorGot.defaults = +{ + err : null, + connection : null, +} + +// + +function _channelMessage( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + flock.eventGive + ({ + kind : 'channelMessage', + representative : !o.connection ? null : flock.connectionToRepresentative( o.connection ), + message : o.deserialized.body, + }); + +} + +// + +function _channelCall( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + return agent._requestPerform + ({ + id : o.deserialized.requestId, + packed : o.deserialized.body, + connection : o.connection, + }); +} + +// + +function _channelResponse( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + return agent._requestClose + ({ + id : o.deserialized.requestId, + packed : o.deserialized.body, + }); +} + +// + +function _channelIdentity( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + agent.slaveConnectEnd + ({ + connection : o.connection, + attempt : agent._connectAttemptsMade, + id : o.deserialized.body.id, + }); + +} + +// -- +// slave +// -- + +function slaveOpenSlave( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.routineOptions( slaveOpenSlave, o ); + + debugger; + + if( flock.role === 'master' ) + { + + return agent.masterSlaveOpen() + .then( ( slaveFlock ) => + { + debugger; + return slaveFlock.object; + }); + + } + else + { + + let body = + { + object : 'agent', + routine : 'slaveOpenSlave', + args : [], + } + + return agent.request + ({ + deserialized : + { + channel : 'call', + recipient : '/master1', + body : body, + }, + }); + + } + +} + +slaveOpenSlave.defaults = +{ +} + +// + +function slaveOpenMaster() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + flock.masterPath = flock.freeLocalMasterPathFind(); + + _.assert( _.strDefined( flock.masterPath ) ); + _.assert( _.strDefined( flock.entryPath ) ); + _.assert( agent._process === null ); + + let result = agent._process = _.process.startNjs + ({ + execPath : flock.entryPath, + args : `role:master masterPath:${flock.masterPath}`, + sync : 0, + deasync : 0, + detaching : 1, + stdio : 'pipe', + }); + + result.then( ( process ) => + { + _.assert( agent._process === result ); + agent._process = process; + return process; + }); + + return result; +} + +// + +function slaveConnectMaster() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + let masterPathParsed = _.uri.parse( flock.masterPath ); + masterPathParsed.port = _.numberFromStrMaybe( masterPathParsed.port ); + + agent._connectAttemptsMade += 1; + + let attempt = agent._connectAttemptsMade; + + _.assert( _.numberDefined( masterPathParsed.port ) ); + _.assert( flock.role === 'slave' ); + _.assert( flock.connections.length === 0 ); + _.assert( agent._connectAttemptsMade <= flock.connectAttempts ); + _.assert( agent._connectStatus === 'closed' ); + + agent.slaveConnectBegin({ attempt }); + + let o2 = { port : masterPathParsed.port }; + let connection = Net.createConnection( o2, () => agent.slaveConnectEndWaitingForIdentity({ attempt, connection }) ); + + flock.connections.push( connection ); + + connection.on( 'data', ( data ) => agent.slaveRecieveGot({ serialized : data }) ); + connection.on( 'error', ( err ) => agent.slaveErrorGot({ err }) ); + connection.on( 'end', () => agent.slaveDisconnectEnd({ connection, attempt }) ) + + let ready = _.Consequence(); + + flock.once( 'connectEnd', connectEnd ); + flock.once( 'errorGot', errorGot ); + + return ready; + + function connectEnd( e ) + { + flock.off( 'connectEnd', connectEnd ); + flock.off( 'errorGot', errorGot ); + ready.take( flock.master ); + } + + function errorGot( e ) + { + flock.off( 'connectEnd', connectEnd ); + flock.off( 'errorGot', errorGot ); + ready.error( e.error ); + } + +} + +// + +function slaveConnectMasterMaybe() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + if( _.longHas( [ 'closed', 'connecting', 'connection.waiting.for.identity' ], agent._connectStatus ) ) + if( flock.connectAttempts > agent._connectAttemptsMade ) + { + _.time.begin( flock.connectAttemptDelay, () => agent.slaveConnectMaster() ); + return true; + } + + return false; +} + +// + +function slaveDisconnectMaster() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + agent._connectStatus = 'closed'; + + if( flock.connections.length ) + { + _.assert( flock.connections.length === 1 ); + flock.connections[ 0 ].end(); + } + + if( agent._process ) + { + let process = agent._process; + agent._process = null; + process.disconnect(); + + /* yyy */ + process.conTerminate.catch( err => + { + if( err.reason != 'disconnected' ) + throw err; + _.errAttend( err ); + return process; + }) + /* yyy */ + + } + +} + +// + +function slaveIsConnected() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + return !!flock.connections.length; +} + +// + +function slaveConnectBegin( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.assert( agent._connectStatus === 'closed' ); + agent._connectStatus = 'connecting'; + + flock.eventGive + ({ + kind : 'connectBegin', + attempt : o.attempt, + }); + + flock.log( -7, `slaveConnectBegin. Attempt ${agent._connectAttemptsMade} / ${flock.connectAttempts}` ); +} + +slaveConnectBegin.defaults = +{ + attempt : null, +} + +// + +function slaveConnectEndWaitingForIdentity( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.assert( !!o.connection ); + _.assert( agent._connectStatus === 'connecting' ); + agent._connectStatus = 'connection.waiting.for.identity'; + + flock.master = flock.representativeMake + ({ + agentPath : _.remote.agentPathFromRole( 'master' ), + connection : o.connection, + }) + + flock.eventGive + ({ + kind : 'connectEndWaitingForIdentity', + attempt : o.attempt, + representative : flock.master, + }); + + flock.log( -7, `slaveConnectEndWaitingForIdentity` ); +} + +slaveConnectEndWaitingForIdentity.defaults = +{ + connection : null, + attempt : null, +} + +// + +function slaveConnectEnd( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.assert( !!o.connection ); + _.assert( agent._connectStatus === 'connection.waiting.for.identity' ); + agent._connectStatus = 'connected'; + + /* qqq : write explanation for every assert. ask how to */ + + _.assert( flock.role === 'slave' ); + _.assert( agent.id === 0 ); + _.assert( o.id >= 2 ); + _.assert( _.numberIs( o.id ) ); + agent.id = o.id; + _.assert( agent.agentPath === null ); + agent.agentPath = _.remote.agentPathFromRole( flock.role, agent.id ); + + flock.eventGive + ({ + kind : 'connectEnd', + attempt : o.attempt, + representative : flock.master, + }); + + flock.log( -7, `slaveConnectEnd` ); +} + +slaveConnectEnd.defaults = +{ + connection : null, + attempt : null, + id : null, +} + +// + +function slaveDisconnectEnd( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + flock.log( -7, `slaveDisconnectEnd` ); + + _.assert( flock.connections.length === 1 ); + _.assert( flock.connections[ 0 ] === o.connection ) + + flock.connections.splice( 0, 1 ); +} + +slaveDisconnectEnd.defaults = +{ + connection : null, + attempt : null, +} + +// + +function slaveRecieveGot( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + _.routineOptions( slaveRecieveGot, arguments ); + if( o.connection === null ) + o.connection = flock.connectionDefaultGet(); + return agent.commonRecieveGot( o ); +} + +slaveRecieveGot.defaults = +{ + ... commonRecieveGot.defaults, +} + +// + +function slaveErrorGot( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + debugger; + try + { + if( !flock.connectionIsAlive( flock.connections[ 0 ] ) ) + { + flock.connections.splice( 0, 1 ); + agent.slaveDisconnectMaster(); + if( agent.slaveConnectMasterMaybe() ) + return; + } + } + catch( err ) + { + logger.error( _.errOnce( 'slaveErrorGot error\n', err ) ); + } + + if( !o.connection ) + try + { + if( flock.connections.length ) + o.connection = flock.connectionDefaultGet(); + } + catch( err ) + { + logger.error( _.errOnce( 'slaveErrorGot error\n', err ) ); + } + + return agent.commonErrorGot( o ); +} + +slaveErrorGot.defaults = +{ + ... commonErrorGot.defaults, +} + +// -- +// master +// -- + +function masterOpen() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.assert( flock.agentCounter === 0 ); + flock.agentCounter += 1; + _.assert( agent.id === 0 ); + agent.id = flock.agentCounter; + _.assert( agent.agentPath === null ); + agent.agentPath = _.remote.agentPathFromRole( flock.role, agent.id ); + + agent.masterOpenBegin(); + + if( !flock.masterPath ) + flock.masterPath = flock.freeLocalMasterPathFind(); + + _.assert( !!flock.masterPath ); + let masterPathParsed = _.uri.parse( flock.masterPath ); + masterPathParsed.port = _.numberFromStrMaybe( masterPathParsed.port ); + _.assert( _.numberDefined( masterPathParsed.port ) ); + + agent.server = Net.createServer( ( connection ) => + { + agent.masterConnectBegin({}); + connection + .on( 'data', ( data ) => agent.masterRecieveGot({ connection, serialized : data }) ) + .on( 'end', () => agent.masterDisconnectEnd({ connection }) ) + .on( 'error', ( err ) => agent.masterErrorGot({ connection, err }) ) + ; + agent.masterConnectEnd({ connection }); + }) + .on( 'error', ( err ) => agent.masterErrorGot({ err }) ) + .on( 'close', () => agent.masterCloseEnd() ) + ; + + agent.server.listen( masterPathParsed.port, () => agent.masterOpenEnd() ); + + return agent; +} + +// + +function masterClose() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.assert( !!agent.server ); + + agent.masterCloseBegin(); + + agent.server.close(); + + return agent; +} + +// + +function masterIsOpened() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + return !!agent.server; +} + +// + +function masterCloseSoonMaybe() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + if( !agent.masterCloseCan() ) + return false; + + agent.terminationTimer = _.time.begin( flock.terminationPeriod, () => agent._masterCloseMaybe() ); + + return true; +} + +// + +function masterCloseSoonCancel() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + if( agent.terminationTimer ) + { + agent.terminationTimer = _.time.cancel( agent.terminationTimer ); + agent.terminationTimer = null; + } + +} + +// + +function _masterCloseMaybe() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + if( agent.masterCloseCan() ) + agent.masterClose(); + +} + +// + +function masterCloseCan() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + if( flock.connections.length ) + return false; + + return true; +} + +// + +function masterCloseBegin() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; +} + +// + +function masterCloseEnd() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + agent.server = null; + _.assert( flock.connections.length === 0 ); /* qqq : reproduce the case when this assertion fails */ +} + +// + +function masterOpenBegin() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.assert( agent._connectStatus === 'closed' ); + agent._connectStatus = 'opening'; + + _.time.out( flock.terminationOnOpeningExtraPeriod, () => agent.masterCloseSoonMaybe() ); + +} + +// + +function masterOpenEnd() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.assert( agent._connectStatus === 'opening' ); + agent._connectStatus = 'opened'; + + flock.log( -7, `opened server on port::${agent.server.address().port}` ); +} + +// + +function masterConnectBegin( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.assert( !o.connection ); + + agent.masterCloseSoonCancel(); + + flock.eventGive + ({ + kind : 'connectBegin', + }); + +} + +masterConnectBegin.defaults = +{ +} + +// + +function masterConnectEnd( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.assert( !!o.connection ); + + _.arrayAppendOnceStrictly( flock.connections, o.connection ); + + flock.agentCounter += 1; + let id = flock.agentCounter; + let agentPath = _.remote.agentPathFromRole( 'slave', id ); + + _.assert( id >= 2 ); + + let representative = flock.representativeMake + ({ + agentPath, + connection : o.connection, + }); + + _.assert( flock.representativesMap[ id ] === representative ); + _.assert( id === representative.id ); + _.assert( o.connection === representative.connection ); + + agent._send + ({ + connection : o.connection, + deserialized : + { + channel : 'identity', + body : { id } + } + }); + + flock.eventGive + ({ + kind : 'connectEnd', + representative, + }); + + flock.log( -7, `${o.connection.remoteAddress} connected. ${flock.connections.length} connection(s)` ); + +} + +masterConnectEnd.defaults = +{ + connection : null, +} + +// + +function masterDisconnectEnd( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + _.arrayRemoveOnceStrictly( flock.connections, o.connection ); + + agent.masterCloseSoonMaybe(); + + flock.log( -7, `${o.connection.remoteAddress} disconnected. ${flock.connections.length} connection(s)` ); +} + +masterDisconnectEnd.defaults = +{ + connection : null, +} + +// + +function masterRecieveGot( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + _.routineOptions( masterRecieveGot, arguments ); + + return agent.commonRecieveGot( ... arguments ); +} + +masterRecieveGot.defaults = +{ + ... commonRecieveGot.defaults, +} + +// + +function masterErrorGot( o ) +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + return agent.commonErrorGot( o ); +} + +masterErrorGot.defaults = +{ + ... commonErrorGot.defaults, +} + +// -- +// relations +// -- + +let Packet = +{ + recipient : null, + requestId : null, + channel : 'message', + body : null, +} + +let Composes = +{ +} + +let Associates = +{ + flock : null, +} + +let Restricts = +{ + + agentPath : null, + + server : null, + _process : null, + + terminationTimer : null, + + id : 0, + _connectAttemptsMade : 0, + _connectStatus : 'closed', + + requestCounter : 0, + requests : _.define.own( {} ), + +} + +let Statics = +{ + + Packet, + +} + +let Forbids = +{ + + terminationPeriod : 'terminationPeriod', + terminationOnOpeningExtraPeriod : 'terminationOnOpeningExtraPeriod', + slaveDelay : 'slaveDelay', + masterDelay : 'masterDelay', + connectAttempts : 'connectAttempts', + connectAttemptDelay : 'connectAttemptDelay', + role : 'role', + entryPath : 'entryPath', + masterPath : 'masterPath', + agentCounter : 'agentCounter', + agent : 'agent', + master : 'master', + representativesMap : 'representativesMap', + connectionToRepresentativeHash : 'connectionToRepresentativeHash', + objectCounter : 'objectCounter', + idToHandleDescriptorHash : 'idToHandleDescriptorHash', + nameToHandleDescriptorHash : 'nameToHandleDescriptorHash', + objectToHandleDescriptorHash : 'objectToHandleDescriptorHash', + object : 'object', + +} + +let Accessor = +{ +} + +// -- +// prototype +// -- + +let Proto = +{ + + // inter + + finit, + init, + unform, + form, + _form : null, + + // send + + send, + _send, + + requestCall, + request, + _requestOpen, + _requestClose, + _requestPerform, + + _serialize, + _deserialize, + _pack, + _unpack, + + // common + + close, + _close : null, + + commonRecieveGot, + commonErrorGot, + + _channelMessage, + _channelCall, + _channelResponse, + _channelIdentity, + + // slave + + slaveOpenSlave, + slaveOpenMaster, + slaveConnectMaster, + slaveConnectMasterMaybe, + slaveDisconnectMaster, + slaveIsConnected, + + slaveConnectBegin, + slaveConnectEndWaitingForIdentity, + slaveConnectEnd, + slaveDisconnectEnd, + slaveRecieveGot, + slaveErrorGot, + + // master + + masterOpen, + masterClose, + masterIsOpened, + masterCloseSoonMaybe, + masterCloseSoonCancel, + _masterCloseMaybe, + masterCloseCan, + + masterCloseBegin, + masterCloseEnd, + masterOpenBegin, + masterOpenEnd, + masterConnectBegin, + masterConnectEnd, + masterDisconnectEnd, + masterRecieveGot, + masterErrorGot, + + // relations + + Composes, + Associates, + Restricts, + Statics, + Forbids, + Accessor, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); + +_.Copyable.mixin( Self ); + +// + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; +_.remote[ Self.shortName ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/l3/Agent.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Agent_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Agent_s */ })(); + +/* */ /* begin of file Flock_s */ ( function Flock_s() { function Flock_s_naked() { ( function _Flock_s_() { + +'use strict'; + +// + +const _ = _global_.wTools; +const Parent = null; +const Self = wRemoteFlock; +function wRemoteFlock( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'Flock'; + +// -- +// inter +// -- + +function finit() +{ + let flock = this; + flock.unform(); + _.Copyable.prototype.finit.call( flock ); +} + +// + +function init( o ) +{ + let flock = this; + + _.assert( arguments.length === 1 ); + + _.workpiece.initFields( flock ); + Object.preventExtensions( flock ); + + if( o ) + flock.copy( o ); + + return flock; +} + +// + +function unform() +{ + let flock = this; + + flock.agent.finit(); + +/* +qqq : cover, please +*/ + +} + +// + +function form() +{ + let flock = this; + let ready = _.Consequence().take( null ); + + if( flock.logger === null ) + { + flock.logger = new _.Logger({ output : _global_.logger }); + flock.logger.verbosity = 7; + } + + let logger = flock.logger; + + // debugger; + // _.process.on( 'exit', flock, () => + _.process.on( 'exit', () => + { + flock.exitGot(); + }); + // debugger; + + ready.then( () => flock.roleDetermine() ); + + ready.then( ( arg ) => + { + flock.enterGot(); + + if( flock.role === 'slave' ) + { + flock.agent = new _.remote.Slave({ flock }); + } + else + { + flock.agent = new _.remote.Master({ flock }); + } + + return flock.agent.form(); + }); + + return ready; +} + +// -- +// etc +// -- + +function close() +{ + let flock = this; + let logger = flock.logger; + + if( flock.agent ) + flock.agent.close(); + +} + +// + +function connectionIs( connection ) +{ + let flock = this; + return _.objectIs( connection ); +} + +// + +function connectionIsAlive( connection ) +{ + let flock = this; + _.assert( connection.destroyed !== undefined ); + return !connection.destroyed; +} + +// + +function connectionDefaultGet() +{ + let flock = this; + _.assert( flock.connections.length === 1 ); + return flock.connections[ 0 ]; +} + +// + +function connectionToRepresentative( connection ) +{ + let flock = this; + _.assert( flock.connectionIs( connection ) ); + return flock.connectionToRepresentativeHash.get( connection ); +} + +// + +function roleDetermine() +{ + let flock = this; + + if( flock.role !== null ) + return end(); + + if( flock.masterPath === null || flock.masterPath === undefined ) + flock.masterPath = flock.openedRemoteMasterPathFind(); + + if( flock.masterPath ) + return end( 'slave' ); + + flock._roleDetermine(); + + return end(); + + function end( role ) + { + if( role !== undefined ) + flock.role = role; + _.assert( _.longHas( [ 'slave', 'master' ], flock.role ), () => `Unknown role ${flock.role}` ); + + return flock.role; + } +} + +// + +function _roleDetermine() +{ + let flock = this; + + _.assert( flock.role === null ); + + let args = _.process.input(); + + if( args.map.role !== undefined ) + { + flock.role = args.map.role; + } + else + { + flock.role = 'slave'; + } + + return flock.role; +} + +// + +function format() +{ + let flock = this; + let logger = flock.logger; + return [ `${flock.role} .`, ... arguments ]; +} + +// + +function log( level, ... msgs ) +{ + let flock = this; + let logger = flock.logger; + + logger.begin({ verbosity : level }); + logger.log( ... flock.format( ... msgs ) ); + logger.end({ verbosity : level }); + +} + +// + +function representativeMake( o ) +{ + let flock = this; + let logger = flock.logger; + + o.flock = flock; + + return _.remote.Representative( o ); +} + +// -- +// handle +// -- + +function LocalHandleIs( src ) +{ + if( _.numberIs( src ) ) + return true; + if( _.strIs( src ) ) + return true; + return false; +} + +// + +function localHandleToObjectDescriptor( key ) +{ + let flock = this; + _.assert( _.strIs( key ) || _.numberIs( key ) ); + if( _.strIs( key ) ) + return flock.nameToHandleDescriptorHash.get( key ); + else + return flock.idToHandleDescriptorHash.get( key ); +} + +// + +function objectToLocalHandleDescriptor( object ) +{ + let flock = this; + return flock.objectToHandleDescriptorHash.get( object ); +} + +// + +function localHandleToObject( key ) +{ + let flock = this; + let desc = flock.localHandleToObjectDescriptor( key ); + if( !desc ) + return; + return desc.object; +} + +// + +function objectToId( object ) +{ + let flock = this; + let desc = flock.objectToLocalHandleDescriptor( object ); + if( !desc ) + return; + return desc.id; +} + +// + +function localHandlesAdd( o ) +{ + let flock = this; + + _.routineOptions( localHandlesAdd, arguments ); + + let result = _.map_( null, o.objects, ( object, k ) => + { + if( _.numberIs( k ) ) + return flock._localHandleAdd({ object }); + else + return flock._localHandleAdd({ object, name : k }); + }); + + return result; +} + +localHandlesAdd.defaults = +{ + objects : null, +} + +// + +function _localHandleAdd( o ) +{ + let flock = this; + let desc; + + _.assert( o.object !== undefined && o.object !== null ); + _.routineOptions( _localHandleAdd, arguments ); + _.assert( o.name === null || _.strDefined( o.name ) ); + + desc = flock.objectToHandleDescriptorHash.get( o.object ); + if( desc ) + { + _.assert( desc.name === o.name, `Object already added with name ${desc.name}. Cant change name to ${o.name}` ); + return desc; + } + + if( o.name ) + { + desc = flock.nameToHandleDescriptorHash.get( o.name ); + if( desc ) + { + debugger; + throw _.err( `Object with name ${o.name} already exists. Cant overwrite it.` ); + } + } + + flock.objectCounter += 1; + + desc = Object.create( null ); + desc.id = flock.objectCounter; + desc.name = o.name; + desc.object = o.object; + + flock.idToHandleDescriptorHash.set( desc.id, desc ); + if( o.name ) + flock.nameToHandleDescriptorHash.set( desc.name, desc ); + flock.objectToHandleDescriptorHash.set( desc.object, desc ); + + return desc; +} + +_localHandleAdd.defaults = +{ + name : null, + object : null, +} + +// + +function localHandlesRemoveObjects( objects ) +{ + let flock = this; + + _.routineOptions( localHandlesRemoveObjects, arguments ); + + let result = _.map_( null, objects, ( object, k ) => + { + return flock.localHandlesRemoveObject( object ); + }); + + return result; +} + +// + +function localHandlesRemoveObject( object ) +{ + let flock = this; + + let desc = flock.objectToHandleDescriptorHash.get( object ); + + _.assert( !!desc, () => `Cant remove object. It was not added` ); + + return result; +} + +// + +function PrimitiveHandleIs( src ) +{ + if( _.numberIs( src ) ) + return true; + if( _.strIs( src ) ) + return true; + return false; +} + +// + +function RemoteHandleIs( src ) +{ + if( !_.objectIs( src ) ) + return false; + if( !src[ twinSymbol ] ) + return false; + return true; +} + +// + +function handleFrom( src ) +{ + let flock = this; + let result = src; + if( flock.RemoteHandleIs( result ) ) + result = src[ twinSymbol ].handle; + _.assert( flock.PrimitiveHandleIs( result ) ); + return result; +} + +// -- +// communication +// -- + +function send( body ) +{ + let flock = this; + let agent = flock.agent; + return agent.send( ... arguments ); +} + +// + +function openedRemoteMasterPathFind() +{ + let flock = this; + let logger = flock.logger; + return null; +} + +// + +function freeLocalMasterPathFind() +{ + let flock = this; + let logger = flock.logger; + return 'http://0.0.0.0:13000'; +} + +// + +function enterGot() +{ + let flock = this; + let logger = flock.logger; + flock.log( -5, `enter` ); +} + +// + +function exitGot() +{ + let flock = this; + let logger = flock.logger; + flock.log( -5, `exit` ); +} + +// -- +// relations +// -- + +let twinSymbol = Symbol.for( 'twin' ); + +let Composes = +{ + + terminationPeriod : 5000, + terminationOnOpeningExtraPeriod : 5000, + slaveDelay : 1000, + masterDelay : 0, + + connectAttempts : 2, + connectAttemptDelay : 250, + + role : null, + entryPath : null, + masterPath : null, + +} + +let Associates = +{ + + logger : null, + +} + +let Restricts = +{ + + agentCounter : 0, + agent : null, + master : null, + + connections : _.define.own( [] ), + representativesMap : _.define.own( {} ), + connectionToRepresentativeHash : _.define.own( new HashMap ), + + objectCounter : 0, + idToHandleDescriptorHash : _.define.own( new HashMap ), + nameToHandleDescriptorHash : _.define.own( new HashMap ), + objectToHandleDescriptorHash : _.define.own( new HashMap ), + +} + +let Events = +{ + + errorGot : {}, + + connectBegin : {}, + connectEndWaitingForIdentity : {}, + connectEnd : {}, + + channelMessage : {}, + +} + +let Statics = +{ + + LocalHandleIs, + PrimitiveHandleIs, + RemoteHandleIs, + +} + +let Forbids = +{ + + object : 'object', + agentPath : 'agentPath', + server : 'server', + _process : '_process', + terminationTimer : 'terminationTimer', + id : 'id', + _connectAttemptsMade : '_connectAttemptsMade', + _connectStatus : '_connectStatus', + requestCounter : 'requestCounter', + requests : 'requests', + +} + +let Accessor = +{ +} + +// -- +// prototype +// -- + +let Proto = +{ + + // inter + + finit, + init, + unform, + form, + + // etc + + close, + connectionIs, + connectionIsAlive, + connectionDefaultGet, + connectionToRepresentative, + + roleDetermine, + _roleDetermine, + format, + log, + + representativeMake, + + // handles + + LocalHandleIs, + + localHandleToObjectDescriptor, + objectToLocalHandleDescriptor, + localHandleToObject, + objectToId, + + localHandlesAdd, + _localHandleAdd, + + localHandlesRemoveObjects, + localHandlesRemoveObject, + + PrimitiveHandleIs, + RemoteHandleIs, + handleFrom, + + // communication + + send, + openedRemoteMasterPathFind, + freeLocalMasterPathFind, + + enterGot, + exitGot, + + // relations + + Composes, + Associates, + Restricts, + Events, + Statics, + Forbids, + Accessor, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); + +_.Copyable.mixin( Self ); +_.EventHandler.mixin( Self ); + +// + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; +_.remote[ Self.shortName ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/l3/Flock.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Flock_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Flock_s */ })(); + +/* */ /* begin of file Representative_s */ ( function Representative_s() { function Representative_s_naked() { ( function _Representative_s_() { + +'use strict'; + +// + +const _ = _global_.wTools; +const Parent = null; +const Self = wRepresentative; +function wRepresentative( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'Representative'; + +// -- +// inter +// -- + +function finit() +{ + let representative = this; + representative.unform(); + _.Copyable.prototype.finit.call( representative ); +} + +// + +function init( o ) +{ + let representative = this; + + _.assert( arguments.length === 1 ); + + _.workpiece.initFields( representative ); + Object.preventExtensions( representative ); + + if( o ) + representative.copy( o ); + + representative.preform(); + + return representative; +} + +// + +function unform() +{ + let representative = this; + let flock = representative.flock; + + _.assert( flock.representativesMap[ representative.id ] === representative ); + _.assert( flock.connectionToRepresentativeHash.get( representative.connection ) === representative ); + _.asert( representative.role !== 'master' || flock.master === representative ); + + if( representative.role === 'master' ) + flock.master = null; + delete flock.representativesMap[ representative.id ]; + flock.connectionToRepresentativeHash.remove( representative.connection ); + +} + +// + +function preform() +{ + let representative = this; + let flock = representative.flock; + + if( representative.role === null ) + representative.role = _.remote.roleFromAgentPath( representative.agentPath ); + if( representative.agentPath === null ) + representative.agentPath = _.remote.agentPathFromRole( representative.role ); + if( representative.id === null ) + representative.id = _.remote.idFromAgentPath( representative.agentPath ); + + _.assert( _.strDefined( representative.role ) ); + _.assert( _.strDefined( representative.agentPath ) ); + _.assert( representative.id >= 1 ); + _.assert( !!representative.connection ); + _.assert( !!representative.flock ); + _.assert( flock.representativesMap[ representative.id ] === undefined ); + _.assert( !flock.connectionToRepresentativeHash.has( representative.connection ) ); + + flock.representativesMap[ representative.id ] = representative; + flock.connectionToRepresentativeHash.set( representative.connection, representative ); + if( representative.role === 'master' ) + flock.master = representative; + +} + +// + +function form() +{ + let representative = this; + let ready = _.Consequence().take( null ); + + return ready; +} + +// -- +// twin +// -- + +function handleToTwin( o ) +{ + let representative = this; + + if( _.numberIs( o ) || _.strIs( o ) ) + o = { handle : arguments[ 0 ] } + + _.routineOptions( handleToTwin, o ); + + _.assert( arguments.length === 1 ); + + o.representative = representative; + + let handlers = + { + get : representative.TwinProxyGet, + set : representative.TwinProxySet, + }; + + let proxy = new Proxy( o, handlers ); + + return proxy; +} + +handleToTwin.defaults = +{ + handle : null, +} + +// + +function TwinProxyGet( op, propName, proxy ) +{ + let representative = op.representative; + let handle = op.handle; + let flock = representative.flock; + + if( propName === twinSymbol ) + return op; + if( _.symbolIs( propName ) ) + return undefined; + + let r = + { + [ propName ] : function() + { + _.assert( this === proxy ); + return flock.agent.requestCall + ({ + recipient : representative.agentPath, + object : handle, + context : this, + routine : propName, + args : arguments, + }).ready; + } + } + + return r[ propName ]; +} + +// + +function TwinProxySet( op, propName, value, proxy ) +{ + debugger; + _.assert( 0 ); +} + +// -- +// relations +// -- + +let twinSymbol = Symbol.for( 'twin' ); + +let Composes = +{ +} + +let Associates = +{ + flock : null, + connection : null, + id : null, + role : null, + agentPath : null, +} + +let Restricts = +{ +} + +let Statics = +{ +} + +let Forbids = +{ +} + +let Accessor = +{ +} + +// -- +// prototype +// -- + +let Proto = +{ + + // inter + + finit, + init, + unform, + preform, + form, + + // twin + + handleToTwin, + TwinProxyGet, + TwinProxySet, + + // relations + + Composes, + Associates, + Restricts, + Statics, + Forbids, + Accessor, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); + +_.Copyable.mixin( Self ); +_.EventHandler.mixin( Self ); + +// + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; +_.remote[ Self.shortName ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/l3/Representative.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Representative_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Representative_s */ })(); + +/* */ /* begin of file Master_s */ ( function Master_s() { function Master_s_naked() { ( function _Master_s_() { + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + var Net = require( 'net' ); +} + +// + +const _ = _global_.wTools; +const Parent = _.remote.Agent; +const Self = wRemoteAgentMaster; +function wRemoteAgentMaster( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'Master'; + +// -- +// inter +// -- + +function _form() +{ + let agent = this; + let flock = agent.flock; + let ready = _.Consequence().take( null ); + + ready.then( () => _.time.out( flock.masterDelay ) ); + ready.then( () => agent.masterOpen() ); + + return ready; +} + +// + +function _close() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + if( agent.masterIsOpened() ) + agent.masterClose(); + +} + +// -- +// relations +// -- + +let Composes = +{ +} + +let Associates = +{ +} + +let Restricts = +{ +} + +let Events = +{ + +} + +let Statics = +{ +} + +let Forbids = +{ + object : 'object', + role : 'role', +} + +let Accessor = +{ +} + +// -- +// prototype +// -- + +let Proto = +{ + + // inter + + _form, + _close, + + // relations + + Composes, + Associates, + Restricts, + Events, + Statics, + Forbids, + Accessor, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); + +// + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; +_.remote[ Self.shortName ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/l5/Master.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Master_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Master_s */ })(); + +/* */ /* begin of file Slave_s */ ( function Slave_s() { function Slave_s_naked() { ( function _Slave_s_() { + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + var Net = require( 'net' ); +} + +// + +const _ = _global_.wTools; +const Parent = _.remote.Agent; +const Self = wRemoteAgentSlave; +function wRemoteAgentSlave( o ) +{ + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'Slave'; + +// -- +// inter +// -- + +function _form() +{ + let agent = this; + let flock = agent.flock; + let ready = _.Consequence().take( null ); + + if( !flock.masterPath ) + { + ready.then( () => agent.slaveOpenMaster() ); + ready.then( () => _.time.out( flock.slaveDelay ) ); + } + + ready.then( () => agent.slaveConnectMaster() ); + + return ready; +} + +// + +function _close() +{ + let agent = this; + let flock = agent.flock; + let logger = flock.logger; + + if( agent.slaveIsConnected() ) + agent.slaveDisconnectMaster(); + +} + +// -- +// relations +// -- + +let Composes = +{ +} + +let Associates = +{ +} + +let Restricts = +{ +} + +let Events = +{ + +} + +let Statics = +{ +} + +let Forbids = +{ + object : 'object', + role : 'role', +} + +let Accessor = +{ +} + +// -- +// prototype +// -- + +let Proto = +{ + + // inter + + _form, + _close, + + // relations + + Composes, + Associates, + Restricts, + Events, + Statics, + Forbids, + Accessor, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + extend : Proto, +}); + +// + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; +_.remote[ Self.shortName ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/l5/Slave.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wremote/proto/wtools/amid/l3/remote/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Slave_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Slave_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wreplicator/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wreplicator/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wreplicator */ ( function wreplicator() { function wreplicator_naked() { +module.exports = require( '../wtools/abase/l4/Replicator.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wReplicator', 'wreplicator' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wreplicator/proto/node_modules/wreplicator' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wreplicator/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wreplicator_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wreplicator */ })(); + +/* */ /* begin of file Replicator_s */ ( function Replicator_s() { function Replicator_s_naked() { ( function _Replicator_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to replicate a complex data structure. It traverse input data structure deeply producing a copy of it.Collection of cross-platform routines to replicate a complex data structure. It traverses input data structure deeply producing a copy of it. + @module Tools/base/Replicator + @extends Tools +*/ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + + _.include( 'wLooker' ); + +} + +const _global = _global_; +const _ = _global_.wTools +const Parent = _.looker.Looker; +_.replicator = _.replicator || Object.create( _.looker ); + +_.assert( !!_realGlobal_ ); + +/* qqq : write nice example for readme */ + +// -- +// relations +// -- + +var Prime = Object.create( null ); +Prime.src = undefined; +Prime.dst = undefined; + +// -- +// implementation +// -- + +function optionsFromArguments( args ) +{ + let o = args[ 0 ]; + + if( args.length === 2 ) + { + o = { dst : args[ 0 ], src : args[ 1 ] } + } + else if( args.length === 3 ) + { + o = { dst : args[ 0 ], src : args[ 1 ], onUp : args[ 2 ] } + } + + _.assert( args.length === 1 || args.length === 2 || args.length === 3 ); + _.assert( arguments.length === 1 ); + _.assert( _.mapIs( o ) ); + + return o; +} + +// + +function optionsToIteration( iterator, o ) +{ + let it = Parent.optionsToIteration.call( this, iterator, o ); + _.assert( arguments.length === 2 ); + _.assert( _.props.has( it, 'dst' ) ); + _.assert( it.dst !== null ); + _.assert( it.iterator.onUp === null || _.routineIs( it.iterator.onUp ) ); + _.assert( it.iterator.onDown === null || _.routineIs( it.iterator.onDown ) ); + return it; +} + +// + +function iteratorInitEnd( iterator ) +{ + Parent.iteratorInitEnd.call( this, iterator ); + + if( iterator.dst === null ) + iterator.dst = undefined; + if( iterator.dst !== undefined ) + iterator.firstIterationPrototype.dstMaking = false; + if( iterator.firstIterationPrototype.dst === null ) + iterator.firstIterationPrototype.dst = undefined; + + return iterator; +} + +// + +function performEnd() +{ + let it = this; + it.iterator.originalResult = it.dst; + it.iterator.result = it.iterator.originalResult; + Parent.performEnd.apply( it, arguments ); + return it; +} + +// + +function dstWriteDown( eit ) +{ + let it = this; + it.DstWriteDown[ it.iterable ].call( it, eit ); +} + +// + +function _dstWriteDownTerminal( eit ) +{ + _.assert( 0, 'Cant write into terminal' ); +} + +// + +function _dstWriteDownCountable( eit ) +{ + if( eit.dst !== undefined ) + this.dst.push( eit.dst ); +} + +// + +function _dstWriteDownAux( eit ) +{ + if( eit.dst === undefined ) + delete this.dst[ eit.key ]; + else + this.dst[ eit.key ] = eit.dst; +} + +// + +function _dstWriteDownHashMap( eit ) +{ + if( eit.dst === undefined ) + this.dst.delete( eit.key ); + else + this.dst.set( eit.key, eit.dst ); +} + +// + +function _dstWriteDownSet( eit ) +{ + if( eit.dst === undefined ) + this.dst.delete( eit.dst ); + else + this.dst.add( eit.dst ); +} + +// + +function _dstWriteDownCustom( eit ) +{ + _.assert( 0, 'not implemented' ); +} + +// + +function dstMake() +{ + let it = this; + + _.assert( it.iterable !== null && it.iterable !== undefined ); + _.assert( it.dstMaking ); + _.assert( arguments.length === 0 ); + _.assert( it.dst !== null ); + + // if( it.dst !== undefined ) + // return; + + it.dst = it.ContainerMake[ it.iterable ].call( it ); +} + +// + +function _containerMakeTerminal() +{ + let it = this; + return it.src; +} + +// + +function _containerMakeCountable() +{ + let it = this; + return []; +} + +// + +function _containerMakeAux() +{ + let it = this; + return Object.create( null ); +} + +// + +function _containerMakeHashMap() +{ + let it = this; + return new HashMap; +} + +// + +function _containerMakeSet() +{ + let it = this; + return new Set; +} + +// + +function _containerMakeCustom() +{ + let it = this; + return it.src; +} + +// + +function visitUpBegin() +{ + let it = this; + + let r = Parent.visitUpBegin.call( it ); + + // if( it.dstMaking ) + // it.dstMake(); + + return r; +} + +// + +function visitUpEnd() +{ + let it = this; + + if( it.dstMaking ) + it.dstMake(); + + return Parent.visitDownEnd.call( it ); +} + +// + +function visitDownEnd() +{ + let it = this; + _.assert( it.iterable !== null && it.iterable !== undefined ); + if( it.down && it.dstWritingDown ) + it.down.dstWriteDown( it ); + return Parent.visitDownEnd.call( it ); +} + +// + +function exec_head( routine, args ) +{ + _.assert( !!routine.defaults.Seeker ); + return routine.defaults.head( routine, args ); +} + +// + +function exec_body( it ) +{ + it.execIt.body.call( this, it ); + return it.result; +} + +// + +/* zzz qqq : implement please replication with buffer sepration +*/ + +// function cloneDataSeparatingBuffers( o ) +// { +// var result = Object.create( null ); +// var buffers = []; +// var descriptorsArray = []; +// var descriptorsMap = Object.create( null ); +// var size = 0; +// var offset = 0; +// +// _.routine.options_( cloneDataSeparatingBuffers, o ); +// _.assert( arguments.length === 1, 'Expects single argument' ); +// +// /* onBuffer */ +// +// o.onBuffer = function onBuffer( srcBuffer, it ) +// { +// +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// _.assert( _.bufferTypedIs( srcBuffer ), 'not tested' ); +// +// var index = buffers.length; +// var id = _.strJoin([ '--buffer-->', index, '<--buffer--' ]); +// var bufferSize = srcBuffer ? srcBuffer.length*srcBuffer.BYTES_PER_ELEMENT : 0; +// size += bufferSize; +// +// let bufferConstructorName; +// if( srcBuffer ) +// { +// let longDescriptor = _.LongTypeToDescriptorsHash.get( srcBuffer.constructor ); +// +// if( longDescriptor ) +// bufferConstructorName = longDescriptor.name; +// else +// bufferConstructorName = srcBuffer.constructor.name; +// +// } +// else +// { +// bufferConstructorName = 'null'; +// } +// +// var descriptor = +// { +// 'bufferConstructorName' : bufferConstructorName, +// 'sizeOfScalar' : srcBuffer ? srcBuffer.BYTES_PER_ELEMENT : 0, +// 'offset' : -1, +// 'size' : bufferSize, +// 'index' : index, +// } +// +// buffers.push( srcBuffer ); +// descriptorsArray.push( descriptor ); +// descriptorsMap[ id ] = descriptor; +// +// it.dst = id; +// +// } +// +// /* clone data */ +// +// result.data = _._clone( o ); +// result.descriptorsMap = descriptorsMap; +// +// /* sort by atom size */ +// +// descriptorsArray.sort( function( a, b ) +// { +// return b[ 'sizeOfScalar' ] - a[ 'sizeOfScalar' ]; +// }); +// +// /* alloc */ +// +// result.buffer = new BufferRaw( size ); +// var dstBuffer = _.bufferBytesGet( result.buffer ); +// +// /* copy buffers */ +// +// for( var b = 0 ; b < descriptorsArray.length ; b++ ) +// { +// +// var descriptor = descriptorsArray[ b ]; +// var buffer = buffers[ descriptor.index ]; +// var bytes = buffer ? _.bufferBytesGet( buffer ) : new U8x(); +// var bufferSize = descriptor[ 'size' ]; +// +// descriptor[ 'offset' ] = offset; +// +// _.bufferMove( dstBuffer.subarray( offset, offset+bufferSize ), bytes ); +// +// offset += bufferSize; +// +// } +// +// return result; +// } +// +// cloneDataSeparatingBuffers.defaults = +// { +// copyingBuffers : 1, +// } +// +// cloneDataSeparatingBuffers.defaults.__proto__ = cloneData.defaults; + +// + +/** + * @summary Replicates a complex data structure using iterator. + * @param {Object} o Options map + * @param {Object} o.it Iterator object + * @param {Object} o.root + * @param {Object} o.src Source data structure + * @param {Object} o.dst Target data structure + * @param {Number} o.recursive=Infinity + * + * @returns {Object} Returns `dst` structure. + * @function replicateIt + * @namespace Tools + * @module Tools/base/Replicator + */ + +// + +/** + * @summary Replicates a complex data structure. + * @param {*} src Source data scructure + * @param {*} dst Target data scructure + * + * @returns {} Returns `dst` structure. + * @function replicate + * @namespace Tools + * @module Tools/base/Replicator + */ + +// -- +// relations +// -- + +let DstWriteDown = +[ + _dstWriteDownTerminal, + _dstWriteDownCountable, + _dstWriteDownAux, + _dstWriteDownHashMap, + _dstWriteDownSet, + _dstWriteDownCustom, +] + +let ContainerMake = +[ + _containerMakeTerminal, + _containerMakeCountable, + _containerMakeAux, + _containerMakeHashMap, + _containerMakeSet, + _containerMakeCustom, +] + +let LookerExtension = +{ + constructor : function Replicator(){}, + optionsFromArguments, + optionsToIteration, + iteratorInitEnd, + performEnd, + dstWriteDown, + _dstWriteDownTerminal, + _dstWriteDownCountable, + _dstWriteDownAux, + _dstWriteDownHashMap, + _dstWriteDownSet, + _dstWriteDownCustom, + dstMake, + _containerMakeTerminal, + _containerMakeCountable, + _containerMakeAux, + _containerMakeHashMap, + _containerMakeSet, + _containerMakeCustom, + visitUpBegin, + visitUpEnd, + visitDownEnd, + DstWriteDown, + ContainerMake, +} + +let Iterator = Object.create( null ); +Iterator.result = undefined; +Iterator.originalResult = undefined; + +let Iteration = Object.create( null ); +Iteration.dst = undefined; +Iteration.dstMaking = true; +Iteration.dstWritingDown = true; + +let Replicator = _.looker.classDefine +({ + name : 'Replicator', + parent : _.looker.Looker, + prime : Prime, + seeker : LookerExtension, + iterator : Iterator, + iteration : Iteration, + exec : { head : exec_head, body : exec_body }, +}); + +_.assert( _.props.has( Replicator.Iteration, 'src' ) && Replicator.Iteration.src === undefined ); +_.assert( _.props.has( Replicator.IterationPreserve, 'src' ) && Replicator.IterationPreserve.src === undefined ); +_.assert( _.props.has( Replicator, 'src' ) && Replicator.src === undefined ); +_.assert( _.props.has( Replicator.Iteration, 'dst' ) && Replicator.Iteration.dst === undefined ); +_.assert( _.props.has( Replicator, 'dst' ) && Replicator.dst === undefined ); +_.assert( _.props.has( Replicator.Iterator, 'result' ) && Replicator.Iterator.result === undefined ); +_.assert( _.props.has( Replicator, 'result' ) && Replicator.result === undefined ); + +// -- +// replicator extension +// -- + +let ReplicatorExtension = +{ + + name : 'replicator', + Seeker : Replicator, + Replicator, + replicateIt : Replicator.execIt, + replicate : Replicator.exec, + +} + +Object.assign( _.replicator, ReplicatorExtension ); + +// -- +// tools extension +// -- + +let ToolsExtension = +{ + + replicate : Replicator.exec, + +} + +Object.assign( _, ToolsExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wreplicator/proto/wtools/abase/l4/Replicator.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wreplicator/proto/wtools/abase/l4' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Replicator_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Replicator_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wrepobasic */ ( function wrepobasic() { function wrepobasic_naked() { +module.exports = require( '../wtools/amid/l3/repo/entry/RepoBasic.ss' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wRepoBasic', 'wrepobasic' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/node_modules/wrepobasic' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wrepobasic_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wrepobasic */ })(); + +/* */ /* begin of file RepoBasic_ss */ ( function RepoBasic_ss() { function RepoBasic_ss_naked() { ( function _RepoBasic_ss_() +{ + +'use strict'; + +/** + * Collection of tools to use git programmatically. + @module Tools/mid/GitTools +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../include/RepoMid.ss' ); + module[ 'exports' ] = _global_.wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/entry/RepoBasic.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/entry' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, RepoBasic_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file RepoBasic_ss */ })(); + +/* */ /* begin of file RepoBasic_ss */ ( function RepoBasic_ss() { function RepoBasic_ss_naked() { ( function _Base_s_() +{ + +'use strict'; + +/* GitTools */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../../node_modules/Tools' ); + + _.include( 'wFilesBasic' ); + _.include( 'wGitPath' ); + + module[ 'exports' ] = _global_.wTools; +} + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/include/RepoBasic.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, RepoBasic_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file RepoBasic_ss */ })(); + +/* */ /* begin of file RepoMid_ss */ ( function RepoMid_ss() { function RepoMid_ss_naked() { ( function _Mid_s_() +{ + +'use strict'; + +/* GitTools */ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../../../node_modules/Tools' ); + + require( './RepoBasic.ss' ); + require( '../l1/Repo.s' ); + require( '../l3_provider/Git.s' ); + require( '../l3_provider/Github.s' ); + require( '../l3_provider/HardDrive.s' ); + require( '../l3_provider/Http.s' ); + require( '../l3_provider/Npm.s' ); + + module[ 'exports' ] = _global_.wTools; +} + +})(); + + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/include/RepoMid.ss' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/include' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, RepoMid_ss_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file RepoMid_ss */ })(); + +/* */ /* begin of file Repo_s */ ( function Repo_s() { function Repo_s_naked() { ( function _Repo_s_() +{ + +'use strict'; + +const _ = _global_.wTools; +_.repo = _.repo || Object.create( null ); +_.repo.provider = _.repo.provider || Object.create( null ); + +// -- +// meta +// -- + +function _request_functor( fo ) +{ + + _.routine.options( _request_functor, fo ); + _.assert( _.strDefined( fo.description ) ); + _.assert( _.aux.is( fo.act ) ); + _.assert( _.strDefined( fo.act.name ) ); + + const description = fo.description; + const actName = fo.act.name; + + request_body.defaults = + { + logger : 0, + throwing : 1, + originalRemotePath : null, + ... fo.act.defaults, + } + + const request = _.routine.unite( request_head, request_body ); + return request; + + function request_head( routine, args ) + { + let o = args[ 0 ]; + if( _.strIs( o ) ) + o = { remotePath : o }; + _.routine.options( request, o ); + _.assert( args.length === 1 ); + return o; + } + + function request_body( o ) + { + let ready = _.take( null ); + let path = _.git.path; + + _.map.assertHasAll( o, request.defaults ); + o.logger = _.logger.maybe( o.logger ); + + o.originalRemotePath = o.originalRemotePath || o.remotePath; + if( _.strIs( o.remotePath ) ) + o.remotePath = path.parse({ remotePath : o.remotePath, full : 0, atomic : 0, objects : 1 }); + + ready + .then( () => + { + let provider = _.repo.providerForPath({ remotePath : o.remotePath, throwing : o.throwing }); + if( provider && !_.routineIs( provider[ actName ] ) ) + throw _.err( `Repo provider ${provider.name} does not support routine ${actName}` ); + return provider[ actName ]( o ); + }) + .then( ( op ) => + { + if( !_.map.is( op ) ) + throw _.err( `Routine ${actName} should return options map. Got:${op}` ); + + if( op.result === undefined ) + throw _.err( `Options map returned by routine ${actName} should have {result} field. Got:${op}` ); + + return o; + }) + .catch( ( err ) => + { + if( o.throwing ) + throw _.err( err, `\nFailed to ${description} for ${path.str( o.originalRemotePath )}` ); + _.errAttend( err ); + return null; + }) + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + } + +} + +_request_functor.defaults = +{ + description : null, + act : null, +} + +// + +function _collectionExportString_functor( fo ) +{ + + _.routine.options( _collectionExportString_functor, fo ); + _.assert( arguments.length === 1 ); + _.assert( _.routine.is( fo.elementExportRoutine ) ); + _.assert( _.routine.is( fo.elementExportRoutine.body ) ); + _.assert( _.aux.is( fo.elementExportRoutine.defaults ) ); + _.assert( _.routine.is( fo.formatHeadRoutine ) || _.strDefined( fo.elementsString ) ); + _.assert( _.routine.is( fo.formatHeadRoutine ) || fo.formatHeadRoutine === null ); + + const elementsString = fo.elementsString; + const elementExportRoutine = fo.elementExportRoutine; + const formatHeadRoutine = fo.formatHeadRoutine ? fo.formatHeadRoutine : formatHeadRoutineDefault; + + elementArrayExportString_body.defaults = + { + ... fo.elementExportRoutine.defaults, + withHead : 1, + verbosity : 2, + } + + elementArrayExportString_body.itDefaults = + { + tab : '', + dtab : ' ', + } + + const elementArrayExportString = _.routine.unite( elementArrayExportString_head, elementArrayExportString_body ); + return elementArrayExportString; + + function elementArrayExportString_head( routine, args ) + { + _.assert( 1 <= args.length && args.length <= 2 ); + let o = args[ 1 ]; + _.routine.options( routine, o ); + o.it = o.it || _.props.extend( null, routine.itDefaults ); + return _.unroll.from([ args[ 0 ], o ]); + } + + function elementArrayExportString_body( object, o ) + { + + o.verbosity = _.logger.verbosityFrom( o.verbosity ); + + if( o.verbosity <= 0 ) + return ''; + + if( o.verbosity === 1 ) + { + if( !object.elements.length ) + return ``; + return formatHeadRoutine( object, o ); + } + + let result = ''; + object.elements.forEach( ( element ) => + { + if( result.length ) + result += '\n'; + /* xxx : use _.stringer.verbosityUp() */ + result += o.it.tab + o.it.dtab + elementExportRoutine.body.call( _.repo, element, o ); + }); + + if( result.length && o.withHead ) + result = `${formatHeadRoutine( object, o )}\n${result}`; + + return result; + + } + + function formatHeadRoutineDefault( object, o ) + { + let prefix = _.ct.format( elementsString, o.secondaryStyle ); + return `${o.it.tab}${object.elements.length} ${prefix}`; + } + +} + +_collectionExportString_functor.defaults = +{ + elementExportRoutine : null, + formatHeadRoutine : null, + elementsString : null +} + +// -- +// provider +// -- + +function providerForPath( o ) +{ + if( _.strIs( o ) ) + o = { remotePath : o }; + + _.assert( arguments.length === 1 ); + _.routine.options( providerForPath, o ); + + let parsed; + o.originalRemotePath = o.originalRemotePath || o.remotePath; + + let providerKey = providerGetService( o.originalRemotePath ); + + let provider = _.repo.provider[ providerKey ]; + + if( !provider ) + { + if( providerKey ) + { + provider = _.repo.provider.git; + } + else + { + providerKey = providerGetProtocol(); + provider = _.repo.provider[ providerKey ]; + } + + if( !provider ) + throw _.err( `No repo provider for path::${ o.originalRemotePath }` ); + } + + return provider; + + /* */ + + function providerGetService( remotePath ) + { + if( _.strIs( o.remotePath ) ) + parsed = o.remotePath = _.git.path.parse({ remotePath, full : 1, atomic : 0, objects : 1 }); + else + parsed = o.remotePath; + + if( parsed.service ) + { + _.assert( _.map.assertHasAll( parsed, { user : null, repo : null } ) ); + _.assert( parsed.protocols === undefined || parsed.protocols.length <= 1 || parsed.protocols[ 0 ] === 'git' ); + return parsed.service; + } + } + + /* */ + + function providerGetProtocol() + { + if( !parsed.protocol ) + return _.fileSystem.defaultProtocol; + return parsed.protocol; + } +} + +// function providerForPath( o ) +// { +// _.routine.options( providerForPath, o ); +// o.originalRemotePath = o.originalRemotePath || o.remotePath; +// if( _.strIs( o.remotePath ) ) +// o.remotePath = _.git.path.parse({ remotePath : o.remotePath, full : 0, atomic : 0, objects : 1 }); +// let provider = _.repo.provider[ o.remotePath.service ]; +// if( !provider ) +// throw _.err( `No repo provider for service::${o.remotePath.service}` ); +// return provider; +// } + +providerForPath.defaults = +{ + originalRemotePath : null, + remotePath : null, + throwing : 0, +}; + +// + +function providerAmend( o ) +{ + _.routine.options( providerAmend, o ); + _.assert( _.mapIs( o.src ) ); + _.assert( _.strIs( o.src.name ) || _.strsAreAll( o.src.names ) ); + + if( !o.src.name ) + o.src.name = o.src.names[ 0 ]; + if( !o.src.names ) + o.src.names = [ o.src.name ]; + + _.assert( _.strIs( o.src.name ) ); + _.assert( _.strsAreAll( o.src.names ) ); + + let was; + o.src.names.forEach( ( name ) => + { + _.assert( _.repo.provider[ name ] === was || _.repo.provider[ name ] === undefined ); + was = was || _.repo.provider[ name ]; + }); + + o.src.names.forEach( ( name ) => + { + let dst = _.repo.provider[ name ]; + if( !dst ) + dst = _.repo.provider[ name ] = Object.create( null ); + let name2 = dst.name || o.src.name; + _.props.extend( dst, o.src ); + dst.name = name2; + }); + +} + +providerAmend.defaults = +{ + src : null, +} + +// + +const repositoryIssuesGetAct = Object.create( null ); + +repositoryIssuesGetAct.name = 'repositoryIssuesGetAct'; +repositoryIssuesGetAct.defaults = +{ + token : null, + remotePath : null, + state : null, +}; + +// + +function issuesGet( o ) +{ + _.routine.options( issuesGet, o ); + _.assert( _.str.is( o.remotePath ) || _.aux.is( o.remotePath ) ); + + o.state = o.state || 'all'; + o.remotePath = _.git.path.normalize( o.remotePath ); + const parsed = _.git.path.parse({ remotePath : o.remotePath, full : 0, atomic : 0, objects : 1 }); + + const provider = _.repo.providerForPath({ remotePath : o.remotePath }); + const o2 = _.props.extend( null, o ); + o2.remotePath = parsed; + + const ready = provider.repositoryIssuesGetAct( o2 ); + ready.finally( ( err, arg ) => + { + if( err ) + throw _.err( `Error code : ${ err.status }. ${ err.message }` ); + return arg || null; + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +issuesGet.defaults = +{ + ... repositoryIssuesGetAct.defaults, + sync : 0, +}; + +// + +const repositoryIssuesCreateAct = Object.create( null ); + +repositoryIssuesCreateAct.name = 'repositoryIssuesCreateAct'; +repositoryIssuesCreateAct.defaults = +{ + token : null, + remotePath : null, + issues : null, +}; + +// + +function issuesCreate( o ) +{ + let localProvider = _.fileProvider; + let path = localProvider.path; + _.routine.options( issuesCreate, o ); + _.assert( _.str.is( o.remotePath ) || _.aux.is( o.remotePath ) ); + _.assert( _.str.defined( o.token ), 'Expects token {-o.token-}' ); + + if( _.str.is( o.issues ) ) + o.issues = localProvider.fileReadUnknown( path.join( path.current(), o.issues ) ); + _.assert( _.array.is( o.issues ) || _.aux.is( o.issues ) ); + + o.remotePath = _.git.path.normalize( o.remotePath ); + const parsed = _.git.path.parse({ remotePath : o.remotePath, full : 0, atomic : 0, objects : 1 }); + + const provider = _.repo.providerForPath({ remotePath : o.remotePath }); + const o2 = _.props.extend( null, o ); + o2.remotePath = parsed; + + const ready = provider.repositoryIssuesCreateAct( o2 ); + ready.finally( ( err, arg ) => + { + if( err ) + throw _.err( `Error code : ${ err.status }. ${ err.message }` ); + return arg || null; + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +issuesCreate.defaults = +{ + ... repositoryIssuesCreateAct.defaults, + sync : 0, +}; + +// -- +// pr +// -- + +function pullIs( element ) +{ + if( !_.object.isBasic( element ) ) + return false; + return element.type === 'repo.pull'; +} + +// + +function pullExportString_body( element, o ) +{ + + _.assert( _.repo.pullIs( element ) ); + o.verbosity = _.logger.verbosityFrom( o.verbosity ); + + if( o.verbosity <= 0 ) + return ''; + + let id = `pr#${element.id}`; + let fromUser = _.ct.format( 'from_user::', o.secondaryStyle ) + element.from.name; + let fromBranch = _.ct.format( 'from_branch::', o.secondaryStyle ) + element.from.tag; + let to = _.ct.format( 'to::', o.secondaryStyle ) + element.to.tag; + let description = _.ct.format( 'description::', o.secondaryStyle ) + element.description.head; + let result = `${ id } ${ fromUser } ${ fromBranch } ${ to } ${ description }`; + + return result; +} + +pullExportString_body.defaults = +{ + secondaryStyle : 'tertiary', + verbosity : 1, + it : null, +}; + +let pullExportString = _.routine.unite( 1, pullExportString_body ); + +// + +let pullCollectionExportString = _collectionExportString_functor +({ + elementExportRoutine : pullExportString, + elementsString : 'program(s)', +}); + +// + +let pullListAct = Object.create( null ); +pullListAct.name = 'pullListAct'; +pullListAct.defaults = +{ + token : null, + remotePath : null, + sync : 1, + withOpened : 1, + withClosed : 0, +}; + +// + +let pullList = _request_functor +({ + description : 'get list of pull requests', + act : pullListAct, +}); + +// + +let pullOpenAct = Object.create( null ); + +pullOpenAct.name = 'pullOpenAct'; +pullOpenAct.defaults = +{ + token : null, + remotePath : null, + descriptionHead : null, + descriptionBody : null, + srcBranch : null, + dstBranch : null, + logger : null, +}; + +// + +function pullOpen( o ) +{ + _.assert( arguments.length === 1 ); + _.routine.options( pullOpen, o ); + _.sure( _.str.defined( o.token ), 'Expects token {-o.token-}.' ); + _.assert( _.str.defined( o.remotePath ) ); + _.assert( _.str.is( o.srcBranch ) || _.str.is( o.dstBranch ), 'Expects either {-o.srcBranch-} or {-o.dstBranch-}.' ); + + o.logger = _.logger.maybe( o.logger ); + + if( o.srcBranch === null ) + o.srcBranch = currentBranchGet(); + if( o.dstBranch === null ) + o.dstBranch = currentBranchGet(); + + const parsed = _.git.path.parse({ remotePath : o.remotePath, full : 1, atomic : 0 }); + + const provider = _.repo.providerForPath({ remotePath : o.remotePath }); + const o2 = _.props.extend( null, o ); + o2.remotePath = parsed; + + const ready = provider.pullOpenAct( o2 ); + ready.finally( ( err, pr ) => + { + if( err ) + { + _.errAttend( err ); + if( o.throwing ) + throw _.err( err, '\nFailed to open pull request' ); + } + return pr || false; + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; + + /* */ + + function currentBranchGet() + { + _.assert( _.strDefined( o.localPath ), 'Expects local path {-o.localPath-}' ); + + let tag = _.git.tagLocalRetrive + ({ + localPath : o.localPath, + detailing : 1, + }); + + if( tag.isBranch ) + return tag.tag; + else + return 'master'; + } + + // /* aaa : for Dmytro : move out to github provider */ /* Dmytro : moved to provider */ + // function pullOpenOnGithub() + // { + // let ready = _.take( null ); + // ready + // .then( () => + // { + // let github = require( 'octonode' ); + // let client = github.client( o.token ); + // let repo = client.repo( `${ parsed.user }/${ parsed.repo }` ); + // let o2 = + // { + // descriptionHead : o.descriptionHead, + // descriptionBody : o.descriptionBody, + // head : o.srcBranch, + // base : o.dstBranch, + // }; + // repo.pr( o2, onRequest ); + // + // /* */ + // + // return ready2 + // .then( ( args ) => + // { + // if( args[ 0 ] ) + // throw _.err( `Error code : ${ args[ 0 ].statusCode }. ${ args[ 0 ].message }` ); /* Dmytro : the structure of HTTP error is : message, statusCode, headers, body */ + // + // if( o.logger && o.logger.verbosity >= 3 ) + // o.logger.log( args[ 1 ] ); + // else if( o.logger && o.logger.verbosity >= 1 ) + // o.logger.log( `Succefully created pull request "${ o.descriptionHead }" in ${ o.remotePath }.` ) + // + // return args[ 1 ]; + // }); + // }); + // return ready; + // } + // + // /* aaa : for Dmytro : ?? */ /* Dmytro : really strange code */ + // function onRequest( err, body, headers ) + // { + // return _.time.begin( 0, () => ready2.take([ err, body ]) ); + // } + +} + +pullOpen.defaults = +{ + throwing : 1, + sync : 1, + logger : 2, + token : null, + remotePath : null, + localPath : null, + // title : null, /* aaa : for Dmytro : rename to descriptionHead */ + // body : null, /* aaa : for Dmytro : rename to descriptionBody */ + descriptionHead : null, + descriptionBody : null, + srcBranch : null, /* aaa : for Dmytro : should get current by default */ /* Dmytro : implemented and covered */ + dstBranch : null, /* aaa : for Dmytro : should get current by default */ /* Dmytro : implemented and covered */ +}; + +// -- +// release +// -- + +let releaseMakeAct = Object.create( null ); + +releaseMakeAct.name = 'releaseMakeAct'; +releaseMakeAct.defaults = +{ + name : null, + token : null, + remotePath : null, + descriptionBody : null, + draft : null, + prerelease : null, + logger : null, +}; + +// + +function releaseMake( o ) +{ + _.assert( arguments.length === 1 ); + _.routine.options( releaseMake, o ); + _.sure( _.str.defined( o.token ), 'Expects token {-o.token-}.' ); + _.assert( _.str.defined( o.remotePath ) ); + + const ready = _.take( null ); + const parsed = _.git.path.parse({ remotePath : o.remotePath, full : 1, atomic : 0 }); + + if( o.force ) + { + let o2 = _.mapOnly_( null, o, _.repo.releaseDelete.defaults ); + o2.throwing = 0; + ready.then( () => _.repo.releaseDelete( o2 ) ); + }; + + ready.then( () => + { + const provider = _.repo.providerForPath({ remotePath : o.remotePath }); + let o2 = _.props.extend( null, o ); + o2.remotePath = parsed; + return provider.releaseMakeAct( o2 ); + }); + ready.finally( ( err, arg ) => + { + if( err ) + { + _.errAttend( err ); + if( o.throwing ) + throw _.err( err, '\nFailed to create release.' ); + } + return arg || false; + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +releaseMake.defaults = +{ + ... releaseMakeAct.defaults, + localPath : null, + throwing : 1, + force : 0, + sync : 1, + logger : 2, +}; + +// + +let releaseDeleteAct = Object.create( null ); + +releaseDeleteAct.name = 'releaseDeleteAct'; +releaseDeleteAct.defaults = +{ + token : null, + remotePath : null, + logger : null, +}; + +// + +function releaseDelete( o ) +{ + _.assert( arguments.length === 1 ); + _.routine.options( releaseDelete, o ); + _.sure( _.str.defined( o.token ), 'Expects token {-o.token-}.' ); + _.assert( _.str.defined( o.remotePath ) ); + _.assert( _.str.defined( o.localPath ), 'Expects local path {-o.localPath-}.' ); + + const parsed = _.git.path.parse({ remotePath : o.remotePath, full : 1, atomic : 0 }); + const provider = _.repo.providerForPath({ remotePath : o.remotePath }); + const o2 = _.props.extend( null, o ); + o2.remotePath = parsed; + + const ready = provider.releaseDeleteAct( o2 ); + ready.then( ( arg ) => + { + _.git.tagDeleteTag + ({ + localPath : o.localPath, + tag : parsed.tag, + remote : o.force, + local : 1, + throwing : 0, + sync : 1, + }); + return arg; + }) + .finally( ( err, arg ) => + { + if( err ) + { + _.errAttend( err ); + if( o.throwing ) + throw _.err( err, '\nFailed to delete release.' ); + } + return arg || false; + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +releaseDelete.defaults = +{ + ... releaseDeleteAct.defaults, + localPath : null, + force : 0, + throwing : 1, + sync : 1, + logger : 2, +}; + +// -- +// repository +// -- + +const repositoryInitAct = Object.create( null ); + +repositoryInitAct.name = 'repositoryInitAct'; +repositoryInitAct.defaults = +{ + token : null, + remotePath : null, + description : null, +}; + +// + +function repositoryInit( o ) +{ + _.routine.options_( repositoryInit, o ); + _.assert( _.str.is( o.remotePath ) || _.aux.is( o.remotePath ) ); + _.sure( _.str.defined( o.token ), 'An access token is required to create a repository.' ); + + /* */ + + o.remotePath = _.git.path.normalize( o.remotePath ); + const parsed = _.git.path.parse({ remotePath : o.remotePath, full : 0, atomic : 0, objects : 1 }); + + const provider = _.repo.providerForPath({ remotePath : o.remotePath }); + const o2 = _.props.extend( null, o ); + o2.remotePath = parsed; + + const ready = provider.repositoryInitAct( o2 ); + ready.finally( ( err, arg ) => + { + if( err ) + { + _.error.attend( err ); + if( o.throwing ) + throw _.err( `Error code : ${ err.status }. ${ err.message }` ); + } + return arg || false; + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +repositoryInit.defaults = +{ + ... repositoryInitAct.defaults, + throwing : 1, + sync : 0, +}; + +// + +const repositoryDeleteAct = Object.create( null ); + +repositoryDeleteAct.name = 'repositoryDeleteAct'; +repositoryDeleteAct.defaults = +{ + token : null, + remotePath : null, +}; + +// + +function repositoryDelete( o ) +{ + _.routine.options_( repositoryDelete, o ); + _.assert( _.str.is( o.remotePath ) || _.aux.is( o.remotePath ) ); + _.sure( _.str.defined( o.token ), 'An access token is required to delete the repository.' ); + + /* */ + + o.remotePath = _.git.path.normalize( o.remotePath ); + const parsed = _.git.path.parse({ remotePath : o.remotePath, full : 0, atomic : 0, objects : 1 }); + + const provider = _.repo.providerForPath({ remotePath : o.remotePath }); + if( !provider.repositoryDeleteAct ) + throw _.err( `Can't remove remote repository, because the API is not implemented for provider ${ provider }.` ); + + const o2 = _.props.extend( null, o ); + o2.remotePath = parsed; + const ready = provider.repositoryDeleteAct( o2 ); + ready.finally( ( err, arg ) => + { + if( err ) + { + _.error.attend( err ); + if( o.throwing ) + throw _.err( `Error code : ${ err.status }. ${ err.message }` ); + } + return arg || false; + }); + + if( o.sync ) + { + ready.deasync(); + return ready.sync(); + } + + return ready; +} + +repositoryDelete.defaults = +{ + ... repositoryDeleteAct.defaults, + throwing : 1, + sync : 0, +}; + +// -- +// program +// -- + +function programIs( object ) +{ + if( !_.object.isBasic( object ) ) + return false; + return object.type === 'repo.program'; +} + +// + +function programExportString_body( element, o ) +{ + + _.assert( _.repo.programIs( element ) ); + o.verbosity = _.logger.verbosityFrom( o.verbosity ); + + if( o.verbosity <= 0 ) + return ''; + + let name = _.ct.format( `name::`, o.secondaryStyle ) + element.name; + let id = `program#${element.id}`; + let state = _.ct.format( `state::`, o.secondaryStyle ) + element.state; + let service = _.ct.format( `service::`, o.secondaryStyle ) + element.service; + let result = `${id} ${name} ${state} ${service}`; + + return result; +} + +programExportString_body.defaults = +{ + secondaryStyle : 'tertiary', + verbosity : 1, + it : null, +} + +let programExportString = _.routine.unite( 1, programExportString_body ); + +// + +let programCollectionExportString = _collectionExportString_functor +({ + elementExportRoutine : programExportString, + elementsString : 'program(s)', +}); + +// + +let programListAct = Object.create( null ); +programListAct.name = 'programListAct'; +programListAct.defaults = +{ + token : null, + remotePath : null, + sync : 1, + withOpened : 1, + withClosed : 0, +}; + +// + +let programList = _request_functor +({ + description : 'get list of programs', + act : programListAct, +}); + +// -- +// etc +// -- + +function vcsFor( o ) +{ + if( !_.map.is( o ) ) + o = { filePath : o }; + + _.assert( arguments.length === 1 ); + _.routine.options( vcsFor, o ); + + if( _.array.is( o.filePath ) && o.filePath.length === 0 ) + return null; + + if( !o.filePath ) + return null; + + _.assert( _.str.is( o.filePath ) ); + _.assert( _.git.path.isGlobal( o.filePath ) ); + + let parsed = _.git.path.parse( o.filePath ); + + if( _.git && _.git.protocols && _.longHas( _.git.protocols, parsed.protocol ) ) + return _.git; + if( _.npm && _.npm.protocols && _.longHasAny( _.npm.protocols, parsed.protocol ) ) + return _.npm; + if( _.http && _.http.protocols && _.longHasAny( _.http.protocols, parsed.protocol ) ) + return _.http; + + return null; +} + +vcsFor.defaults = +{ + filePath : null, +}; + +// -- +// declare +// -- + +let Extension = +{ + + // meta + + _request_functor, + _collectionExportString_functor, + + // provider + + providerForPath, + providerAmend, + + // issue + + repositoryIssuesGetAct, + issuesGet, + repositoryIssuesCreateAct, + issuesCreate, + + // pr + + pullIs, + pullExportString, + pullCollectionExportString, + + pullListAct, + pullList, /* aaa : for Dmytro : cover */ /* Dmytro : covered */ + + pullOpenAct, /* aaa : for Dmytro : add */ /* Dmytro : added */ + pullOpen, + + // release + + releaseMakeAct, + releaseMake, + releaseDeleteAct, + releaseDelete, + + // repository + + repositoryInitAct, + repositoryInit, + repositoryDeleteAct, + repositoryDelete, + + // program + + programIs, + programExportString, + programCollectionExportString, + + programListAct, + programList, + + // etc + + vcsFor, + +} + +/* _.props.extend */Object.assign( _.repo, Extension ); + +// + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _global_.wTools; + +})(); + + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/l1/Repo.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/l1' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Repo_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Repo_s */ })(); + +/* */ /* begin of file Git_s */ ( function Git_s() { function Git_s_naked() { ( function _Git_s_() +{ + +'use strict'; + +const _ = _global_.wTools; +const Parent = _.repo; +_.repo.provider = _.repo.provider || Object.create( null ); + +// -- +// implement +// -- + +function _open( o ) +{ + _.assert( 0, 'not implemented' ); +} + +_open.defaults = +{ +}; + +// + +function repositoryInitAct( o ) +{ + _.assert( 0, 'not implemented' ); +} + +repositoryInitAct.defaults = +{ +}; + +// + +function repositoryDeleteAct( o ) +{ + _.assert( 0, 'not implemented' ); +} + +repositoryDeleteAct.defaults = +{ +}; + +// -- +// declare +// -- + +const Self = +{ + + name : 'git', + names : [ 'git', 'git+http', 'git+https', 'git+ssh', 'git+hd', 'git+file' ], + + // + + _open, + + repositoryInitAct, + repositoryDeleteAct, + +} + +_.repo.providerAmend({ src : Self }); + +// + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _global_.wTools; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/l3_provider/Git.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/l3_provider' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Git_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Git_s */ })(); + +/* */ /* begin of file Github_s */ ( function Github_s() { function Github_s_naked() { ( function _Github_s_() +{ + +'use strict'; + +let Github, Octokit; +const _ = _global_.wTools; +const Parent = _.repo; +_.repo.provider = _.repo.provider || Object.create( null ); + +// -- +// implement +// -- + +function _open( o ) +{ + _.map.assertHasAll( o, _open.defaults ); + _.assert( _.object.isBasic( o.remotePath ) ); + let ready = _.take( null ); + ready + .then( () => + { + if( !Octokit ) + Octokit = require( '@octokit/rest' ).Octokit; + const octokit = new Octokit + ({ + auth : o.token, + }); + return octokit; + }) + return ready; +} + +_open.defaults = +{ + token : null, +} + +// + +function _responseNormalize() +{ + _.assert( 0, 'not implemented' ); +} +_responseNormalize.defaults = +{ + requestCommand : null, + options : null, + fallingBack : 1, + response : null, + result : null, +} + +// + +function repositoryInitAct( o ) +{ + const self = this; + _.map.assertHasAll( o, repositoryInitAct.defaults ); + _.assert( _.aux.is( o.remotePath ) ); + + return this._open( o ) + .then( ( octokit ) => + { + return octokit.rest.repos.createForAuthenticatedUser + ({ + name : o.remotePath.repo, + description : o.description || '', + }); + }) + .finally( ( err, arg ) => + { + if( err ) + throw _.err( `Error code : ${ err.statusCode }. ${ err.message }` ); + return arg; + }); +} + +repositoryInitAct.defaults = +{ + ... Parent.repositoryInitAct.defaults, +}; + +// + +function repositoryDeleteAct( o ) +{ + const self = this; + _.map.assertHasAll( o, repositoryDeleteAct.defaults ); + _.assert( _.aux.is( o.remotePath ) ); + + return this._open( o ) + .then( ( octokit ) => + { + return octokit.rest.repos.delete + ({ + owner : o.remotePath.user, + repo : o.remotePath.repo, + }); + }); +} + +repositoryDeleteAct.defaults = +{ + ... Parent.repositoryDeleteAct.defaults, +}; + +// + +function repositoryIssuesGetAct( o ) +{ + const self = this; + _.map.assertHasAll( o, repositoryIssuesGetAct.defaults ); + _.assert( _.aux.is( o.remotePath ) ); + _.assert( _.long.leftIndex( [ 'open', 'closed', 'all' ], o.state ) !== -1 ); + + let result = []; + + return this._open( o ) + .then( ( octokit ) => issuesGet( octokit, 1 ) ) + .then( () => result ); + + /* */ + + function issuesGet( octokit, page ) + { + const con = _.take( null ); + con.then( () => + { + return octokit.rest.issues.listForRepo + ({ + owner : o.remotePath.user, + repo : o.remotePath.repo, + state : o.state, + per_page : 50, + page, + }); + return null; + }); + con.then( ( op ) => + { + if( op.data.length ) + { + _.arrayAppendArray( result, op.data ); + return issuesGet( octokit, page + 1 ); + } + else + { + result = result.filter( ( e ) => !e.pull_request ); + } + return null; + }); + return con; + } +} + +repositoryIssuesGetAct.defaults = +{ + ... Parent.repositoryIssuesGetAct.defaults, +}; + +// + +function repositoryIssuesCreateAct( o ) +{ + const self = this; + _.assert( _.aux.is( o.remotePath ) ); + _.assert( _.str.defined( o.token ) ); + _.assert( o.issues !== null ); + + o.issues = _.array.as( o.issues ); + + return this._open( o ) + .then( ( octokit ) => + { + let ready = _.take( null ); + for( let i = 0 ; i < o.issues.length ; i++ ) + ready.then( () => issueCreate( octokit, o.issues[ i ].title, o.issues[ i ].body || null ) ); + return ready; + }); + + /* */ + + function issueCreate( octokit, title, body ) + { + return octokit.rest.issues.create + ({ + owner : o.remotePath.user, + repo : o.remotePath.repo, + title, + body, + }); + } +} + +repositoryIssuesCreateAct.defaults = +{ + ... Parent.repositoryIssuesCreateAct.defaults, +}; + + +// + +function pullListAct( o ) +{ + let self = this; + let ready = _.take( null ); + _.map.assertHasAll( o, pullListAct.defaults ); + _.assert( _.object.isBasic( o.remotePath ) ); + + return self._open( o ) + .then( ( octokit ) => + { + return octokit.rest.pulls.list + ({ + owner : o.remotePath.user, + repo : o.remotePath.repo, + }) + }) + .then( ( response ) => + { + o.result = self._pullListResponseNormalize + ({ + requestCommand : 'octokit.rest.pulls.list', + options : o, + response, + }) + return o; + }); +} + +pullListAct.defaults = +{ + ... Parent.pullListAct.defaults, +}; + +// + +function _pullListResponseNormalize( o ) +{ + let result = o.result = o.result || Object.create( null ); + let response = o.response; + result.total = response.data.total_count; + result.original = response; + result.type = 'repo.pull.collection'; + result.elements = response.data.map( ( original ) => + { + let r = Object.create( null ); + r.original = original; + r.type = 'repo.pull'; + r.description = Object.create( null ); + r.description.head = original.title; + r.description.body = original.body; + r.to = Object.create( null ); + r.to.tag = original.base.ref; + r.to.hash = original.base.sha; + r.from = Object.create( null ); + r.from.name = original.head.user.login; + r.from.tag = original.head.ref; + r.id = original.number; + return r; + }); + return result; +} + +_pullListResponseNormalize.defaults = +{ + ... _responseNormalize.defaults, + requestCommand : 'octokit.rest.pulls.list', +} + +// + +function pullOpenAct( o ) +{ + const self = this; + _.map.assertHasAll( o, pullOpenAct.defaults ); + _.assert( _.aux.is( o.remotePath ) ); + + return this._open( o ) + .then( ( octokit ) => + { + return octokit.rest.pulls.create + ({ + owner : o.remotePath.user, + repo : o.remotePath.repo, + title : o.descriptionHead || '', + body : o.descriptionBody || '', + head : o.srcBranch, + base : o.dstBranch, + }); + }) + .finally( ( err, arg ) => + { + if( err ) + { + _.errAttend( err ); + throw _.err( `Error code : ${ err.status }. ${ err.message }` ); + } + + if( o.logger && o.logger.verbosity >= 3 ) + o.logger.log( arg ); + else if( o.logger && o.logger.verbosity >= 1 ) + o.logger.log( `Succefully created pull request "${ o.descriptionHead }" in ${ _.git.path.str( o.remotePath ) }.` ); + + return arg; + }); +} + +pullOpenAct.defaults = +{ + ... Parent.pullOpenAct.defaults, +}; + +/* aaa for Dmytro : should use parent defaults */ /* Dmytro : parent defaults is used */ + +// + +function releaseMakeAct( o ) +{ + _.map.assertHasAll( o, releaseMakeAct.defaults ); + _.assert( _.aux.is( o.remotePath ) ); + _.assert( _.str.defined( o.remotePath.tag ), 'Expects tag to publish.' ); + + return this._open( o ) + .then( ( octokit ) => + { + return octokit.rest.repos.createRelease + ({ + owner : o.remotePath.user, + repo : o.remotePath.repo, + tag_name : o.remotePath.tag, + name : o.name || '', + body : o.descriptionBody || '', + draft : o.draft || false, + prerelease : o.prerelease || false, + }); + }) + .finally( ( err, arg ) => + { + if( err ) + { + _.errAttend( err ); + throw _.err( `Error code : ${ err.status }. ${ err.message }` ); + } + + if( o.logger && o.logger.verbosity >= 3 ) + o.logger.log( arg ); + else if( o.logger && o.logger.verbosity >= 1 ) + o.logger.log( `Succefully created release "${ o.remotePath.tag }" in ${ _.git.path.str( o.remotePath ) }.` ); + + return arg; + }); +} + +releaseMakeAct.defaults = +{ + ... Parent.releaseMakeAct.defaults, +}; + +// + +function releaseDeleteAct( o ) +{ + _.map.assertHasAll( o, releaseDeleteAct.defaults ); + _.assert( _.aux.is( o.remotePath ) ); + _.assert( _.str.defined( o.remotePath.tag ), 'Expects tag to publish.' ); + + let octokit = null; + + return this._open( o ) + .then( ( instance ) => + { + octokit = instance; + return octokit.rest.repos.getReleaseByTag + ({ + owner : o.remotePath.user, + repo : o.remotePath.repo, + tag : o.remotePath.tag, + }); + }) + .then( ( response ) => + { + return octokit.rest.repos.deleteRelease + ({ + owner : o.remotePath.user, + repo : o.remotePath.repo, + release_id : response.data.id, + }); + }) + .finally( ( err, arg ) => + { + if( err ) + { + _.errAttend( err ); + throw _.err( `Error code : ${ err.status }. ${ err.message }` ); + } + + if( o.logger && o.logger.verbosity >= 3 ) + o.logger.log( arg ); + else if( o.logger && o.logger.verbosity >= 1 ) + o.logger.log( `Succefully deleted release "${ o.remotePath.tag }" in ${ _.git.path.str( o.remotePath ) }.` ); + + return arg; + }); +} + +releaseDeleteAct.defaults = +{ + ... Parent.releaseDeleteAct.defaults, +}; + +// + +function programListAct( o ) +{ + let self = this; + let ready = _.take( null ); + _.map.assertHasAll( o, programListAct.defaults ); + _.assert( _.object.isBasic( o.remotePath ) ); + return this._open( o ) + .then( ( octokit ) => + { + return octokit.rest.actions.listRepoWorkflows + ({ + owner : o.remotePath.user, + repo : o.remotePath.repo, + per_page : 100, + }); + }) + .then( ( response ) => + { + o.result = self._programListResponseNormalize + ({ + requestCommand : 'octokit.rest.actions.listRepoWorkflows', + options : o, + response, + }); + return o; + }); +} + +programListAct.defaults = +{ + ... Parent.pullListAct.defaults, +} + +// + +function _programListResponseNormalize( o ) +{ + let result = o.result = o.result || Object.create( null ); + let response = o.response; + result.total = response.data.total_count; + result.original = response; + result.type = 'repo.program.collection'; + result.elements = response.data.workflows.map( ( original ) => + { + let r = Object.create( null ); + r.original = original; + r.type = 'repo.program'; + r.name = original.name; + r.id = original.id; + r.state = original.state; + r.fileRelativePath = original.path; + r.fileGlobalPath = original.html_url; + r.service = 'github'; + return r; + }); + return result; +} + +_programListResponseNormalize.defaults = +{ + ... _responseNormalize.defaults, + requestCommand : 'octokit.rest.actions.listRepoWorkflows', +} + +// -- +// declare +// -- + +const _responseNormalizersMap = +{ + + 'octokit.rest.pulls.list' : pullListAct, + 'octokit.rest.actions.listRepoWorkflows' : _programListResponseNormalize, + +} + +// + +const Self = +{ + + name : 'github', + names : [ 'github', 'github.com' ], + _responseNormalizersMap, + + // + + _open, + _responseNormalize, + + repositoryInitAct, + repositoryDeleteAct, + + repositoryIssuesGetAct, + repositoryIssuesCreateAct, + + pullListAct, + _pullListResponseNormalize, + + pullOpenAct, + + releaseMakeAct, + releaseDeleteAct, + + programListAct, + _programListResponseNormalize, + +} + +_.repo.providerAmend({ src : Self }); + +// + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _global_.wTools; + +})(); + + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/l3_provider/Github.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/l3_provider' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Github_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Github_s */ })(); + +/* */ /* begin of file HardDrive_s */ ( function HardDrive_s() { function HardDrive_s_naked() { ( function _HardDrive_s_() +{ + +'use strict'; + +const _ = _global_.wTools; +const Parent = _.repo; +_.repo.provider = _.repo.provider || Object.create( null ); + +// -- +// implement +// -- + +function _open( o ) +{ + _.assert( 0, 'not implemented' ); +} + +_open.defaults = +{ +}; + +// + +function repositoryInitAct( o ) +{ + _.assert( 0, 'not implemented' ); +} + +repositoryInitAct.defaults = +{ +}; + +// + +function repositoryDeleteAct( o ) +{ + _.assert( 0, 'not implemented' ); +} + +repositoryDeleteAct.defaults = +{ +}; + +// -- +// declare +// -- + +const Self = +{ + + name : 'hd', + names : [ 'hd', 'file' ], + + // + + _open, + + repositoryInitAct, + repositoryDeleteAct, + +} + +_.repo.providerAmend({ src : Self }); + +// + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _global_.wTools; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/l3_provider/HardDrive.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/l3_provider' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, HardDrive_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file HardDrive_s */ })(); + +/* */ /* begin of file Http_s */ ( function Http_s() { function Http_s_naked() { ( function _Http_s_() +{ + +'use strict'; + +const _ = _global_.wTools; +const Parent = _.repo; +_.repo.provider = _.repo.provider || Object.create( null ); + +// -- +// implement +// -- + +function _open( o ) +{ + _.assert( 0, 'not implemented' ); +} + +_open.defaults = +{ +}; + +// + +function repositoryInitAct( o ) +{ + _.assert( 0, 'not implemented' ); +} + +repositoryInitAct.defaults = +{ +}; + +// + +function repositoryDeleteAct( o ) +{ + _.assert( 0, 'not implemented' ); +} + +repositoryDeleteAct.defaults = +{ +}; + +// -- +// declare +// -- + +const Self = +{ + + name : 'http', + names : [ 'http', 'https' ], + + // + + _open, + + repositoryInitAct, + repositoryDeleteAct, + +} + +_.repo.providerAmend({ src : Self }); + +// + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _global_.wTools; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/l3_provider/Http.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/l3_provider' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Http_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Http_s */ })(); + +/* */ /* begin of file Npm_s */ ( function Npm_s() { function Npm_s_naked() { ( function _Npm_s_() +{ + +'use strict'; + +const _ = _global_.wTools; +const Parent = _.repo; +_.repo.provider = _.repo.provider || Object.create( null ); + +// -- +// implement +// -- + +function _open( o ) +{ + _.assert( 0, 'not implemented' ); +} + +_open.defaults = +{ +}; + +// + +function repositoryInitAct( o ) +{ + _.assert( 0, 'not implemented' ); +} + +repositoryInitAct.defaults = +{ +}; + +// + +function repositoryDeleteAct( o ) +{ + _.assert( 0, 'not implemented' ); +} + +repositoryDeleteAct.defaults = +{ +}; + +// -- +// declare +// -- + +const Self = +{ + + name : 'npm', + names : [ 'npm' ], + + // + + _open, + + repositoryInitAct, + repositoryDeleteAct, + +} + +_.repo.providerAmend({ src : Self }); + +// + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _global_.wTools; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/l3_provider/Npm.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wrepobasic/proto/wtools/amid/l3/repo/l3_provider' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Npm_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Npm_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wselector/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wselector/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wselector */ ( function wselector() { function wselector_naked() { +module.exports = require( '../wtools/abase/l5/Selector.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wSelector', 'wselector' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wselector/proto/node_modules/wselector' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wselector/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wselector_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wselector */ })(); + +/* */ /* begin of file Selector_s */ ( function Selector_s() { function Selector_s_naked() { ( function _Selector_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to select a sub-structure from a complex data structure. Use the module to transform a data structure with the help of a short selector string. + @module Tools/base/Selector +*/ + +/** + * Collection of cross-platform routines to select a sub-structure from a complex data structure. + @namespace Tools.selector + @extends Tools + @module Tools/base/Selector +*/ + +/* Problems : + +zzz qqq : optimize +qqq : cover select with glob using test routine filesFindGlob of test suite FilesFind.Extract.test.s. ask how + +qqq : write nice example for readme + +qqq xxx : does not work +__.select( module.files, '* / sourcePath' ) +and +__.select( module.files.values(), '* / sourcePath' ) +where module.files is hash map + +xxx : qqq : implement _.selector.isQuery() +xxx : qqq : move _.selector.isQuery() to module::Tools? + +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../node_modules/Tools' ); + _.include( 'wLooker' ); + _.include( 'wReplicator' ); + _.include( 'wPathTools' ); +} + +const _global = _global_; +const _ = _global_.wTools; +const Parent = _.looker.Looker; +_.selector = _.selector || Object.create( _.looker ); +_.selector.functor = _.selector.functor || Object.create( null ); + + +_.assert( !!_realGlobal_ ); +_.assert( !!Parent ); + +// -- +// relations +// -- + +let Prime = Object.create( null ); + +// Prime.src = null; +Prime.selector = null; +Prime.missingAction = 'undefine'; +Prime.preservingIteration = 0; +Prime.globing = 1; +Prime.revisiting = 2; +Prime.upToken = '/'; +Prime.downToken = '..'; +Prime.hereToken = '.'; +Prime.visited = null; +Prime.set = null; +// Prime.setting = null; +Prime.action = null; +Prime.creating = null; +Prime.onUpBegin = null; +Prime.onUpEnd = null; +Prime.onDownBegin = null; +Prime.onDownEnd = null; +Prime.onQuantitativeFail = null; +Prime.onSelectorUndecorate = null; + +let Action = Object.create( null ); +Action.no = 0; +Action.set = 1; +Action.del = 2; +Action.last = 2; + +// -- +// extend looker +// -- + +function head( routine, args ) +{ + _.assert( arguments.length === 2 ); + let o = routine.defaults.Seeker.optionsFromArguments( args ); + o.Seeker = o.Seeker || routine.defaults; + _.assert( _.routineIs( routine ) || _.auxIs( routine ) ); + if( _.routineIs( routine ) ) /* zzz : remove "if" later */ + _.map.assertHasOnly( o, routine.defaults ); + else if( routine !== null ) + _.map.assertHasOnly( o, routine ); + let it = o.Seeker.optionsToIteration( null, o ); + return it; +} + +// + +function optionsFromArguments( args ) +{ + let o = args[ 0 ]; + + if( args.length === 2 ) + { + o = { src : args[ 0 ], selector : args[ 1 ] } + } + + _.assert( args.length === 1 || args.length === 2 ); + _.assert( arguments.length === 1 ); + _.assert( _.mapIs( o ) ); + + return o; +} + +// + +function optionsToIteration( iterator, o ) +{ + let it = Parent.optionsToIteration.call( this, iterator, o ); + _.assert( arguments.length === 2 ); + _.assert( it.absoluteLevel === null ); + it.absoluteLevel = 0; + _.assert( Object.hasOwnProperty.call( it.iterator, 'selector' ) ); + // _.assert( Object.hasOwnProperty.call( Object.getPrototypeOf( it ), 'selector' ) ); + return it; +} + +// + +function iteratorInitEnd( iterator ) +{ + let looker = this; + + _.assert( iterator.iteratorProper( iterator ) ); + _.assert( arguments.length === 1 ); + _.assert( _.strIs( iterator.selector ) ); + _.assert( _.strIs( iterator.downToken ) ); + _.assert( _.strIs( iterator.hereToken ) ); + /* xxx : optimize */ + _.assert + ( + _.longHas( [ 'undefine', 'ignore', 'throw', 'error' ], iterator.missingAction ) + , () => `Unknown missing action ${iterator.missingAction}` + ); + _.assert( iterator.it === undefined ); + + // if( iterator.setting === null && iterator.set !== null ) + // iterator.setting = 1; + if( iterator.action === null ) + iterator.action = iterator.set === null ? iterator.Action.no : iterator.Action.set; + if( iterator.creating === null ) + iterator.creating = iterator.action === iterator.Action.set; + // iterator.creating = !!iterator.setting; + + _.assert( _.numberIs( iterator.action ) && iterator.action <= iterator.Action.last ); + + return Parent.iteratorInitEnd.call( this, iterator ); +} + +// + +function reperformIt() +{ + let it = this; + + _.assert( arguments.length === 1 ); + _.assert( it.selector !== null, () => `Iteration is not looked` ); + _.assert + ( + it.iterationProper( it ), + () => `Expects iteration of ${Self.constructor.name} but got ${_.entity.exportStringDiagnosticShallow( it )}` + ); + + let it2 = it.iterationMake(); + let args = _.longSlice( arguments ); + if( args.length === 1 && !_.object.isBasic( args[ 0 ] ) ) + args = [ it.src, args[ 0 ] ]; + let o = Self.optionsFromArguments( args ); + o.Seeker = o.Seeker || it.Seeker || Self; + + _.assert( _.mapIs( o ) ); + _.map.assertHasOnly( o, { src : null, selector : null, Seeker : null }, 'Implemented only for options::selector' ); + _.assert( _.strIs( o.selector ) ); + _.assert( _.strIs( it2.iterator.selector ) ); + + it2.iterator.selector = it2.iterator.selector + _.strsShortest( it2.iterator.upToken ) + o.selector; + it2.iteratorSelectorChanged(); + it2.chooseRoot(); + it2.iterate(); + /* qqq : call perform here? */ + + return it2.lastIt; +} + +// + +function reperform( o ) +{ + let it = this; + + _.assert( arguments.length === 1 ); + + let it2 = it.reperformIt( o ); + + return it2.dst; +} + +// + +function performBegin() +{ + let it = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( Object.hasOwnProperty.call( it.iterator, 'selector' ) ); + // _.assert( Object.hasOwnProperty.call( Object.getPrototypeOf( it ), 'selector' ) ); + _.assert( _.intIs( it.iterator.selector ) || _.strIs( it.iterator.selector ) ); + _.assert( !!it.upToken ); + _.assert( it.iterationProper( it ) ); + + it.iteratorSelectorChanged(); + + Parent.performBegin.apply( it, arguments ); + + _.assert( it.state === 0 ); + it.iterator.state = 1; + +} + +// + +function performEnd() +{ + let it = this; + + _.assert( it.state === 1 ); + it.iterator.state = 2; + + it.iterator.originalResult = it.dst; + + if( it.missingAction === 'error' && it.error ) + { + it.result = it.error; + return it; + } + + it.iterator.result = it.originalResult; + + _.assert( it.error === null || it.error === true ); + + Parent.performEnd.apply( it, arguments ); + return it; +} + +// + +function iterationMake() +{ + let it = this; + let newIt = Parent.iterationMake.call( it ); + newIt.dst = undefined; + return newIt; +} + +// + +function iterableEval() +{ + let it = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( _.strIs( it.selectorType ) ); + + if( it.selectorType === 'down' ) + { + it.iterable = it.ContainerType.down; + } + else if( it.selectorType === 'here' ) + { + it.iterable = it.ContainerType.here; + } + else if( it.selectorType === 'terminal' ) + { + it.iterable = 0; + } + else if( it.selectorType === 'glob' ) + { + + /* xxx : custom? */ + if( _.longLike( it.src ) ) + { + it.iterable = it.ContainerType.countable; + } + else if( _.object.isBasic( it.src ) ) + { + it.iterable = it.ContainerType.aux; + } + else if( _.hashMapLike( it.src ) ) + { + it.iterable = it.ContainerType.hashMap; + } + else if( _.setLike( it.src ) ) + { + it.iterable = it.ContainerType.set; + } + else + { + it.iterable = 0; + } + + } + else + { + it.iterable = it.ContainerType.single; + } + + _.assert( it.iterable >= 0 ); +} + +// + +function selectorIsCardinal( src ) +{ + let it = this; + if( !_.strIs( src ) ) + return false; + if( !_.strBegins( src, it.cardinalDelimeter ) ) + return false; + return true; +} + +// + +function selectorCardinalParse( src ) +{ + let it = this; + if( !it.selectorIsCardinal( src ) ) + return false; + let result = Object.create( null ); + result.str = _.strRemoveBegin( src, it.cardinalDelimeter ); + result.number = _.numberFromStrMaybe( result.str ); + if( !_.numberIs( result.number ) ) + return false; + return result; +} + +// + +function elementGet( e, k, c ) +{ + let it = this; + let result; + + _.assert( arguments.length === 3 ); + + _.debugger; + let q = it.selectorCardinalParse( k ); + if( q ) + { + result = _.entity.elementWithCardinal( e, q.number ); /* xxx : use maybe functor */ + return [ result[ 0 ], result[ 1 ], q.number, result[ 2 ] ]; + } + else + { + result = _.entity.elementWithImplicit( e, k ); /* xxx : use maybe functor */ + if( c === null ) + c = _.container.cardinalWithKey( e, k ); + return [ result[ 0 ], result[ 1 ], c, result[ 2 ] ]; + } + +} + +// + +function chooseBegin() +{ + let it = this; + let e = arguments[ 0 ]; + let k = arguments[ 1 ]; + let c = arguments[ 2 ]; + let exists = arguments[ 3 ]; + + [ e, k, c, exists ] = Parent.chooseBegin.call( it, ... arguments ); + + // _.assert( arguments.length === 4, 'Expects three argument' ); + // _.assert( !!it.down ); + + if( !it.fast ) + { + it.absoluteLevel = it.down.absoluteLevel+1; + } + + return [ e, k, c, exists ]; +} + +// + +function chooseEnd() +{ + let it = this; + let e = arguments[ 0 ]; + let k = arguments[ 1 ]; + let c = arguments[ 2 ]; + let exists = arguments[ 3 ]; + + // _.assert( arguments.length === 4 ); + // _.assert( _.boolIs( exists ) || exists === null ); + + it.exists = exists; + it.selector = it.selectorArray[ it.level+1 ]; + it.iterationSelectorChanged(); + + /* xxx : move out */ + if( it.creating ) + if( exists === false && k !== undefined && it.selectorType !== 'terminal' ) + if( it.down ) + { + e = it.containerMake(); + it.down.srcWriteDown( e, k, c ); + it.exists = true; + } + + let result = Parent.chooseEnd.call( it, e, k, c, exists ); + + _.assert( _.boolIs( it.exists ) ); + + if( it.exists === false ) + if( it.action === it.Action.no || ( it.action === it.Action.set && it.selectorType !== 'terminal' ) ) + { + it.errDoesNotExistHandle(); + } + + it.srcChanged(); + it.revisitedEval( it.originalSrc ); + + return [ e, k, c, exists ]; +} + +// + +function chooseRoot() +{ + let it = this; + + _.assert( arguments.length === 0 ); + + it.exists = true; + it.selector = it.selectorArray[ it.level ]; + it.iterationSelectorChanged(); + + return Parent.chooseRoot.call( it ); +} + +// + +function containerMake() +{ + let it = this; + return Object.create( null ); +} + +// + +function iteratorSelectorChanged() +{ + let it = this; + + if( _.intIs( it.iterator.selector ) ) + it.iterator.selectorArray = [ it.iterator.selector ]; + else + it.iterator.selectorArray = split( it.iterator.selector ); + + /* */ + + function split( selector ) + { + let splits = _.strSplit + ({ + src : selector, + delimeter : it.upToken, + preservingDelimeters : 0, + preservingEmpty : 1, + preservingQuoting : 0, + stripping : 1, + }); + + if( _.strBegins( selector, it.upToken ) ) + splits.splice( 0, 1 ); + if( _.strEnds( selector, it.upToken ) ) + splits.pop(); + + return splits; + } + +} + +// + +function iterationSelectorChanged() +{ + let it = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + if( it.originalSelector === null ) + it.originalSelector = it.selector; + + if( it.selector !== undefined ) + if( it.onSelectorUndecorate ) + { + it.onSelectorUndecorate(); + } + + /* xxx : move out and use it in ResolverAdv */ + + if( it.selector === it.downToken ) + it.selectorType = 'down'; + else if( it.selector === it.hereToken ) + it.selectorType = 'here'; + else if( it.selector === undefined || it.selector === '/' ) + it.selectorType = 'terminal'; + + if( it.globing && it.selector && it.selectorType === null ) + { + + let selectorIsGlob; + if( _.path && _.path.selectorIsGlob ) + selectorIsGlob = function( selector ) + { + return _.path.selectorIsGlob( selector ) + } + else + selectorIsGlob = function selectorIsGlob( selector ) + { + return _.strHas( selector, '*' ); + } + + if( selectorIsGlob( it.selector ) ) + it.selectorType = 'glob'; + + } + + if( it.selectorType === null ) + it.selectorType = 'single'; + +} + +// + +function globParse() +{ + let it = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + _.assert( !!it.globing ); + + let regexp = /(.*){?\*=(\d*)}?(.*)/; + let match = it.selector.match( regexp ); + it.parsedSelector = it.parsedSelector || Object.create( null ); + + if( match ) + { + _.sure( _.strCount( it.selector, '=' ) <= 1, () => 'Does not support selector with several assertions, like ' + _.strQuote( it.selector ) ); + it.parsedSelector.glob = match[ 1 ] + '*' + match[ 3 ]; + if( match[ 2 ].length > 0 ) + { + it.parsedSelector.limit = _.numberFromStr( match[ 2 ] ); + _.sure( !isNaN( it.parsedSelector.limit ) && it.parsedSelector.limit >= 0, () => 'Epects non-negative number after "=" in ' + _.strQuote( it.selector ) ); + } + + } + else + { + it.parsedSelector.glob = it.selector; + } + +} + +// + +function errNoDown() +{ + let it = this; + let err = this.errMake + ( + 'Cant go down', _.strQuote( it.selector ), + '\nbecause', _.strQuote( it.selector ), 'does not exist', + '\nat', _.strQuote( it.path ), + '\nin container\n', _.entity.exportStringDiagnosticShallow( it.src ) + ); + return err; +} + +// + +function errNoDownHandle() +{ + let it = this; + it.errHandle( () => it.errNoDown() ); +} + +// + +function errCantSet() +{ + let it = this; + let err = _.err + ( + `Cant set ${it.key}` + ); + return err; +} + +// + +function errCantSetHandle() +{ + let it = this; + it.errHandle( () => it.errCantSet() ); +} + +// + +function errDoesNotExist() +{ + let it = this; + if( it.down ) + { + return this.errMake + ( + `Cant select ${it.iterator.selector} from ${_.entity.exportStringDiagnosticShallow( it.down.originalSrc )}`, + `\n because ${_.entity.exportStringDiagnosticShallow( it.down.originalSelector )} does not exist`, + `\n fall at ${_.strQuote( it.path )}`, + ); + } + else + { + return this.errMake + ( + `Cant select ${it.iterator.selector} from ${_.entity.exportStringDiagnosticShallow( it.originalSrc )}`, + `\n because ${_.entity.exportStringDiagnosticShallow( it.originalSelector )} does not exist`, + `\n fall at ${_.strQuote( it.path )}`, + ); + } +} + +// + +function errDoesNotExistHandle() +{ + let it = this; + it.errHandle( () => it.errDoesNotExist() ); +} + +// + +function errHandle( err ) +{ + let it = this; + it.continue = false; + + _.assert( arguments.length === 1 ); + _.assert( _.routineIs( err ) || _.errIs( err ) ); + + // debugger; + + if( it.missingAction === 'undefine' || it.missingAction === 'ignore' ) + { + it.iterator.error = true; + if( it.missingAction === 'undefine' ) + it.dst = undefined; + } + else + { + it.dst = undefined; + if( !it.iterator.error || it.iterator.error === true ) + it.iterator.error = errMake(); + if( it.missingAction === 'throw' ) + { + debugger; /* eslint-disable-line no-debugger */ + // console.log( `errHandle.1 attended:${it.iterator.error.attended}` ); + throw it.iterator.error; + } + } + + function errMake() + { + if( _.routineIs( err ) ) + return err(); + return err; + } + +} + +// + +function visitUp() +{ + let it = this; + + it.visitUpBegin(); + + if( it.onUpBegin ) + it.onUpBegin.call( it ); + + if( it.dstWritingDown ) + { + + if( it.selectorType === 'terminal' ) + it.terminalUp(); + else if( it.selectorType === 'down' ) + it.downUp(); + else if( it.selectorType === 'glob' ) + it.globUp(); + else + it.singleUp(); + + } + + if( it.onUpEnd ) + it.onUpEnd.call( it ); + + /* */ + + _.assert( it.visiting ); + _.assert( _.routineIs( it.onUp ) ); + let r = it.onUp.call( it, it.src, it.key, it ); + _.assert( r === undefined ); + + it.visitUpEnd() + +} + +// + +function visitUpBegin() +{ + let it = this; + + it.ascending = true; + + _.assert( it.visiting ); + + it.dstWriteDownAct = function dstWriteDownAct( eit ) + { + it.dst = eit.dst; + } + + return Parent.visitUpBegin.apply( it, ... arguments ); +} + +// + +function visitDown() +{ + let it = this; + + it.visitDownBegin(); + + if( it.onDownBegin ) + it.onDownBegin.call( it ); + + if( it.selectorType === 'terminal' ) + it.terminalDown(); + else if( it.selectorType === 'down' ) + it.downDown(); + else if( it.selectorType === 'glob' ) + it.globDown(); + else + it.singleDown(); + + it.downSet(); + + if( it.onDownEnd ) + it.onDownEnd.call( it ); + + /* */ + + _.assert( it.visiting ); + if( it.onDown ) + { + let r = it.onDown.call( it, it.src, it.key, it ); + _.assert( r === undefined ); + } + + it.visitDownEnd(); + + /* */ + + if( it.down ) + { + // _.assert( _.routineIs( it.down.dstWriteDown ) ); + if( it.dstWritingDown ) + it.down.dstWriteDown( it ); + } + +} + +// // +// +// function performSet() +// { +// let it = this; +// let it2 = it; +// +// if( !!it2.action && it2.selectorType === 'terminal' ) +// { +// /* qqq2 : implement and cover for all type of containers */ +// if +// ( +// it2.down +// && !_.primitiveIs( it2.down.src ) +// && it2.key !== undefined +// ) +// { +// if( it2.action === it2.Action.del ) +// delete it2.down.src[ it2.key ]; +// else +// it2.down.src[ it2.key ] = it2.set; +// /* zzz : introduce method writeDown */ +// } +// else +// { +// it2.errCantSetHandle(); +// } +// } +// +// } + +// + +function downSet() +{ + let it = this; + + if( !!it.action && it.selectorType === 'terminal' ) + { + // _.debugger; + /* qqq2 : implement and cover for all type of containers */ + if + ( + it.down + && !_.primitiveIs( it.down.src ) + && it.key !== undefined + ) + { + // debugger; + if( it.action === it.Action.del ) + // delete it.down.src[ it.key ]; + it.down.srcDel( it.set, it.key, it.cardinal ); + else + it.down.srcWriteDown( it.set, it.key, it.cardinal ); + // it.down.src[ it.key ] = it.set; + } + else + { + it.errCantSetHandle(); + } + } + +} + +// + +/* xxx : merge src/dst writeDown? */ + +function srcDel( e, k, c ) +{ + let it = this; + let r; + + // r = _.entity.elementDel( it.src, k, e ); /* Dmytro : element*Del accept only 2 arguments : src and key */ + + /* Dmytro : implementation that use flag `cardinal` */ + // if( c ) + // r = _.entity.elementWithCardinalDel( it.src, k ); + // else + // r = _.entity.elementDel( it.src, k ); + r = _.entity.elementDel( it.src, k ); + + if( r === false ) + { + it.errCantSetHandle(); + } + +} + +// + +/* xxx : merge src/dst writeDown? */ + +function srcWriteDown( e, k, c ) +{ + let it = this; + let r; + + let selectorIsCardinal = _.numberIs( k ) && it.selectorIsCardinal( it.selector ); + if( selectorIsCardinal ) + r = _.entity.elementWithCardinalSet( it.src, k, e ); + else + r = _.entity.elementSet( it.src, k, e ); + + if( r[ 1 ] === false ) + { + it.errCantSetHandle(); + } + + // if( it._srcWriteDownMethod === null ) + // { + // let selectorIsCardinal = _.numberIs( k ) && it.selectorIsCardinal( it.selector ); + // if( selectorIsCardinal ) + // it._srcWriteDownMethod = _.entity.elementWithCardinalSet.functor.call( _.container, it.src ); + // else + // it._srcWriteDownMethod = _.entity.elementSet.functor.call( _.container, it.src ); + // } + // + // let r = it._srcWriteDownMethod( k, e ); + // + // if( r[ 2 ] === false ) + // { + // it.errCantSetHandle(); + // } + +} + +// + +function dstWriteDown( eit ) +{ + let it = this; + _.assert( _.routineIs( it.dstWriteDownAct ) ); + if( eit.dst === undefined ) + if( it.missingAction === 'ignore' ) + return; + let val = eit.dst; + if( it.preservingIteration ) /* qqq : cover the option. seems it does not work in some cases */ + val = eit; + return it.dstWriteDownAct( eit, val ); + // return it.ContainerTypeToDstWriteDownMap[ it.iterable ]( eit, val ); +} + +// + +function dstWriteDownLong( eit, val ) +{ + let it = this; + it.dst.push( val ); +} + +// + +function dstWriteDownAux( eit, val ) +{ + let it = this; + it.dst[ eit.key ] = val; +} + +// + +function dstWriteDownHashMap( eit, val ) +{ + let it = this; + it.dst.set( eit.key, val ); +} + +// + +function dstWriteDownSet( eit, val ) +{ + let it = this; + it.dst.add( val ); +} + +// + +function makeEmptyLong() +{ + let it = this; + return []; +} + +// + +function makeEmptyAux() +{ + let it = this; + return Object.create( null ); +} + +// + +function makeEmptyHashMap() +{ + let it = this; + return new HashMap(); +} + +// + +function makeEmptySet( eit, val ) +{ + let it = this; + return new Set(); +} + +// + +function downUp() +{ + let it = this; + + _.assert( it.selectorType === 'down' ); + +} + +// + +function downDown() +{ + let it = this; +} + +// + +function downAscend() +{ + let it = this; + let counter = 1; + let dit = it; + + _.assert( arguments.length === 1 ); + + while( counter > 0 ) + { + dit = dit.down; + if( !dit ) + return it.errNoDownHandle(); + if( dit.selectorType === 'down' ) + { + counter += 1; + } + else if( dit.selectorType === 'here' ) + { + } + else if( dit.selectorType === 'terminal' ) + { + } + else if( dit.selectorType !== 'terminal' ) + { + counter -= 1; + } + } + + _.assert( it.iterationProper( dit ) ); + + it.visitPop(); + dit.visitPop(); + + /* */ + + let nit = it.iterationMake(); + + nit.choose( dit.src, it.selector, null, true ); + _.assert( nit.src === dit.src ); + _.assert( nit.exists === true ); + + _.assert( nit.dst === undefined ); + nit.dst = undefined; + nit.absoluteLevel -= 2; + + nit.iterate(); + + return true; +} + +// + +function hereUp() +{ + let it = this; + +} + +// + +function hereDown() +{ + let it = this; + + it.dst = it.src; + +} + +// + +function hereAscend() +{ + let it = this; + + let eit = it.iterationMake().choose( it.src, it.selector, null, true ); + eit.iterate(); + +} + +// + +function singleUp() +{ + let it = this; +} + +// + +function singleDown() +{ + let it = this; +} + +// + +function singleAscend( src ) +{ + let it = this; + + _.assert( arguments.length === 1 ); + + let eit = it.iterationMake().choose( undefined, it.selector, null, null ); + eit.iterate(); + +} + +// + +function terminalUp() +{ + let it = this; + + it.dst = it.src; + +} + +// + +function terminalDown() +{ + let it = this; +} + +// + +function globUp() +{ + let it = this; + + _.assert( !!it.globing ); + + /* qqq : teach it to parse more than single "*=" */ + + if( it.globing ) + it.globParse(); + + if( it.globing ) + if( it.parsedSelector.glob !== '*' ) + { + if( it.iterable ) + { + /* qqq : optimize for ** */ + it.src = _.path.globShortFilter + ({ + src : it.src, + selector : it.parsedSelector.glob, + onEvaluate : ( e, k ) => k, + }); + it.iterable = null; + it.srcChanged(); + } + } + + /* xxx : refactor */ + + let makeEmpty = it.ContainerTypeToMakeEmptyMap[ it.iterable ]; + if( makeEmpty ) + { + it.dst = makeEmpty.call( it ); + it.dstWriteDownAct = it.ContainerTypeToDstWriteDownMap[ it.iterable ]; + } + else + { + it.errDoesNotExistHandle(); + } + +} + +// + +function globDown() +{ + let it = this; + + if( !it.dstWritingDown ) + return; + + if( it.parsedSelector.limit === undefined ) + return; + + _.assert( !!it.globing ); + + let length = _.entity.lengthOf( it.dst ); + if( length !== it.parsedSelector.limit ) + { + let currentSelector = it.selector; + if( it.parsedSelector && it.parsedSelector.full ) + currentSelector = it.parsedSelector.full; + let err = _.looker.SeekingError + ( + `Select constraint "${ currentSelector }" failed with ${ length } elements` + + `\nSelector "${ it.iterator.selector }"` + + `\nAt : "${ it.path }"` + ); + debugger; /* eslint-disable-line no-debugger */ + if( it.onQuantitativeFail ) + it.onQuantitativeFail.call( it, err ); + else + throw err; + } + +} + +// -- +// namespace +// -- + +function select_head( routine, args ) +{ + return routine.defaults.head( routine, args ); +} + +// + +/** + * @summary Selects elements from source object( src ) using provided pattern( selector ). + * @description Returns iterator with result of selection + * @param {*} src Source entity. + * @param {String} selector Pattern that matches against elements in a entity. + * + * @example //select element with key 'a1' + * let it = _.selectIt( { a1 : 1, a2 : 2 }, 'a1' ); + * console.log( it.dst )//1 + * + * @example //select any that starts with 'a' + * let it = _.select( { a1 : 1, a2 : 2 }, 'a*' ); + * console.log( it.dst ) // { a1 : 1, a2 : 1 } + * + * @example //select with constraint, only one element should be selected + * let it = _.select( { a1 : 1, a2 : 2 }, 'a*=1' ); + * console.log( it.error ) // error + * + * @example //select with constraint, two elements + * let it = _.select( { a1 : 1, a2 : 2 }, 'a*=2' ); + * console.log( it.dst ) // { a1 : 1, a2 : 1 } + * + * @example //select inner element using path selector + * let it = _.select( { a : { b : { c : 1 } } }, 'a/b' ); + * console.log( it.dst ) //{ c : 1 } + * + * @example //select value of each property with name 'x' + * let it = _.select( { a : { x : 1 }, b : { x : 2 }, c : { x : 3 } }, '*\/x' ); + * console.log( it.dst ) //{a: 1, b: 2, c: 3} + * + * @example // select root + * let it = _.select( { a : { b : { c : 1 } } }, '/' ); + * console.log( it.dst ) + * + * @function selectIt + * @module Tools/base/Selector + * @namespace Tools.selector +*/ + +function exec_head( routine, args ) +{ + return routine.defaults.head( routine, args ); +} + +function exec_body( it ) +{ + it.execIt.body.call( this, it ); + return it.result; +} + +// + +/** + * @summary Selects elements from source object( src ) using provided pattern( selector ). + * @description Short-cur for {@link module:Tools/base/Selector.Tools.selector.select _.selectIt }. Returns found element(s) instead of iterator. + * @param {*} src Source entity. + * @param {String} selector Pattern that matches against elements in a entity. + * + * @example //select element with key 'a1' + * _.select( { a1 : 1, a2 : 2 }, 'a1' ); // 1 + * + * @example //select any that starts with 'a' + * _.select( { a1 : 1, a2 : 2 }, 'a*' ); // { a1 : 1, a2 : 1 } + * + * @example //select with constraint, only one element should be selected + * _.select( { a1 : 1, a2 : 2 }, 'a*=1' ); // error + * + * @example //select with constraint, two elements + * _.select( { a1 : 1, a2 : 2 }, 'a*=2' ); // { a1 : 1, a2 : 1 } + * + * @example //select inner element using path selector + * _.select( { a : { b : { c : 1 } } }, 'a/b' ); //{ c : 1 } + * + * @example //select value of each property with name 'x' + * _.select( { a : { x : 1 }, b : { x : 2 }, c : { x : 3 } }, '*\/x' ); //{a: 1, b: 2, c: 3} + * + * @example // select root + * _.select( { a : { b : { c : 1 } } }, '/' ); + * + * @function select + * @module Tools/base/Selector + * @namespace Tools.selector +*/ + +// + +function onSelectorUndecorate() +{ + let it = this; + _.assert( _.strIs( it.selector ) || _.numberIs( it.selector ) ); +} + +// + +function onSelectorUndecorateDoubleColon() +{ + return function onSelectorUndecorateDoubleColon() + { + let it = this; + if( !_.strIs( it.selector ) ) + return; + if( !_.strHas( it.selector, '::' ) ) + return; + it.selector = _.strIsolateRightOrAll( it.selector, '::' )[ 2 ]; + } +} + +// -- +// relations +// -- + +let last = _.looker.Looker.ContainerType.last; +_.assert( last > 0 ); +let ContainerType = +{ + ... _.looker.Looker.ContainerType, + down : last+1, + here : last+2, + single : last+3, + last : last+3, +} + +let ContainerTypeToName = +[ + ... _.looker.Looker.ContainerTypeToName, + 'down', + 'here', + 'single', +] + +let Ascend = +[ + ... _.looker.Looker.Ascend, + downAscend, + hereAscend, + singleAscend, +] + +let ContainerTypeToMakeEmptyMap = +{ + 1 : makeEmptyLong, + 2 : makeEmptyAux, + 3 : makeEmptyHashMap, + 4 : makeEmptySet, +} + +let ContainerTypeToDstWriteDownMap = +{ + 1 : dstWriteDownLong, + 2 : dstWriteDownAux, + 3 : dstWriteDownHashMap, + 4 : dstWriteDownSet, +} + + // 0 : 'terminal', + // 1 : 'countable', + // 2 : 'aux', + // 3 : 'hashMap', + // 4 : 'set', + +// + +let LookerExtension = Object.create( null ); + +LookerExtension.constructor = function Selector(){}; +LookerExtension.head = head; +LookerExtension.optionsFromArguments = optionsFromArguments; +LookerExtension.optionsToIteration = optionsToIteration; +LookerExtension.iteratorInitEnd = iteratorInitEnd; +LookerExtension.reperformIt = reperformIt; +LookerExtension.reperform = reperform; +LookerExtension.performBegin = performBegin; +LookerExtension.performEnd = performEnd; +LookerExtension.iterationMake = iterationMake; +LookerExtension.iterableEval = iterableEval; +LookerExtension.selectorIsCardinal = selectorIsCardinal; +LookerExtension.selectorCardinalParse = selectorCardinalParse; +LookerExtension.elementGet = elementGet; +LookerExtension.chooseBegin = chooseBegin; +LookerExtension.chooseEnd = chooseEnd; +LookerExtension.chooseRoot = chooseRoot; +LookerExtension.containerMake = containerMake +LookerExtension.iteratorSelectorChanged = iteratorSelectorChanged; +LookerExtension.iterationSelectorChanged = iterationSelectorChanged; +LookerExtension.globParse = globParse; + +LookerExtension.errNoDown = errNoDown; +LookerExtension.errNoDownHandle = errNoDownHandle; +LookerExtension.errCantSet = errCantSet; +LookerExtension.errCantSetHandle = errCantSetHandle; +LookerExtension.errDoesNotExist = errDoesNotExist; +LookerExtension.errDoesNotExistHandle = errDoesNotExistHandle; +LookerExtension.errHandle = errHandle; + +LookerExtension.visitUp = visitUp; +LookerExtension.visitUpBegin = visitUpBegin; + +LookerExtension.visitDown = visitDown; +// LookerExtension.performSet = performSet; +LookerExtension.downSet = downSet; + +LookerExtension.srcWriteDown = srcWriteDown; +LookerExtension.srcDel = srcDel; +// LookerExtension.srcWriteDownMap = srcWriteDownMap; +LookerExtension.dstWriteDown = dstWriteDown; +LookerExtension.dstWriteDownLong = dstWriteDownLong; /* xxx : remove? */ +LookerExtension.dstWriteDownAux = dstWriteDownAux; +LookerExtension.dstWriteDownHashMap = dstWriteDownHashMap; +LookerExtension.dstWriteDownSet = dstWriteDownSet; + +LookerExtension.makeEmptyLong = makeEmptyLong; /* xxx : remove? */ +LookerExtension.makeEmptyAux = makeEmptyAux; +LookerExtension.makeEmptyHashMap = makeEmptyHashMap; +LookerExtension.makeEmptySet = makeEmptySet; + +// down + +LookerExtension.downUp = downUp; +LookerExtension.downDown = downDown; +LookerExtension.downAscend = downAscend; + +// here + +LookerExtension.hereUp = hereUp; +LookerExtension.hereDown = hereDown; +LookerExtension.hereAscend = hereAscend; + +// single + +LookerExtension.singleUp = singleUp; +LookerExtension.singleDown = singleDown; +LookerExtension.singleAscend = singleAscend; + +// terminal + +LookerExtension.terminalUp = terminalUp; +LookerExtension.terminalDown = terminalDown; + +// glob + +LookerExtension.globUp = globUp; +LookerExtension.globDown = globDown; + +// fields + +LookerExtension.Action = Action; +LookerExtension.cardinalDelimeter = '#'; +LookerExtension.ContainerType = ContainerType; +LookerExtension.ContainerTypeToName = ContainerTypeToName; +LookerExtension.Ascend = Ascend; +LookerExtension.ContainerTypeToDstWriteDownMap = ContainerTypeToDstWriteDownMap; +LookerExtension.ContainerTypeToMakeEmptyMap = ContainerTypeToMakeEmptyMap; + +// + +let Iterator = Object.create( null ); + +Iterator.selectorArray = null; +Iterator.result = undefined; /* qqq : cover please */ +Iterator.originalResult = undefined; /* qqq : cover please */ +Iterator.state = 0; /* qqq : cover please */ +Iterator.absoluteLevel = null; + +// + +let Iteration = Object.create( null ); + +Iteration.exists = null; +Iteration.dst = undefined; +Iteration.selector = null; +Iteration.originalSelector = null; +Iteration.absoluteLevel = null; +Iteration.parsedSelector = null; + +Iteration.selectorType = null; +Iteration.dstWritingDown = true; +Iteration.dstWriteDownAct = null; +// Iteration._srcWriteDownMethod = null; + +// + +let IterationPreserve = Object.create( null ); +IterationPreserve.absoluteLevel = null; + +// + +const Selector = _.looker.classDefine +({ + name : 'Equaler', + parent : _.looker.Looker, + prime : Prime, + seeker : LookerExtension, + iterator : Iterator, + iteration : Iteration, + iterationPreserve : IterationPreserve, + exec : { head : exec_head, body : exec_body }, +}); + +_.assert( Selector.exec.head === exec_head ); +_.assert( Selector.exec.body === exec_body ); +_.assert( _.props.has( Selector.Iteration, 'dst' ) && Selector.Iteration.dst === undefined ); +_.assert( _.props.has( Selector.Iterator, 'result' ) && Selector.Iterator.result === undefined ); + +const select = Selector.exec; +const selectIt = Selector.execIt; + +// + +/** + * @summary Short-cut for {@link module:Tools/base/Selector.Tools.selector.select _.select }. Sets value of element selected by pattern ( o.selector ). + * @param {Object} o Options map + * @param {*} o.src Source entity + * @param {String} o.selector Pattern to select element(s). + * @param {*} o.set=null Entity to set. + * + * @example + * let src = {}; + _.selectSet({ src, selector : 'a', set : 1 }); + console.log( src.a ); //1 + * + * @function selectSet + * @module Tools/base/Selector + * @namespace Tools.selector +*/ + +let selectSet = _.routine.uniteInheriting( select.head, select.body ); + +var defaults = selectSet.defaults; +defaults.Seeker = defaults; +defaults.set = null; +defaults.action = Action.set; + +_.assert( Action.set > 0 ); + +// + +/** + * @summary Short-cut for {@link module:Tools/base/Selector.Tools.selector.select _.select }. Returns only unique elements. + * @param {*} src Source entity. + * @param {String} selector Pattern that matches against elements in a entity. + * + * @function select + * @module Tools/base/Selector + * @namespace Tools.selector +*/ + +function selectUnique_body( o ) +{ + _.assert( arguments.length === 1 ); + + let selected = _.select.body( o ); + + let result = _.replicate({ src : selected, onUp }); + + return result; + + function onUp( e, k, it ) + { + if( _.longLike( it.src ) ) + { + if( _.arrayIs( it.src ) ) + it.src = _.longOnce_( it.src ); + else + it.src = _.longOnce_( null, it.src ); + } + } + +} + +_.routine.extendInheriting( selectUnique_body, select.body ); +selectUnique_body.defaults.Seeker = selectUnique_body.defaults; +let selectUnique = _.routine.uniteReplacing( select.head, selectUnique_body ); + +// + +var FunctorExtension = +{ + onSelectorUndecorateDoubleColon, +} + +let SelectorExtension = +{ + + name : 'selector', + Seeker : Selector, + Selector, + Action, + + selectIt, + select, + selectSet, + selectUnique, + + onSelectorUndecorate, + +} + +let ToolsSupplementation = +{ + + Selector, + selectIt, + select, + selectSet, + selectUnique, + +} + +const Self = Selector; +_.props.extend( _, ToolsSupplementation ); +/* _.props.extend */Object.assign( _.selector, SelectorExtension ); +/* _.props.extend */Object.assign( _.selector.functor, FunctorExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wselector/proto/wtools/abase/l5/Selector.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wselector/proto/wtools/abase/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Selector_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Selector_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wstringer/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wstringer/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wstringer */ ( function wstringer() { function wstringer_naked() { +module.exports = require( '../wtools/abase/l3/Stringer.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wStringer', 'wstringer' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wstringer/proto/node_modules/wstringer' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wstringer/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wstringer_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wstringer */ })(); + +/* */ /* begin of file Stringer_s */ ( function Stringer_s() { function Stringer_s_naked() { (function _Stringer_s_() { + +'use strict'; + +/** + * Stringer nicely stringifies structures does not matter how complex or cycled them are. Convenient tool for fast diagnostic and inspection of data during development and in production. Use it to see more, faster. Refactoring required. + * Collection of tools for fast diagnostic and inspection of data during development and in production. + @module Tools/base/Stringer + @extends Tools +*/ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + +} + +// + +const Self = _global_.wTools; +const _global = _global_; +const _ = _global_.wTools; + +const _ArraySlice = Array.prototype.slice; +const _FunctionBind = Function.prototype.bind; +const _ObjectToString = Object.prototype.toString; +const _ObjectHasOwnProperty = Object.hasOwnProperty; + +// + +/** + * Short-cut for exportString function that works only with Routine type entities. + * Converts object passed by argument( src ) to string representation using + * options provided by argument( o ). + * + * @param {object} src - Source object. + * @param {Object} o - conversion o {@link module:Tools/base/Stringer.Tools.Stringer.exportStringOptions}. + * @param {boolean} [ options.onlyRoutines=true ] - makes object behavior Routine only. + * @see {@link wTools.exportStringFine} Check out main function for more usage options and details. + * @returns {string} Returns string that represents object data. + * + * @example + * //returns { routine add } + * _.entity.exportStringMethods( ( function add(){} ), { } ) + * + * @example + * //returns { routine noname } + * _.entity.exportStringMethods( ( function(){} ), { } ) + * + * @function exportStringMethods + * @namespace Tools + * @module Tools/base/Stringer + * + */ + +function exportStringMethods( src, o ) +{ + var o = o || Object.create( null ); + o.onlyRoutines = 1; + var result = _.entity.exportStringFine( src, o ); + return result; +} + +// + +/** + * Short-cut for exportString function that works with all entities, but ingnores Routine type. + * Converts object passed by argument( src ) to string representation using + * options provided by argument( o ). + * + * @param {object} src - Source object. + * @param {Object} o - conversion o {@link module:Tools/base/Stringer.Tools.Stringer.exportStringOptions}. + * @param {boolean} [ options.noRoutine=false ] - Ignores all entities of type Routine. + * @see {@link wTools.exportStringFine} Check out main function for more usage options and details. + * @returns {string} Returns string that represents object data. + * + * @example + * //returns [ 0, "a" ] + * _.entity.exportStringFields( [ function del(){}, 0, 'a' ], {} ) + * + * @example + * //returns { c : 1, d : "2" } + * _.entity.exportStringFields( { a : function b(){}, c : 1 , d : '2' }, {} ) + * + * @function exportStringFields + * @namespace Tools + * @module Tools/base/Stringer + * + */ + +function exportStringFields( src, o ) +{ + var o = o || Object.create( null ); + o.noRoutine = 1; + var result = _.entity.exportStringFine( src, o ); + return result; +} + +// + +/** +* @summary Options object for exportString function. +* @typedef {Object} exportStringOptions +* @property {boolean} [ o.wrap=true ] - Wrap array-like and object-like entities +* into "[ .. ]" / "{ .. }" respecitvely. +* @property {boolean} [ o.stringWrapper='\'' ] - Wrap string into specified string. +* @property {boolean} [ o.multilinedString=false ] - Wrap string into backtick ( `` ). +* @property {number} [ o.level=0 ] - Sets the min depth of looking into source object. Function starts from zero level by default. +* @property {number} [ o.levels=1 ] - Restricts max depth of looking into source object. Looks only in one level by default. +* @property {number} [ o.limitElementsNumber=0 ] - Outputs limited number of elements from object or array. +* @property {number} [ o.widthLimit=0 ] - Outputs limited number of characters from source string. +* @property {boolean} [ o.prependTab=true ] - Prepend tab before first line. +* @property {boolean} [ o.errorAsMap=false ] - Interprets Error as Map if true. +* @property {boolean} [ o.onlyOwn=true ] - Use only onlyOwn properties of ( src ), ignore properties of ( src ) prototype. +* @property {string} [ o.tab='' ] - Prepended before each line tab. +* @property {string} [ o.dtab=' ' ] - String attached to ( o.tab ) each time the function parses next level of object depth. +* @property {string} [ o.colon=' : ' ] - Colon between name and value, example : { a : 1 }. +* @property {boolean} [ o.noRoutine=false ] - Ignores all entities of type Routine. +* @property {boolean} [ o.noAtomic=false ] - Ignores all entities of type Atomic. +* @property {boolean} [ o.noArray=false ] - Ignores all entities of type Array. +* @property {boolean} [ o.noObject=false ] - Ignores all entities of type Object. +* @property {boolean} [ o.noRow=false ] - Ignores all entities of type Row. +* @property {boolean} [ o.noError=false ] - Ignores all entities of type Error. +* @property {boolean} [ o.noNumber=false ] - Ignores all entities of type Number. +* @property {boolean} [ o.noString=false ] - Ignores all entities of type String. +* @property {boolean} [ o.noUndefines=false ] - Ignores all entities of type Undefined. +* @property {boolean} [ o.noDate=false ] - Ignores all entities of type Date. +* @property {boolean} [ o.onlyRoutines=false ] - Ignores all entities, but Routine. +* @property {boolean} [ o.onlyEnumerable=true ] - Ignores all non-enumerable properties of object ( src ). +* @property {boolean} [ o.noSubObject=false ] - Ignores all child entities of type Object. +* @property {number} [ o.precision=null ] - An integer specifying the number of significant digits, example : [ '1500' ]. +* Number must be between 1 and 21. +* @property {number} [ o.fixed=null ] - The number of digits to appear after the decimal point, example : [ '58912.001' ]. +* Number must be between 0 and 20. +* @property {string} [ o.comma=', ' ] - Splitter between elements, example : [ 1, 2, 3 ]. +* @property {boolean} [ o.multiline=false ] - Writes each object property in new line. +* @property {boolean} [ o.escaping=false ] - enable escaping of special characters. +* @property {boolean} [ o.jsonLike=false ] - enable conversion to JSON string. +* @property {boolean} [ o.jsLike=false ] - enable conversion to JS string. +* @namespace Tools + * @module Tools/base/Stringer +*/ + +/** + * Converts object passed by argument( src ) to string format using parameters passed + * by argument( o ).If object ( src ) has onlyOwn ( exportString ) method defined function uses it for conversion. + * + * @param {object} src - Source object for representing it as string. + * @param {Object} o - conversion o {@link module:Tools/base/Stringer.Tools.Stringer.exportStringOptions}. + * @returns {string} Returns string that represents object data. + * + * @example + * //Each time function parses next level of object depth + * //the ( o.dtab ) string ( '-' ) is attached to ( o.tab ). + * //returns + * // { // level 1 + * // -a : 1, + * // -b : 2, + * // -c : + * // -{ // level 2 + * // --subd : "some test", + * // --sube : true, + * // --subf : { x : 1 // level 3} + * // -} + * // } + * _.entity.exportString( { a : 1, b : 2, c : { subd : 'some test', sube : true, subf : { x : 1 } } }, { levels : 3, dtab : '-'} ); + * + * @example + * //returns " \n1500 " + * _.entity.exportString( ' \n1500 ', { escaping : 1 } ); + * + * @example + * //returns + * // " + * // 1500 " + * _.entity.exportString( ' \n1500 ' ); + * + * @example + * //returns 14.5333 + * _.entity.exportString( 14.5333 ); + * + * @example + * //returns 1.50e+3 + * _.entity.exportString( 1500, { precision : 3 } ); + * + * @example + * //returns 14.53 + * _.entity.exportString( 14.5333, { fixed : 2 } ); + * + * @example + * //returns true + * _.entity.exportString( 1 !== 2 ); + * + * @example + * //returns '' + * _.entity.exportString( 1 !== 2, { noAtomic : 1 } ); + * + * @example + * //returns [ 1, 2, 3, 4 ] + * _.entity.exportString( [ 1, 2, 3, 4 ] ); + * + * @example + * //returns [Array with 3 elements] + * _.entity.exportString( [ 'a', 'b', 'c' ], { levels : 0 } ); + * + * @example + * //returns [ 1, 2, 3 ] + * _.entity.exportString( _.entity.exportString( [ 'a', 'b', 'c', 1, 2, 3 ], { levels : 2, noString : 1} ) ); + * + * @example + * //returns + * // [ + * // { Object with 1 elements }, + * // { Object with 1 elements } + * // ] + * _.entity.exportString( [ { a : 1 }, { b : 2 } ] ); + * + * @example + * //returns + * // " a : 1 + * // b : 2" + * _.entity.exportString( [ { a : 1 }, { b : 2 } ], { levels : 2, wrap : 0 } ); + * + * @example + * //returns + * // [ + * // { a : 1 }, + * // { b : 2 } + * // ] + * _.entity.exportString( [ { a : 1 }, { b : 2 } ], { levels : 2 } ); + * + * @example + * //returns 1 , 2 , 3 , 4 + * _.entity.exportString( [ 1, 2, 3, 4 ], { wrap : 0, comma : ' , ' } ); + * + * @example + * //returns [ 0.11, 40 ] + * _.entity.exportString( [ 0.11112, 40.4 ], { precision : 2 } ); + * + * @example + * //returns [ 2.00, 1.56 ] + * _.entity.exportString( [ 1.9999, 1.5555 ], { fixed : 2 } ); + * + * @example + * //returns + * // [ + * // 0, + * // [ + * // 1, + * // 2, + * // 3 + * // ], + * // 4 + * // ] + * _.entity.exportString( [ 0, [ 1, 2, 3 ], 4 ], { levels : 2, multiline : 1 } ); + * + * @example + * //returns [ 1, 2, [ other 3 element(s) ] ] + * _.entity.exportString( [ 1, 2 , 3, 4, 5 ], { limitElementsNumber : 2 } ); + * + * @example + * //returns [ routine sample ] + * _.entity.exportString( function sample( ){ }); + * + * @example + * //returns [ rotuine without name ] + * _.entity.exportString( function add( ){ }, { levels : 0 } ); + * + * @example + * //If object ( src ) has onlyOwn ( exportString ) method defined function uses it for conversion + * //returns + * //function func( ) { + * //console.log('sample'); + * //} + * var x = function func ( ) + * { + * console.log( 'sample' ); + * } + * x.exportString = x.toString; + * _.entity.exportString( x ); + * + * @example + * //returns { o : 1, y : 3 } + * _.entity.exportString( { o : 1, y : 3 } ); + * + * @example + * //returns { Object with 1 elements } + * _.entity.exportString( { o : 1 }, { levels : 0 } ); + * + * @example + * //returns + * { + * o : { p : "value" } + * } + * _.entity.exportString( { o : { p : 'value' } }, { levels : 2 } ); + * + * @example + * //returns + * // { + * // y : "value1" + * // } + * _.entity.exportString( { y : 'value1', o : { p : 'value2' } }, { levels : 2, noSubObject : 1} ); + * + * @example + * //returns a : 1 | b : 2 + * _.entity.exportString( { a : 1, b : 2 }, { wrap : 0, comma : ' | ' } ); + * + * @example + * //returns { b : 1, c : 2 } + * _.entity.exportString( { a : 'string', b : 1 , c : 2 }, { levels : 2 , noString : 1 } ); + * + * @example + * //returns { a : string, b : str, c : 2 } + * _.entity.exportString( { a : 'string', b : "str" , c : 2 }, { levels : 2 , stringWrapper : '' } ); + * + * @example + * //returns { "a" : "string", "b" : 1, "c" : 2 } + * _.entity.exportString( { a : 'string', b : 1 , c : 2 }, { levels : 2 , jsonLike : 1 } ); + * + * @example + * //returns + * // '{', + * // ' a : 1, ', + * // ' b : 2, ', + * // '{ other 2 element(s) }', + * // '}', + * _.entity.exportString( { a : 1, b : 2, c : 3, d : 4 }, { limitElementsNumber : 2 } ); + * + * @example + * //returns { stack : "Error: my message2"..., message : "my message2" } + * _.entity.exportString( new Error('my message2'), { onlyEnumerable : 0, errorAsMap : 1 } ); + * + * @example + * //returns + * // "{ + * // a : `line1 + * // line2 + * // line3` + * // }" + * _.entity.exportString( { a : "line1\nline2\nline3" }, { levels: 2, multilinedString : 1 } ); + * + * @function exportString + * @throws { Exception } Throw an exception if( o ) is not a Object. + * @throws { Exception } Throw an exception if( o.stringWrapper ) is not equal true when ( o.jsonLike ) is true. + * @throws { Exception } Throw an exception if( o.multilinedString ) is not equal false when ( o.jsonLike ) is true. + * @throws { RangeError } Throw an exception if( o.precision ) is not between 1 and 21. + * @throws { RangeError } Throw an exception if( o.fixed ) is not between 0 and 20. + * @namespace Tools + * @module Tools/base/Stringer + * + */ + +function _exportStringFine_functor() +{ + + var primeFilter = + { + + noRoutine : 0, + noAtomic : 0, + noArray : 0, + noObject : 0, + noRow : 0, + noError : 0, + noNumber : 0, + noString : 0, + noDate : 0, + noUndefines : 0, + + } + + var composes = + { + + levels : 1, + level : 0, + + wrap : 1, + // stringWrapper : '\'', + stringWrapper : null, + keyWrapper : '', + prependTab : 1, + errorAsMap : 0, + onlyOwn : 1, + tab : '', + dtab : ' ', + colon : ' : ', + limitElementsNumber : 0, + widthLimit : 0, + heightLimit : 0, + + format : 'string.diagnostic', + + } + + /**/ + + var optional = + { + + /* secondary filter */ + + noSubObject : 0, + onlyRoutines : 0, + onlyEnumerable : 1, + + /**/ + + precision : null, + fixed : null, + // comma : ', ', + comma : null, + multiline : 0, + multilinedString : null, + escaping : 0, + jsonLike : 0, + jsLike : 0, + + } + + var restricts = + { + /*level : 0, */ + } + + Object.preventExtensions( primeFilter ); + Object.preventExtensions( composes ); + Object.preventExtensions( optional ); + Object.preventExtensions( restricts ); + + var def; + + def = _.props.extend( null, optional, primeFilter, composes ); + + var routine = exportStringFine; + routine.defaults = def; + routine.methods = _.entity.exportStringMethods; + routine.fields = _.entity.exportStringFields; + // routine.notMethod = 1; + return routine; + + function exportStringFine( src, o ) + { + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.object.isBasic( o ) || o === undefined, 'Expects map {-o-}' ); + + var o = o || Object.create( null ); + var exportStringDefaults = Object.create( null ); + // if( !_.primitiveIs( src ) && 'exportString' in src && _.routineIs( src.exportString ) && !src.exportString.notMethod && _.object.isBasic( src.exportString.defaults ) ) + if( !_.primitiveIs( src ) && 'exportString' in src && _.routineIs( src.exportString ) && _.instanceIs( src ) && _.object.isBasic( src.exportString.defaults ) ) + exportStringDefaults = src.exportString.defaults; + + if( o.levels === undefined || o.levels === null ) + if( o.jsonLike || o.jsLike ) + o.levels = 1 << 20; + + if( o.jsLike ) + { + if( o.escaping === undefined || o.escaping === null ) + o.escaping = 1; + if( o.keyWrapper === undefined || o.keyWrapper === null ) + o.keyWrapper = '"'; + if( o.stringWrapper === undefined || o.stringWrapper === null ) + o.stringWrapper = '`'; + } + + if( o.jsonLike ) + { + if( o.escaping === undefined || o.escaping === null ) + o.escaping = 1; + if( o.keyWrapper === undefined || o.keyWrapper === null ) + o.keyWrapper = '"'; + if( o.stringWrapper === undefined || o.stringWrapper === null ) + o.stringWrapper = '"'; + } + + // _.map.assertHasOnly( o, [ composes, primeFilter, optional ] ); + // o = _.props.supplement( null, o, exportStringDefaults, composes, primeFilter ); + + _.map.assertHasOnly( o, def ); + o = _.props.supplement( o, def ); + + if( o.multilinedString === undefined || o.multilinedString === null ) + o.multilinedString = o.stringWrapper === '`'; + + if( o.stringWrapper === undefined || o.stringWrapper === null ) + if( o.multilinedString ) + o.stringWrapper = '`'; + else + o.stringWrapper = `'`; + + if( o.onlyRoutines ) + { + _.assert( !o.noRoutine, 'Expects {-o.noRoutine-} false if( o.onlyRoutines ) is true' ); + for( var f in primeFilter ) + o[ f ] = 1; + o.noRoutine = 0; + } + + if( o.comma === undefined || o.comma === null ) + o.comma = o.wrap ? ', ' : ' '; + + if( o.comma && !_.strIs( o.comma ) ) + o.comma = ', '; + + // if( o.stringWrapper === '`' && o.multilinedString === undefined ) + // o.multilinedString = 1; + + _.assert( _.strIs( o.stringWrapper ), 'Expects string {-o.stringWrapper-}' ); + + if( o.jsonLike ) + { + if( !o.jsLike ) + _.assert( o.stringWrapper === '"', 'Expects double quote ( o.stringWrapper ) true if either ( o.jsonLike ) or ( o.jsLike ) is true' ); + _.assert( !o.multilinedString, 'Expects {-o.multilinedString-} false if either ( o.jsonLike ) or ( o.jsLike ) is true to make valid JSON' ); + } + + var r = _.entity._exportString( src, o ); + + return r ? r.text : ''; + } + +} + +// + +let exportStringFine = _exportStringFine_functor(); +exportStringFine.functor = _exportStringFine_functor; +let exportString = exportStringFine; +_.assert( exportString.defaults.multilinedString !== undefined ); + +// + +function exportStringNice( src, o ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + + o = _.routine.options_( exportStringNice, o || null ); + + var result = _.entity.exportString( src, o ); + + return result; +} + +exportStringNice.defaults = +{ + ... exportStringFine.defaults, + escaping : 0, + multilinedString : 0, + multiline : 1, + levels : 9, + stringWrapper : '', + keyWrapper : '', + tab : '', + wrap : 0, + comma : '', +} + +// + +function exportStringSolo( src, o ) +{ + o = _.routine.options_( exportStringSolo, o || null ); + let result = _.entity.exportStringNice( src, o ); + // return _.strReplace( result, '\n', ' ' ); + return _.entity.exportStringNice( src, o ) + .split( '\n' ) + .map( ( e ) => e.trim() ) + .join( ' ' ); +} + +exportStringSolo.defaults = +{ + ... exportStringNice.defaults, + levels : 1, +} + +// + +function exportJson( src, o ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + + o = _.routine.options_( exportJson, o || null ); + + if( o.cloning ) + src = _.cloneData({ src }); + + delete o.cloning; + + var result = _.entity.exportString( src, o ); + + return result; +} + +exportJson.defaults = +{ + jsonLike : 1, + levels : 1 << 20, + cloning : 1, +} + +// + +function exportJs( src, o ) +{ + _.assert( arguments.length === 1 || arguments.length === 2 ); + + o = _.routine.options_( exportJs, o || null ); + + var result = _.entity.exportString( src, o ); + + return result; +} + +exportJs.defaults = +{ + escaping : 1, + multilinedString : 1, + levels : 1 << 20, + stringWrapper : null, + keyWrapper : null, + jsLike : 1, +} + +// + +function _exportString( src, o ) +{ + + if( o.precision !== null ) + if( o.precision < 1 || o.precision > 21 ) + { + throw _.err( 'RangeError' ); + } + + if( o.fixed !== null ) + if( o.fixed < 0 || o.fixed > 20 ) + throw _.err( 'RangeError' ); + + var result = ''; + var simple = 1; + var type = _.entity.strTypeSecondary( src ); + + if( o.level >= o.levels ) + { + return { text : _.entity._exportStringShortAct( src, o ), simple : 1 }; + } + + if( !_.entity._exportStringIsVisibleElement( src, o ) ) + return; + + var isPrimitive = _.primitiveIs( src ); + var isLong = _.longIs( src ); + var isArray = _.arrayIs( src ); + var isObject = !isLong && _.object.isBasic( src ); + var isObjectLike = !isLong && _.objectLike( src ) && !( 'toString' in src ); + + /* */ + + // if( !isPrimitive && 'exportString' in src && _.routineIs( src.exportString ) && !src.exportString.notMethod && !_ObjectHasOwnProperty.call( src, 'constructor' ) ) + if( !isPrimitive && 'exportString' in src && _.routineIs( src.exportString ) && _.instanceIs( src ) ) + { + + _.assert + ( + src.exportString.length === 0 || src.exportString.length === 1, + 'Method exportString should expect either none or one argument' + ); + + // var r = src.exportString( o ); + var r = src.exportString({ it : o }); + if( _.object.isBasic( r ) ) + { + _.assert( r.simple !== undefined && r.text !== undefined ); + simple = r.simple; + result += r.text; + } + else if( _.strIs( r ) ) + { + simple = r.indexOf( '\n' ) === -1; + result += r; + } + else throw _.err( 'unexpected' ); + + } + // else if( _.vectorAdapterIs( src ) ) + // { + // result += _.vectorAdapter.exportString( src, o ); + // } + else if( _.errIs( src ) ) + { + + if( !o.errorAsMap ) + { + result += src.toString(); + } + else + { + if( o.onlyEnumerable === undefined || o.onlyEnumerable === null ) + o.onlyEnumerable = 1; + var o2 = _.props.extend( null, o ); + o2.onlyEnumerable = 0; + var r = _.entity._exportStringFromObject( src, o2 ); + result += r.text; + simple = r.simple; + } + + } + else if( type === 'Function' ) + { + result += _.entity._exportStringFromRoutine( src, o ); + } + else if( type === 'Number' && _.numberIs( src ) ) + { + result += _.entity._exportStringFromNumber( src, o ); + } + else if( type === 'BigInt' ) + { + result += _.entity._exportStringFromBigInt( src, o ); + } + else if( type === 'String' ) + { + result += _.entity._exportStringFromStr( src, o ); + } + else if( type === 'Date' ) + { + if( o.jsonLike ) + result += '"' + src.toISOString() + '"'; + else if( o.jsLike ) + result += 'new Date( \'' + src.toISOString() + '\' )'; + else + result += src.toISOString(); + } + else if( type === 'Symbol' ) + { + result += _.entity._exportStringFromSymbol( src, o ); + } + else if( _.bufferRawIs( src ) ) + { + var r = _.entity._exportStringFromBufferRaw( src, o ); + result += r.text; + simple = r.simple; + } + else if( _.bufferTypedIs( src ) ) + { + var r = _.entity._exportStringFromBufferTyped( src, o ); + result += r.text; + simple = r.simple; + } + else if( _.bufferNodeIs( src ) ) + { + var r = _.entity._exportStringFromBufferNode( src, o ); + result += r.text; + simple = r.simple; + } + else if( isLong ) + { + var r = _.entity._exportStringFromArray( src, o ); + result += r.text; + simple = r.simple; + } + else if( isObject ) + { + var r = _.entity._exportStringFromObject( src, o ); + result += r.text; + simple = r.simple; + } + else if( _.hashMapLike( src ) ) + { + var r = _.entity._exportStringFromHashMap( src, o ); + result += r.text; + simple = r.simple; + } + else if( _.setLike( src ) ) + { + var r = _.entity._exportStringFromSet( src, o ); + result += r.text; + simple = r.simple; + } + else if( !isPrimitive && _.routineIs( src.toString ) ) + { + result += src.toString(); + } + else + { + if( o.jsonLike ) + { + if( src === undefined || src === NaN ) + result += 'null'; + else + result += String( src ); + } + else + { + result += String( src ); + } + } + + return { text : result, simple }; +} + +// + +/** + * Converts object passed by argument( src ) to string representation using + * options provided by argument( o ) for string and number types. + * Returns string with object type for routines and errors, iso format for date, string representation for atomic. + * For object, array and row returns count of elemets, example: '[ Row with 3 elements ]'. + * + * @param {object} src - Source object. + * @param {Object} o - Conversion options {@link module:Tools/base/Stringer.Tools.Stringer.exportStringOptions}. + * @returns {string} Returns string that represents object data. + * + * @example + * //returns [ Array with 3 elements ] + * _._exportStringShortAct( [ function del(){}, 0, 'a' ], { levels : 0 } ) + * + * @function _exportStringShortAct + * @namespace Tools + * @module Tools/base/Stringer + * + */ + +function _exportStringShortAct( src, o ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.object.isBasic( o ), 'Expects map {-o-}' ); + + var result = ''; + + try + { + + if( _.strIs( src ) ) + { + + /* xxx : ? */ + var o2 = + { + widthLimit : o.widthLimit ? Math.min( o.widthLimit, 40 ) : 40, + heightLimit : o.heightLimit || 0, + stringWrapper : o.stringWrapper, + prefix : o.prefix, + postfix : o.postfix, + infix : o.infix, + shortDelimeter : o.shortDelimeter, + } + result = _.entity._exportStringFromStr( src, o2 ); + + } + else if( _.errIs( src ) ) + { + result += _ObjectToString.call( src ); + } + else if( _.routineIs( src ) ) + { + result += _.entity._exportStringFromRoutine( src, o ); + } + else if( _.numberIs( src ) ) + { + result += _.entity._exportStringFromNumber( src, o ); + } + else + { + result = _.entity.exportStringDiagnosticShallow( src ); + } + + } + catch( err ) + { + throw _.err( err ); + } + + return result; +} + +// + +/** + * Checks if object provided by argument( src ) must be ignored by exportString() function. + * Filters are provided by argument( o ). + * Returns false if object must be ignored. + * + * @param {object} src - Source object. + * @param {Object} o - Filters {@link module:Tools/base/Stringer.Tools.Stringer.exportStringOptions}. + * @returns {boolean} Returns result of filter check. + * + * @example + * //returns false + * _.entity.exportStringIsVisibleElement( function del(){}, { noRoutine : 1 } ); + * + * @function _exportStringIsVisibleElement + * @namespace Tools + * @module Tools/base/Stringer + * + */ + +function _exportStringIsVisibleElement( src, o ) +{ + + var isPrimitive = _.primitiveIs( src ); + var isArray = _.longIs( src ); + var isObject = !isArray && _.objectLike( src ); + var type = _.entity.strTypeSecondary( src ); + + /* */ + + // if( !isPrimitive && 'exportString' in src && _.routineIs( src.exportString ) && !src.exportString.notMethod ) + if( !isPrimitive && 'exportString' in src && _.routineIs( src.exportString ) && _.instanceIs( src ) ) + { + if( isObject && o.noObject ) + return false; + if( isArray && o.noArray ) + return false; + + return true; + } + else if( _.vectorAdapterIs( src ) ) + { + if( o.noRow ) + return false; + return true; + } + else if( _.errIs( src ) ) + { + if( o.noError ) + return false; + return true; + } + else if( type === 'Function' ) + { + if( o.noRoutine ) + return false; + return true; + } + else if( type === 'Number' ) + { + if( o.noNumber || o.noAtomic ) + return false; + return true; + } + else if( type === 'String' ) + { + if( o.noString || o.noAtomic ) + return false; + return true; + } + else if( type === 'Date' ) + { + if( o.noDate ) + return false; + return true; + } + else if( isArray ) + { + if( o.noArray ) + return false; + + if( !o.wrap ) + { + src = _.entity._exportStringFromArrayFiltered( src, o ); + if( !src.length ) + return false; + } + + return true; + } + else if( isObject ) + { + if( o.noObject ) + return false; + + if( !o.wrap ) + { + var keys = _.entity._exportStringFromObjectKeysFiltered( src, o ); + if( !keys.length ) + return false; + } + + return true; + } + else if( !isPrimitive && _.routineIs( src.toString ) ) + { + if( isObject && o.noObject ) + return false; + if( isArray && o.noArray ) + return false; + return true; + } + else + { + if( o.noAtomic ) + return false; + if( o.noUndefines && src === undefined ) + return false; + return true; + } + +} + +// + +/** + * Checks if object length provided by argument( element ) is enough to represent it as single line string. + * Options are provided by argument( o ). + * Returns true if object can be represented as one line. + * + * @param {object} element - Source object. + * @param {Object} o - Check options {@link module:Tools/base/Stringer.Tools.Stringer.exportStringOptions}. + * @param {boolean} [ o.escaping=false ] - enable escaping of special characters. + * @returns {boolean} Returns result of length check. + * + * @example + * //returns true + * _.entity.exportStringIsSimpleElement( 'string', { } ); + * + * @example + * //returns false + * _.entity.exportStringIsSimpleElement( { a : 1, b : 2, c : 3, d : 4, e : 5 }, { } ); + * + * @function _exportStringIsSimpleElement + * @throws { Exception } Throw an exception if( arguments.length ) is not equal 2. + * @namespace Tools + * @module Tools/base/Stringer + * + */ + +function _exportStringIsSimpleElement( element, o ) +{ + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.object.isBasic( o ) || o === undefined, 'Expects map {-o-}' ); + + if( _.strIs( element ) ) + { + if( element.length > 40 ) + return false; + if( !o.escaping ) + return element.indexOf( '\n' ) === -1; + return true; + } + else if( element && !_.object.isBasic( element ) && _.numberIs( element.length ) ) + return !element.length; + else if( _.object.isBasic( element ) || _.objectLike( element ) ) + return !_.entity.lengthOf( element ); + else + return _.primitiveIs( element ); + +} + +// + +/** + * Returns string representation of routine provided by argument( src ) using options + * from argument( o ). + * + * @param {object} src - Source object. + * @param {Object} o - conversion options {@link module:Tools/base/Stringer.Tools.Stringer.exportStringOptions}. + * @returns {string} Returns routine as string. + * + * @example + * //returns [ routine a ] + * _.entity.exportStringFromRoutine( function a(){}, {} ); + * + * @function _exportStringFromRoutine + * @namespace Tools + * @module Tools/base/Stringer + * + */ + +function _exportStringFromRoutine( src, o ) +{ + var result = ''; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.routineIs( src ), 'Expects routine {-src-}' ); + + if( o.jsLike ) + { + if( _.routineSourceGet ) + result = _.routineSourceGet( src ); + else + result = src.toString(); + } + else + { + result = '[ routine ' + ( src.name || src._name || 'without name' ) + ' ]'; + } + + return result; +} + +// + +/** + * Converts Number( src ) to String using one of two possible options: precision or fixed. + * If no option specified returns source( src ) as simple string. + * + * @param {Number} src - Number to convert. + * @param {Object} o - Contains conversion options {@link module:Tools/base/Stringer.Tools.Stringer.exportStringOptions}. + * @returns {String} Returns number converted to the string. + * + * @example + * //returns 8.9 + * _._exportStringFromNumber( 8.923964453, { precision : 2 } ); + * + * @example + * //returns 8.9240 + * _._exportStringFromNumber( 8.923964453, { fixed : 4 } ); + * + * @example + * //returns 8.92 + * _._exportStringFromNumber( 8.92, { } ); + * + * @function _exportStringFromNumber + * @throws {Exception} If no arguments provided. + * @throws {Exception} If( src ) is not a Number. + * @throws {Exception} If( o ) is not a Object. + * @throws {RangeError} If( o.precision ) is not between 1 and 21. + * @throws {RangeError} If( o.fixed ) is not between 0 and 20. + * @namespace Tools + * @module Tools/base/Stringer + * +*/ + +function _exportStringFromNumber( src, o ) +{ + var result = ''; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.numberIs( src ) && _.object.isBasic( o ) ); + + if( o.precision !== null ) + if( o.precision < 1 || o.precision > 21 ) + throw _.err( 'RangeError' ); + + if( o.fixed !== null ) + if( o.fixed < 0 || o.fixed > 20 ) + throw _.err( 'RangeError' ); + + if( _.numberIs( o.precision ) ) + result += src.toPrecision( o.precision ); + else if( _.numberIs( o.fixed ) ) + result += src.toFixed( o.fixed ); + else + result += String( src ); + + if( Object.is( src, -0 ) ) + result = '-' + result; + + return result; +} + +// + +function _exportStringFromBigInt( src, o ) +{ + let result = ''; + + if( o.jsonLike ) + result += '"' + src.toString() + 'n"'; + else if( o.jsLike ) + result += src.toString() + 'n'; + else + result += String( src ); + + return result; +} + +// + +function _exportStringFromSymbol( src, o ) +{ + let text = src.toString().slice( 7, -1 ); + let result = `{- Symbol${text ? ' ' + text + ' ' : ' '}-}`; + return result; +} + +// + +/** + * Adjusts source string. Takes string from argument( src ) and options from argument( o ). + * Limits string length using option( o.widthLimit ), disables escaping characters using option( o.escaping ), + * wraps source into specified string using( o.stringWrapper ). + * Returns result as new string or source string if no changes maded. + * + * @param {object} src - String to parse. + * @param {Object} o - Contains conversion options {@link module:Tools/base/Stringer.Tools.Stringer.exportStringOptions}. + * @returns {String} Returns result of adjustments as new string. + * + * @example + * //returns "hello" + * _._exportStringFromStr( 'hello', {} ); + * + * @example + * //returns "test\n" + * _._exportStringFromStr( 'test\n', { escaping : 1 } ); + * + * @example + * //returns [ "t" ... "t" ] + * _._exportStringFromStr( 'test', { widthLimit: 2 } ); + * + * @example + * //returns `test` + * _._exportStringFromStr( 'test', { stringWrapper : '`' } ); + * + * @function _exportStringFromStr + * @throws {Exception} If no arguments provided. + * @throws {Exception} If( src ) is not a String. + * @throws {Exception} If( o ) is not a Object. + * @namespace Tools + * @module Tools/base/Stringer + * +*/ + +function _exportStringFromStr( src, o ) +{ + var result = ''; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( src ), 'Expects string {-src-}' ); + _.assert( _.object.isBasic( o ) || o === undefined, 'Expects map {-o-}' ); + + if( o.stringWrapper === undefined ) + o.stringWrapper = `\'`; + + var q = o.stringWrapper; + + if( o.widthLimit ) + { + + if( o.shortDelimeter === undefined || o.shortDelimeter === null ) + o.shortDelimeter = _.strShort_.defaults.delimeter || '...'; + + result = _.strShort_ + ({ + src : _.strEscape( src ), + widthLimit : o.widthLimit - q.length*2, + heightLimit : o.heightLimit || 0, + delimeter : o.shortDelimeter, + }).result; + + // if( result.length > o.widthLimit ) + // { + // result = '[ ' + result + ' ]'; + // q = ''; + // } + } + else if( o.escaping ) + { + if( o.stringWrapper === undefined ) + debugger; + result = _.strEscape({ src, stringWrapper : o.stringWrapper }); + } + else + { + result = src; + } + + // if( o.stringWrapper && !o.widthLimit ) + // { + // result = q + result + q; + // } + + if( q ) + // if( !o.widthLimit || result.length < o.widthLimit ) + { + result = q + result + q; + } + + return result; +} + +// + +function _exportStringFromHashMap( src, o ) +{ + var result = 'HashMap\n'; + var simple = 0; + + _.assert( src instanceof HashMap ); + + src.forEach( function( e, k ) + { + // result += '\n' + k + ' : ' + e; + result += '\n' + k + ' : ' + _.entity.exportStringDiagnosticShallow( e ); + }); + + return { text : result, simple : 0 }; + + /* item options */ + + var optionsItem = _.props.extend( null, o ); + optionsItem.noObject = o.noSubObject ? 1 : optionsItem.noObject; + optionsItem.tab = o.tab + o.dtab; + optionsItem.level = o.level + 1; + optionsItem.prependTab = 0; + + /* get names */ + + var keys = _.entity._exportStringFromObjectKeysFiltered( src, o ); + + /* empty case */ + + var length = keys.length; + if( length === 0 ) + { + if( !o.wrap ) + return { text : '', simple : 1 }; + return { text : '{}', simple : 1 }; + } + + /* is simple */ + + var simple = !optionsItem.multiline; + if( simple ) + simple = length < 4; + if( simple ) + for( var k in src ) + { + simple = _.entity._exportStringIsSimpleElement( src[ k ], optionsItem ); + if( !simple ) + break; + } + + /* */ + + result += _.entity._exportStringFromContainer + ({ + values : src, + names : keys, + optionsContainer : o, + optionsItem, + simple, + prefix : '{', + postfix : '}', + }); + + return { text : result, simple }; +} + +// + +function _exportStringFromSet( src, o ) +{ + let result = _.entity._exportStringFromArray( _.array.from( src ), o ); + result.text = `new Set(${result.text})` ; + return result; +} + +// + +function _exportStringFromBufferTyped( src, o ) +{ + var result = ''; + + _.assert( _.bufferTypedIs( src ) ); + + src.forEach( function( e, k ) + { + if( k !== 0 ) + result += ', '; + result += _.entity._exportStringFromNumber( e, o ); + }); + + result = '( new ' + src.constructor.name + '([ ' + result + ' ]) )'; + + return { text : result, simple : true }; +} + +// + +function _exportStringFromBufferRaw( src, o ) +{ + var result = ''; + + _.assert( _.bufferRawIs( src ) ); + + ( new U8x( src ) ).forEach( function( e, k ) + { + if( k !== 0 ) + result += ', '; + result += '0x' + e.toString( 16 ); + }); + + result = '( new U8x([ ' + result + ' ]) ).buffer'; + + return { text : result, simple : true }; +} + +// + +function _exportStringFromBufferNode( src, o ) +{ + var result = ''; + + _.assert( _.bufferNodeIs( src ) ); + + let k = 0; + for ( let value of src.values() ) + { + if( k !== 0 ) + result += ', '; + result += value; + ++k; + } + + result = '( BufferNode.from([ ' + result + ' ]) )'; + + return { text : result, simple : true }; +} + +// + +function _exportStringFromArrayFiltered( src, o ) +{ + var result = ''; + + _.assert( arguments.length === 2 ); + + /* item options */ + + var optionsItem = _.props.extend( null, o ); + optionsItem.level = o.level + 1; + + /* filter */ + + var v = 0; + var length = src.length; + for( var i = 0 ; i < length ; i++ ) + { + v += !!_.entity._exportStringIsVisibleElement( src[ i ], optionsItem ); + } + + if( v !== length ) + { + var i2 = 0; + var i = 0; + var src2 = _.long.makeUndefined( src, v ); + while( i < length ) + { + if( _.entity._exportStringIsVisibleElement( src[ i ], optionsItem ) ) + { + src2[ i2 ] = src[ i ]; + i2 += 1; + } + i += 1; + } + src = src2; + length = src.length; + } + + return src; +} + +// + +/** + * Converts array provided by argument( src ) into string representation using options provided by argument( o ). + * + * @param {object} src - Array to convert. + * @param {Object} o - Contains conversion options {@link module:Tools/base/Stringer.Tools.Stringer.exportStringOptions}. + * @returns {String} Returns string representation of array. + * + * @example + * //returns + * //[ + * // [ Object with 1 elements ], + * // [ Object with 1 elements ] + * //] + * _.entity.exportStringFromArray( [ { a : 1 }, { b : 2 } ], {} ); + * + * @example + * //returns + * // [ + * // 1, + * // [ + * // 2, + * // 3, + * // 4' + * // ], + * // 5 + * // ] + * _.entity.exportStringFromArray( [ 1, [ 2, 3, 4 ], 5 ], { levels : 2, multiline : 1 } ); + * + * @function _exportStringFromArray + * @throws { Exception } If( src ) is undefined. + * @throws { Exception } If no arguments provided. + * @throws { Exception } If( o ) is not a Object. + * @namespace Tools + * @module Tools/base/Stringer + * + */ + +function _exportStringFromArray( src, o ) +{ + var result = ''; + + _.assert( arguments.length === 2 ); + _.assert( src && _.numberIs( src.length ) ); + _.assert( _.object.isBasic( o ) || o === undefined, 'Expects map {-o-}' ); + + + if( o.level >= o.levels ) + { + return { text : _.entity._exportStringShortAct( src, o ), simple : 1 }; + } + + /* item options */ + + var optionsItem = _.props.extend( null, o ); + optionsItem.tab = o.tab + o.dtab; + optionsItem.level = o.level + 1; + optionsItem.prependTab = 0; + + /* empty case */ + + if( src.length === 0 ) + { + if( !o.wrap ) + return { text : '', simple : 1 }; + return { text : '[]', simple : 1 }; + } + + /* filter */ + + src = _.entity._exportStringFromArrayFiltered( src, o ); + + /* is simple */ + + var length = src.length; + var simple = !optionsItem.multiline; + if( simple ) + simple = length < 8; + if( simple ) + for( var i = 0 ; i < length ; i++ ) + { + simple = _.entity._exportStringIsSimpleElement( src[ i ], optionsItem );; + if( !simple ) + break; + } + + /* */ + + result += _.entity._exportStringFromContainer + ({ + values : src, + optionsContainer : o, + optionsItem, + simple, + prefix : '[', + postfix : ']', + }); + + return { text : result, simple }; +} + +// + +/** + * Builds string representation of container structure using options from + * argument( o ). Takes keys from option( o.names ) and values from option( o.values ). + * Wraps array-like and object-like entities using ( o.prefix ) and ( o.postfix ). + * + * @param {object} o - Contains data and options. + * @param {object} [ o.values ] - Source object that contains values. + * @param {array} [ o.names ] - Source object keys. + * @param {string} [ o.prefix ] - Denotes begin of container. + * @param {string} [ o.postfix ] - Denotes end of container. + * @param {Object} o.optionsContainer - Options for container {@link module:Tools/base/Stringer.Tools.Stringer.exportStringOptions}. + * @param {Object} o.optionsItem - Options for item {@link module:Tools/base/Stringer.Tools.Stringer.exportStringOptions}. + * @returns {String} Returns string representation of container. + * + * @function _exportStringFromContainer + * @throws { Exception } If no argument provided. + * @throws { Exception } If( o ) is not a Object. + * @namespace Tools + * @module Tools/base/Stringer + * + */ + +function _exportStringFromContainer( o ) +{ + var result = ''; + + _.assert( arguments.length > 0 ); + _.assert( _.object.isBasic( o ) || o === undefined, 'Expects map {-o-}' ); + _.assert( _.arrayIs( o.names ) || !o.names ); + + var values = o.values; + var names = o.names; + var optionsContainer = o.optionsContainer; + var optionsItem = o.optionsItem; + + var length = ( names ? names.length : values.length ); + var simple = o.simple; + var prefix = o.prefix; + var postfix = o.postfix; + var limit = optionsContainer.limitElementsNumber; + var l = length; + + if( o.keyWrapper === undefined ) + o.keyWrapper = ''; + + if( limit > 0 && limit < l ) + { + l = limit; + optionsContainer.limitElementsNumber = 0; + } + + /* line postfix */ + + var linePostfix = ''; + if( optionsContainer.comma ) + linePostfix += optionsContainer.comma; + + if( !simple ) + { + linePostfix += '\n' + optionsItem.tab; + } + + /* prepend */ + + if( optionsContainer.prependTab ) + { + result += optionsContainer.tab; + } + + /* wrap */ + + if( optionsContainer.wrap ) + { + result += prefix; + if( simple ) + { + if( l ) + result += ' '; + } + else + { + result += '\n' + optionsItem.tab; + } + } + else if( !simple ) + { + /*result += '\n' + optionsItem.tab;*/ + } + + /* keyWrapper */ + + if( optionsContainer.json ) + { + optionsContainer.keyWrapper = '"'; + } + + /* exec */ + + var r; + var written = 0; + for( var n = 0 ; n < l ; n++ ) + { + + _.assert( optionsItem.tab === optionsContainer.tab + optionsContainer.dtab ); + _.assert( optionsItem.level === optionsContainer.level + 1 ); + + if( names ) + r = _.entity._exportString( values[ names[ n ] ], optionsItem ); + else + r = _.entity._exportString( values[ n ], optionsItem ); + + _.assert( _.object.isBasic( r ) && _.strIs( r.text ) ); + _.assert( optionsItem.tab === optionsContainer.tab + optionsContainer.dtab ); + + if( written > 0 ) + { + result += linePostfix; + } + else if( !optionsContainer.wrap ) + if( !names || !simple ) + //if( !simple ) + { + result += optionsItem.dtab; + } + + if( names ) + { + if( o.keyWrapper === undefined ) + debugger; + let name = _.strEscape({ src : names[ n ], stringWrapper : o.keyWrapper }); + if( optionsContainer.keyWrapper ) + result += optionsContainer.keyWrapper + name + optionsContainer.keyWrapper + optionsContainer.colon; + else + result += name + optionsContainer.colon; + + if( !r.simple ) + result += '\n' + optionsItem.tab; + } + + if( r.text ) + { + result += r.text; + written += 1; + } + + } + + /* other */ + + // if( names && l < names.length ) + // result += other( names.length ); + // else if( l < names.length ) + // result += other( names.length ); + + /* wrap */ + + if( length - l > 0 ) + result += other( length ); + + if( optionsContainer.wrap ) + { + if( simple ) + { + if( l ) + result += ' '; + } + else + { + result += '\n' + optionsContainer.tab; + } + result += postfix; + } + + return result; + + function other( length ) + { + return linePostfix + '[ ... other '+ ( length - l ) +' element(s) ]'; + } + +} + +// + +function _exportStringFromObjectKeysFiltered( src, o ) +{ + var result = ''; + + _.assert( arguments.length === 2 ); + + /* item options */ + + var optionsItem = _.props.extend( null, o ); + optionsItem.noObject = o.noSubObject ? 1 : optionsItem.noObject; + + /* get keys */ + + var keys = _.props._keys + ({ + srcMap : src, + onlyOwn : o.onlyOwn, + onlyEnumerable : o.onlyEnumerable || o.onlyEnumerable === undefined || o.onlyEnumerable === null || false, + }); + + /* filter */ + + for( var n = 0 ; n < keys.length ; n++ ) + { + if( !_.entity._exportStringIsVisibleElement( src[ keys[ n ] ], optionsItem ) ) + { + keys.splice( n, 1 ); + n -= 1; + } + } + + return keys; +} + +// + +/** + * Converts object provided by argument( src ) into string representation using options provided by argument( o ). + * + * @param {object} src - Object to convert. + * @param {Object} o - Contains conversion options {@link module:Tools/base/Stringer.Tools.Stringer.exportStringOptions}. + * @returns {String} Returns string representation of object. + * + * @example + * //returns + * // { + * // r : 9, + * // t : { a : 10 }, + * // y : 11 + * // } + * _.entity.exportStringFromObject( { r : 9, t : { a : 10 }, y : 11 }, { levels : 2 } ); + * + * @example + * //returns '' + * _.entity.exportStringFromObject( { h : { d : 1 }, g : 'c', c : [2] }, { levels : 2, noObject : 1 } ); + * + * @function _exportStringFromObject + * @throws { Exception } If( src ) is not a object-like. + * @throws { Exception } If not all arguments provided. + * @throws { Exception } If( o ) is not a Object. + * @namespace Tools + * @module Tools/base/Stringer + * +*/ + +function _exportStringFromObject( src, o ) +{ + var result = ''; + + _.assert( arguments.length === 2 ); + _.assert( _.objectLike( src ) || _.entity.strTypeSecondary( src ) === 'Error' ); + _.assert( _.object.isBasic( o ) || o === undefined, 'Expects map {-o-}' ); + + + if( o.level >= o.levels ) + { + return { text : _.entity._exportStringShortAct( src, o ), simple : 1 }; + } + + if( o.noObject ) + return; + + /* item options */ + + var optionsItem = _.props.extend( null, o ); + optionsItem.noObject = o.noSubObject ? 1 : optionsItem.noObject; + optionsItem.tab = o.tab + o.dtab; + optionsItem.level = o.level + 1; + optionsItem.prependTab = 0; + + /* get names */ + + var keys = _.entity._exportStringFromObjectKeysFiltered( src, o ); + + /* empty case */ + + var length = keys.length; + if( length === 0 ) + { + if( !o.wrap ) + return { text : '', simple : 1 }; + return { text : '{}', simple : 1 }; + } + + /* is simple */ + + var simple = !optionsItem.multiline; + if( simple ) + simple = length < 4; + if( simple ) + for( var k in src ) + { + simple = _.entity._exportStringIsSimpleElement( src[ k ], optionsItem ); + if( !simple ) + break; + } + + /* */ + + result += _.entity._exportStringFromContainer + ({ + values : src, + names : keys, + optionsContainer : o, + optionsItem, + simple, + prefix : '{', + postfix : '}', + keyWrapper : o.keyWrapper, + stringWrapper : o.stringWrapper, + }); + + return { text : result, simple }; +} + +// -- +// declare +// -- + +let EntityExtension = +{ + + exportString, + exportStringFine, + exportStringMethods, + exportStringFields, + // exportStringDiagnosticShallow, + exportStringNice, + exportStringSolo, + exportJson, + exportJs, + + _exportStringFine_functor, + + _exportString, + _exportStringShortAct, + + _exportStringIsVisibleElement, + _exportStringIsSimpleElement, + + _exportStringFromRoutine, + _exportStringFromNumber, + _exportStringFromBigInt, + _exportStringFromSymbol, + _exportStringFromStr, + + _exportStringFromHashMap, + _exportStringFromSet, + + _exportStringFromBufferRaw, + _exportStringFromBufferNode, + _exportStringFromBufferTyped, + + _exportStringFromArrayFiltered, + _exportStringFromArray, + + _exportStringFromContainer, + + _exportStringFromObjectKeysFiltered, + _exportStringFromObject, + + Stringer : 1, +} + +/* _.props.extend */Object.assign( _.entity, EntityExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wstringer/proto/wtools/abase/l3/Stringer.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wstringer/proto/wtools/abase/l3' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Stringer_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Stringer_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wstringsextra/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wstringsextra/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wstringsextra */ ( function wstringsextra() { function wstringsextra_naked() { +module.exports = require( '../wtools/abase/l5/StringTools.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wStringsExtra', 'wstringsextra' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wstringsextra/proto/node_modules/wstringsextra' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wstringsextra/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wstringsextra_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wstringsextra */ })(); + +/* */ /* begin of file Dissector_s */ ( function Dissector_s() { function Dissector_s_naked() { (function _Dissector_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../node_modules/Tools' ); + _.include( 'wArraySorted' ); + _.include( 'wArraySparse' ); + _.include( 'wBlueprint' ); +} + +// + +const _ = _global_.wTools; +const Self = _.dissector = _.dissector || Object.create( null ); + +// -- +// dissector +// -- + +function dissectionIs( src ) +{ + if( !_.object.isBasic( src ) ) + return false; + if( !_.object.isBasic( src.dissector ) || !_.arrayIs( src.parcels ) ) + return false; + return true; +} + +// + +function dissectorIs( src ) +{ + if( !_.object.isBasic( src ) ) + return false; + if( !_.strIs( src.code ) || !_.routineIs( src.parse ) ) + return false; + return true; +} + +// + +function _codeLex_head( routine, args ) +{ + + let o = args[ 0 ] + if( !_.mapIs( o ) ) + { + o = + { + code : args[ 0 ], + } + } + + _.assert( args.length === 1 ); + _.assert( arguments.length === 2 ); + _.routine.options_( routine, o ); + + return o; +} + +function _codeLex_body( o ) +{ + + let op = Object.create( null ); + let delimeter = [ '\\\\', '\\<', '\\>', '<', '>', ' ', '**', '*' ]; + + op.splits = _.strSplit + ({ + src : o.code, + delimeter, + stripping : 0, + preservingDelimeters : 1, + preservingEmpty : 0, + }); + + _.strSplitsQuotedRejoin.body + ({ + splits : op.splits, + delimeter, + quoting : 1, + quotingPrefixes : [ '<' ], + quotingPostfixes : [ '>' ], + preservingQuoting : 0, + inliningQuoting : 0, + onQuoting, + }); + + tstepsWrap(); + + priorityRejoin(); + + prioritize( op.splits ); + + reprioritize( op.splits ); + + return op.splits; + + /* - */ + + function tstepsWrap() + { + let orphan; + let left = 0; + for( let i = 0 ; i < op.splits.length ; i++ ) + { + let split = op.splits[ i ]; + if( !_.strIs( split ) ) + { + let tstep = split; + _.assert( tstep.charInterval === undefined ); + if( orphan !== undefined ) + { + tstep.raw = orphan + tstep.raw; + orphan = undefined; + } + tstep.charInterval = [ left, left + tstep.raw.length - 1 ]; + left += tstep.raw.length; + continue; + } + let stripped = split.trim(); + if( stripped === '' ) + { + op.splits.splice( i, 1 ); + i -= 1; + if( i >= 0 ) + { + let tstep = op.splits[ i ]; + tstep.raw = tstep.raw + stripped; + tstep.charInterval[ 1 ] = tstep.charInterval[ 0 ] + tstep.raw.length; + } + else + { + orphan = split + } + continue; + } + let tstep = Object.create( null ); + tstep.type = 'etc'; + tstep.raw = split; + if( orphan !== undefined ) + { + tstep.raw = orphan + tstep.raw; + orphan = undefined; + } + tstep.val = stripped; + tstep.charInterval = [ left, left + tstep.raw.length - 1 ]; + left += tstep.raw.length; + op.splits[ i ] = tstep; + } + } + + function priorityRejoin() + { + + for( let i = 0 ; i < op.splits.length ; i++ ) + { + let split = op.splits[ i ]; + _.assert( _.mapIs( split ) ); + if( !/^\s*\^+\s*$/.test( split.val ) ) + continue; + let nsplit = op.splits[ i + 1 ]; + _.assert( !!nsplit && nsplit.val === '**', `Cant tokenize template. Priority ${split.val} should be followed by **` ); + nsplit.val = split.val + nsplit.val; + nsplit.raw = split.raw + nsplit.raw; + nsplit.charInterval[ 0 ] = split.charInterval[ 0 ]; + op.splits.splice( i, 1 ); + } + + } + + function prioritize( splits ) + { + for( let s = 0 ; s < splits.length ; s++ ) + { + let split = splits[ s ]; + _.assert( !_.strIs( split ) ); + if( split.type === 'text' ) + continue; + _.assert( split.type === 'etc' ); + let parsed = /(\^*)\s*(\*\*)/.exec( split.val ); + if( !parsed ) + continue; + let tstep = split; + tstep.type = 'any'; + tstep.val = parsed[ 1 ] + parsed[ 2 ]; + tstep.map = Object.create( null ); + tstep.map.priority = parsed[ 1 ]; + tstep.map.any = parsed[ 2 ]; + tstep.priority = -parsed[ 1 ].length; + splits[ s ] = tstep; + } + } + + function reprioritize( splits ) + { + + let min = +Infinity; + let max = -Infinity; + let indexToPriority = Object.create( null ); + let priorities = []; + + for( let s = 0 ; s < splits.length ; s++ ) + { + let split = splits[ s ]; + if( _.strIs( split ) ) + continue; + if( split.priority !== undefined ) + { + if( min > split.priority ) + min = split.priority; + if( max < split.priority ) + max = split.priority; + indexToPriority[ s ] = split.priority; + sortedAdd( priorities, { priority : split.priority, index : s } ); + } + } + + let effectivePriority = 0; + for( let p = priorities.length-1 ; p >= 0 ; p-- ) + { + let current = priorities[ p ]; + splits[ current.index ].priority = effectivePriority; + effectivePriority -= 1; + _.assert( -_.dissector._maxPriority <= effectivePriority && effectivePriority <= _.dissector._maxPriority ); + if( Config.debug ) + { + if( p < priorities.length-1 && priorities[ p+1 ].priority === priorities[ p ].priority ) + _.assert( priorities[ p+1 ].index < priorities[ p ].index ); + } + } + + } + + function sortedAdd( array, ins ) + { + return _.sorted.addLeft( array, ins, ( e ) => e.priority ); + } + + function onQuoting( e, op ) + { + let tstep = Object.create( null ); + tstep.type = 'text'; + tstep.raw = e; + tstep.val = _.dissector.unescape( e ); + return tstep; + } +} + +_codeLex_body.defaults = +{ + code : null +} + +let _codeLex = _.routine.uniteCloning_replaceByUnite( _codeLex_head, _codeLex_body ); + +// + +function unescape( src ) +{ + let map = + { + '\\<' : '<', + '\\>' : '>', + '\\\\' : '\\', + } + return _.strReplaceAll( src, map ); +} + +// + +function escape( src ) +{ + let map = + { + '<' : '\\<', + '>' : '\\>', + '\\' : '\\\\', + } + return _.strReplaceAll( src, map ); +} + + +// + +function make_head( routine, args ) +{ + + let o = args[ 0 ] + if( !_.mapIs( o ) ) + { + o = + { + code : args[ 0 ], + } + } + + _.assert( args.length === 1 ); + _.assert( arguments.length === 2 ); + _.routine.options_( routine, o ); + + return o; +} + +function make_body( o ) +{ + + let dissector = Object.create( null ); + dissector.code = o.code; + dissector.tokenSteps = _.dissector._codeLex.body( o ); + dissector.eatMap = eatMapGenerate(); + dissector.parcelSteps = stepsGenerate(); + dissector.parse = parse; + + /* token steps interval */ + let tokenInterval = [ 0, dissector.tokenSteps.length - 1 ] + + /* input text interval */ + let textInterval = []; + + /* markers */ + let pmarker = 0; + let tmarker = 0; + + /* etc */ + let pstep, direct, text; + + return dissector; + + /* - */ + + function parse( _text ) + { + let result = Object.create( null ); + result.dissector = dissector; + result.parcels = []; + result.tokens = []; + result.map = Object.create( null ); + result.matched = null; + + text = _text; + textInterval[ 0 ] = 0; + textInterval[ 1 ] = text.length-1; + + _.assert( arguments.length === 1 ); + _.assert( _.strIs( _text ) ); + + parseStatic( result ); + + if( result.matched === null ) + { + result.matched = tokenInterval[ 0 ] > tokenInterval[ 1 ]; + _.assert( !result.matched || textInterval[ 0 ] > textInterval[ 1 ] ); + } + + return result; + } + + /* */ + + function parseStatic( result ) + { + + for( let i = 0 ; i < dissector.parcelSteps.length ; i++ ) + { + pstep = dissector.parcelSteps[ i ]; + direct = pstep.side === 'left'; + + let parcel = pstep.eat(); + + if( !parcel ) + { + result.matched = false; + return result; + } + + parcelNormalize( parcel ); + move( result, parcel ); + } + + } + + /* */ + + function move( result, parcel ) + { + if( direct ) + { + result.parcels.splice( pmarker, 0, parcel ); + pmarker += 1; + result.tokens.splice( tmarker, 0, ... parcel.tokens ); + tmarker += parcel.tokens.length; + tokenInterval[ 0 ] += pstep.tokenSteps.length; + textInterval[ 0 ] = parcel.interval[ 1 ] + 1; + } + else + { + result.parcels.splice( pmarker, 0, parcel ); + result.tokens.splice( tmarker, 0, ... [ ... parcel.tokens ].reverse() ); + tokenInterval[ 1 ] -= pstep.tokenSteps.length; + textInterval[ 1 ] = parcel.interval[ 0 ] - 1; + } + } + + /* */ + + function parcelNormalize( parcel ) + { + if( parcel.tokens === undefined ) + { + parcel.tokens = [ parcel ]; + } + if( parcel.pstep === undefined ) + parcel.pstep = pstep; + if( parcel.tstep === undefined ) + { + _.assert( !!pstep.tokenSteps ); + _.assert( pstep.tokenSteps.length === 1 ); + parcel.tstep = pstep.tokenSteps[ 0 ]; + } + _.assert( _.cinterval.is( parcel.interval ) ); + _.assert( _.mapIs( parcel.map ) ); + } + + /* */ + + function eatFirstLeft() + { + // let left = _.strLeft( text, pstep.map.first.val, [ textInterval[ 0 ], textInterval[ 1 ] + 1 ] ); + let left = _.strLeft_( text, pstep.map.first.val, textInterval.slice() ); /* xxx */ + if( left.entry === undefined ) + return; + + let any = Object.create( null ); + any.interval = [ textInterval[ 0 ], left.index-1 ]; + any.val = text.slice( textInterval[ 0 ], left.index ); + any.tstep = pstep.map.any; + any.pstep = null; + + let first = Object.create( null ); + first.interval = [ left.index, left.index+pstep.map.first.val.length-1 ]; + first.val = pstep.map.first.val; + first.tstep = pstep.map.first; + first.pstep = null; + + let parcel = Object.create( null ); + parcel.interval ; [ textInterval[ 0 ], left.index+pstep.map.first.val.length-1 ]; + parcel.val = text.slice( textInterval[ 0 ], left.index+pstep.map.first.val.length ); + parcel.tokens = [ any, first ]; + parcel.interval = [ textInterval[ 0 ], left.index+pstep.map.first.val.length-1 ]; + parcel.tstep = null; + parcel.pstep = pstep; + parcel.map = + { + any, + first, + } + + return parcel; + } + + /* */ + + function eatFirstRight() + { + // let right = _.strRight( text, pstep.map.first.val, [ textInterval[ 0 ], textInterval[ 1 ] + 1 ] ); + let right = _.strRight_( text, pstep.map.first.val, textInterval.slice() ); /* xxx */ + if( right.entry === undefined ) + return; + + let any = Object.create( null ); + any.interval = [ right.index+pstep.map.first.val.length, textInterval[ 1 ] ]; + any.val = text.slice( right.index+pstep.map.first.val.length, textInterval[ 1 ] + 1 ); + any.tstep = pstep.map.any; + any.pstep = null; + + let first = Object.create( null ); + first.interval = [ right.index, right.index+pstep.map.first.val.length-1 ]; + first.val = pstep.map.first.val; + first.tstep = pstep.map.first; + first.pstep = null; + + let parcel = Object.create( null ); + parcel.interval = [ right.index, textInterval[ 1 ] ]; + parcel.val = text.slice( right.index, textInterval[ 1 ] + 1 ); + parcel.tokens = [ any, first ]; + parcel.interval = [ right.index, textInterval[ 1 ] ]; + parcel.tstep = null; + parcel.pstep = pstep; + parcel.map = + { + any, + first, + } + + return parcel; + } + + /* */ + + function eatRestLeft() + { + let parcel = + { + interval : [ textInterval[ 0 ], textInterval[ 1 ] ], + val : text.slice( textInterval[ 0 ], textInterval[ 1 ] + 1 ), + map : Object.create( null ), + }; + return parcel; + } + + /* */ + + function eatRestRight() + { + let parcel = + { + interval : [ textInterval[ 0 ], textInterval[ 1 ] ], + val : text.slice( textInterval[ 0 ], textInterval[ 1 ] + 1 ), + map : Object.create( null ), + }; + return parcel; + } + + /* */ + + function eatLeastLeft() + { + let parcel = + { + interval : [ textInterval[ 0 ], textInterval[ 0 ]-1 ], + val : '', + map : Object.create( null ), + }; + return parcel; + } + + /* */ + + function eatLeastRight() + { + let parcel = + { + interval : [ textInterval[ 1 ] + 1, textInterval[ 1 ] ], + val : '', + map : Object.create( null ), + }; + return parcel; + } + + /* */ + + function eatTextLeft() + { + let match = pstep.val === text.slice( textInterval[ 0 ], textInterval[ 0 ] + pstep.val.length ); + if( !match ) + return; + let parcel = + { + interval : [ textInterval[ 0 ], textInterval[ 0 ] + pstep.val.length - 1 ], + val : pstep.val, + map : Object.create( null ), + }; + return parcel; + } + + /* */ + + function eatTextRight() + { + let match = pstep.val === text.slice( textInterval[ 1 ] - pstep.val.length + 1, textInterval[ 1 ] + 1 ); + if( !match ) + return; + let parcel = + { + interval : [ textInterval[ 1 ] - pstep.val.length + 1, textInterval[ 1 ] ], + val : pstep.val, + map : Object.create( null ), + }; + return parcel; + } + + /* */ + + function eatMapGenerate() + { + let eatMap = Object.create( null ); + eatMap.restLeft = eatRestLeft; + eatMap.restRight = eatRestRight; + eatMap.firstLeft = eatFirstLeft; + eatMap.firstRight = eatFirstRight; + eatMap.leastLeft = eatLeastLeft; + eatMap.leastRight = eatLeastRight; + eatMap.textLeft = eatTextLeft; + eatMap.textRight = eatTextRight; + return eatMap; + } + + /* */ + + function stepsGenerate() + { + let parcelSteps = []; + + let op = Object.create( null ); + op.dissector = dissector; + op.tinterval = [ 0, dissector.tokenSteps.length-1 ]; + + let leftPstep = null; + let rightPstep = null; + + while( op.tinterval[ 0 ] <= op.tinterval[ 1 ] ) + { + + if( leftPstep === null ) + { + op.tindex = op.tinterval[ 0 ]; + op.tindex2 = op.tindex + 1; + op.direct = true; + leftPstep = _.dissector._stepGenerate( op ); + } + + if( rightPstep === null ) + { + op.tindex = op.tinterval[ 1 ]; + op.tindex2 = op.tindex - 1; + op.direct = false; + rightPstep = _.dissector._stepGenerate( op ); + } + + let direct = leftPstep.priority >= rightPstep.priority; + let pstep = direct ? leftPstep : rightPstep; + + if( Config.debug ) + { + _.assert + ( + _.cinterval.has( op.tinterval, pstep.tinterval ) + , `Current pstep is ${_.dissector._stepExportToStringShort( pstep )}` + , `\nPstep has token interval ${pstep.tinterval[ 0 ]} .. ${pstep.tinterval[ 1 ]}.` + , `\nBut current token interval is ${op.tinterval[ 0 ]} .. ${op.tinterval[ 1 ]}` + ); + } + + parcelSteps.push( pstep ); + pstep.index = parcelSteps.length; + + if( direct ) + { + op.tinterval[ 0 ] += pstep.tokenSteps.length; + leftPstep = null; + if( !_.cinterval.has( op.tinterval, rightPstep.sensetiveInterval ) ) + rightPstep = null; + } + else + { + op.tinterval[ 1 ] -= pstep.tokenSteps.length; + rightPstep = null; + if( !_.cinterval.has( op.tinterval, leftPstep.sensetiveInterval ) ) + leftPstep = null; + } + + } + + return parcelSteps; + } + + /* */ + +} + +make_body.defaults = +{ + code : null +} + +let make = _.routine.uniteCloning_replaceByUnite( make_head, make_body ); + +// + +function _stepGenerate( op ) +{ + let pstep; + + op.tstep = op.dissector.tokenSteps[ op.tindex ]; + if( _.cinterval.has( op.tinterval, op.tindex2 ) ) + op.tstep2 = op.dissector.tokenSteps[ op.tindex2 ]; + else + op.tstep2 = undefined; + + _.assert + ( + _.object.isBasic( op.tstep ) && _.longHas( [ 'any', 'text' ], op.tstep.type ), + `Unknown type of token of the shape ${op.dissector.code}` + ); + + if( op.tstep.type === 'any' ) + { + pstep = Object.create( null ); + pstep.map = Object.create( null ); + pstep.map.any = op.tstep; + pstep.priority = op.tstep.priority; + if( op.tstep2 === undefined ) + { + pstep.type = 'rest'; + pstep.priority = _.dissector._maxPriority + 10; + pstep.tokenSteps = [ op.tstep ]; + pstep.sensetiveInterval = [ 0, 0 ]; + } + else if( op.tstep2.type === 'text' ) + { + pstep.type = 'first'; + pstep.map.first = op.tstep2; + pstep.tokenSteps = [ op.tstep, op.tstep2 ]; + pstep.sensetiveInterval = [ 0, 1 ]; + } + else if( op.tstep2.type === 'any' ) + { + pstep.type = 'least'; + pstep.map.least = op.tstep2; + pstep.tokenSteps = [ op.tstep ]; + pstep.sensetiveInterval = [ 0, 1 ]; + } + else _.assert( 0, `Unknown type of token step : ${op.tstep2.type}` ); + } + else if( op.tstep.type === 'text' ) + { + pstep = Object.create( null ); + pstep.tokenSteps = [ op.tstep ]; + pstep.type = op.tstep.type; + pstep.val = op.tstep.val; + pstep.priority = _.dissector._maxPriority + 20; + pstep.sensetiveInterval = [ 0, 0 ]; + _.assert( op.tstep.side === undefined ); + _.assert( op.tstep.priority === undefined ); + } + else _.assert( 0 ); + + if( pstep.side === undefined ) + pstep.side = ( op.direct ? 'left' : 'right' ); + _.assert( _.longHas( [ 'left', 'right' ], pstep.side ) ); + + _.assert( pstep.eat === undefined ); + let rname = pstep.type + ( op.direct ? 'Left' : 'Right' ); + pstep.eat = op.dissector.eatMap[ rname ]; + _.assert( _.routineIs( pstep.eat ), `No such eater ${rname}` ); + + _.assert( pstep.tinterval === undefined ); + + if( op.direct ) + { + pstep.tinterval = [ op.tindex, op.tindex + pstep.tokenSteps.length - 1 ]; + pstep.sensetiveInterval[ 0 ] += op.tindex; + pstep.sensetiveInterval[ 1 ] += op.tindex; + } + else + { + pstep.tinterval = [ op.tindex - pstep.tokenSteps.length + 1, op.tindex ]; + pstep.sensetiveInterval[ 0 ] = op.tindex - pstep.sensetiveInterval[ 1 ]; + pstep.sensetiveInterval[ 1 ] = op.tindex; + } + + _.assert( _.numberIs( pstep.priority ) ); + _.assert( _.arrayIs( pstep.tokenSteps ) ); + + return pstep; +} + +_stepGenerate.defaults = +{ + dissector : null, + direct : null, + tindex2 : null, + tindex : null, +} + +// + +function dissect_head( routine, args ) +{ + + let o = args[ 0 ] + if( !_.mapIs( o ) ) + { + o = + { + code : args[ 0 ], + text : ( args.length > 1 ? args[ 1 ] : null ), + } + } + + _.assert( args.length === 1 || args.length === 2 ); + _.assert( arguments.length === 2 ); + _.routine.options_( routine, o ); + + return o; +} + +function dissect_body( o ) +{ + let dissector = _.dissector.make.body( o ); + return dissector.parse( o.text ); +} + +dissect_body.defaults = +{ + text : null, + code : null, +} + +let dissect = _.routine.uniteCloning_replaceByUnite( dissect_head, dissect_body ); + +// + +function _tstepExportToString( tstep ) +{ + + if( tstep.type === 'any' ) + { + _.assert( tstep.priority <= 0 ); + return _.strDup( '^', -tstep.priority ) + tstep.map.any; + } + else if( tstep.type === 'text' ) + { + _.assert( tstep.priority === 0 || tstep.priority === undefined ); + return `<${tstep.val}>`; + } + else _.assert( 0 ); + +} + +// + +function dissectorExportToString( dissector ) +{ + let result = ''; + + _.assert( _.dissector.dissectorIs( dissector ) ); + + dissector.tokenSteps.forEach( ( tstep ) => + { + result += _.dissector._tstepExportToString( tstep ); + }); + + return result; +} + +// + +function _stepExportToStringShort( step ) +{ + return `${step.type}.${step.side}#${step.index}`; +} + +// + +function dissectionExportToString( o ) +{ + let result = ''; + + _.routine.options_( dissectionExportToString, arguments ); + _.assert( _.dissector.dissectionIs( o.src ) ); + _.assert( _.longHas( [ 'track' ], o.mode ) ); + + if( o.mode === 'track' ) + { + o.src.parcels.forEach( ( parcel ) => + { + let s = _.dissector._stepExportToStringShort( parcel.pstep ); + if( result.length ) + result += ` ${s}`; + else + result += `${s}`; + }); + return result; + } + else _.assert( 0 ); + +} + +dissectionExportToString.defaults = +{ + src : null, + mode : 'track', +} + +// + +/* zzz : imlement parsing with template routine _.dissector.dissect() + + b ^** ':' ** e + b ^** ':' ^** ':' ** e + b ^*+ s+ ^^*+ ':' *+ e + b ( ^*+ )^ <&( s+ )&> ( ^^*+ ':' *+ )^ e + +b subject:^** s+ map:** e +// 'c:/dir1 debug:0' -> subject : 'c:/dir1', debug:0 + +// test.identical( _.strCount( op.output, /program.end(.|\n|\r)*timeout1/mg ), 1 ); +test.identical( _.strCount( op.output, `'program.end'**'timeout1'` ), 1 ); + +*/ + +// -- +// declare +// -- + +let DissectorExtension = +{ + + dissectionIs, + dissectorIs, + is : dissectorIs, + + _codeLex, + unescape, + escape, + + make, + _stepGenerate, + dissect, + + _tstepExportToString, + dissectorExportToString, + _stepExportToStringShort, + dissectionExportToString, + + _maxPriority : 1 << 20, + +} + +/* _.props.extend */Object.assign( _.dissector, DissectorExtension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wstringsextra/proto/wtools/abase/l5/Dissector.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wstringsextra/proto/wtools/abase/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Dissector_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Dissector_s */ })(); + +/* */ /* begin of file StringTools_s */ ( function StringTools_s() { function StringTools_s_naked() { (function _StringTools_s_() +{ + +'use strict'; + +/** + * Collection of sophisticated routines for operations on Strings. StringsToolsExtra leverages analyzing, parsing and formatting of String for special purposes. + @module Tools/base/l5/StringTools + @extends Tools +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../node_modules/Tools' ); + _.include( 'wArraySorted' ); + _.include( 'wArraySparse' ); + _.include( 'wBlueprint' ); +} + +/** + * Collection of sophisticated routines for operations on Strings. + @namespace Tools.StringTools + @module Tools/base/l5/StringTools + @augments wTools +*/ + +// + +const Self = _global_.wTools; +const _ = _global_.wTools; + +const _ArraySlice = Array.prototype.slice; +const _FunctionBind = Function.prototype.bind; +const _ObjectToString = Object.prototype.toString; +const _ObjectHasOwnProperty = Object.hasOwnProperty; + +const _longSlice = _.longSlice; +const strType = _.entity.strType; + +_.assert( _.routineIs( _.sorted.addOnce ) ); + +// -- +// +// -- + +// function strDecamelize( o ) +// { +// +// +// } +// +// strDecamelize.defaults = +// { +// src : null, +// } + +// + +/** + * Converts string to camelcase using special pattern. + * If function finds character from this( '.','-','_','/' ) list before letter, + * it replaces letter with uppercase version. + * For example: '.an _example' or '/an -example', method converts string to( 'An Example' ). * + * + * @param {string} srcStr - Source string. + * @returns {string} Returns camelcase version of string. + * + * @example + * //returns aBCD + * _.strCamelize( 'a-b_c/d' ); + * + * @example + * //returns testString + * _.strCamelize( 'test-string' ); + * + * @function strCamelize + * @throws { Exception } Throws a exception if( srcStr ) is not a String. + * @throws { Exception } Throws a exception if no argument provided. + * @namespace Tools + * @module Tools/base/l5/StringTools + * + */ + +function strCamelize( srcStr ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( srcStr ) ); + + let result = srcStr; + let regexp = /\.\w|-\w|_\w|\/\w/g; + + result = result.replace( regexp, function( match ) + { + return match[ 1 ].toUpperCase(); + }); + + return result; +} + +// + +let _strToTitleRegexp1 = /(?<=\s|^)(?:_|\.)+|(?:_|\.)+(?=\s|$)|^\w(?=[A-Z])/g; +let _strToTitleRegexp2 = /(?:_|\.)+/g; +let _strToTitleRegexp3 = /(\s*[A-za-z][a-z]*)|(\s*[0-9]+)/g; +function strToTitle( srcStr ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( srcStr ) ); + + let result = srcStr; + + result = result.replace( _strToTitleRegexp1, '' ); + result = result.replace( _strToTitleRegexp2, ' ' ); + result = result.replace( _strToTitleRegexp3, function( /* match, g1, g2, offset */ ) + { + let match = arguments[ 0 ]; + let g1 = arguments[ 1 ]; + let g2 = arguments[ 2 ]; + let offset = arguments[ 3 ]; + + let g = match; + if( offset > 0 ) + g = _.strDecapitalize( g ); + if( offset > 0 && g[ 0 ] !== ' ' ) + return ' ' + g; + else + return g; + }); + + return result; +} + +// + +/** + * Removes invalid characters from filename passed as first( srcStr ) argument by replacing characters finded by + * pattern with second argument( o ) property( o.delimeter ).If( o.delimeter ) is not defined, + * function sets value to( '_' ). + * + * @param {string} srcStr - Source string. + * @param {object} o - Object that contains o. + * @returns {string} Returns string with result of replacements. + * + * @example + * //returns _example_file_name.txt + * _.strFilenameFor( "'example\\file?name.txt" ); + * + * @example + * //returns #example#file#name.js + * let o = { 'delimeter':'#' }; + * _.strFilenameFor( "'example\\file?name.js",o ); + * + * @function strFilenameFor + * @throws { Exception } Throws a exception if( srcStr ) is not a String. + * @throws { Exception } Throws a exception if( o ) is not a Map. + * @throws { Exception } Throws a exception if no arguments provided. + * @namespace Tools + * @module Tools/base/l5/StringTools + * + */ + +function strFilenameFor( o ) +{ + if( _.strIs( o ) ) + o = { srcString : o } + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( o.srcString ) ); + _.routine.options_( strFilenameFor, o ); + + let regexp = /<|>|:|"|'|\/|\\|\||\&|\?|\*|\n|\s/g; + let result = o.srcString.replace( regexp, function( match ) + { + return o.delimeter; + }); + + return result; +} + +strFilenameFor.defaults = +{ + srcString : null, + delimeter : '_', +} + +// + +/** + * Replaces invalid characters from variable name `o.src` with special character `o.delimeter`. + * + * @description + * Accepts string as single arguments. In this case executes routine with default `o.delimeter`. + * + * @param {Object} o Options map. + * @param {String} o.src Source string. + * @param {String} o.delimeter='_' Replacer string. + * + * @example + * _.strVarNameFor( 'some:var');//some_var + * + * @returns {String} Returns string with result of replacements. + * @throws { Exception } Throws a exception if( srcStr ) is not a String. + * @throws { Exception } Throws a exception if( o ) is not a Map. + * @throws { Exception } Throws a exception if no arguments provided. + * @function strVarNameFor + * @namespace Tools + * @module Tools/base/l5/StringTools + * + */ + +function strVarNameFor( o ) +{ + if( _.strIs( o ) ) + o = { src : o } + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( o.src ) ); + _.routine.options_( strVarNameFor, o ); + + let regexp = /\.|\-|\+|<|>|:|"|'|\/|\\|\||\&|\?|\*|\n|\s/g; + let result = o.src.replace( regexp, function( match ) + { + return o.delimeter; + }); + + return result; +} + +strVarNameFor.defaults = +{ + src : null, + delimeter : '_', +} + +// + +/** + * @summary Html escape symbols map. + * @enum {String} _strHtmlEscapeMap + * @module Tools/base/l5/StringTools + */ + +let _strHtmlEscapeMap = +{ + '&' : '&', + '<' : '<', + '>' : '>', + '"' : '"', + '\'' : ''', + '/' : '/' +} + +/** + * Replaces all occurrences of html escape symbols from map {@link module:Tools/base/l5/StringTools~_strHtmlEscapeMap} + * in source( str ) with their code equivalent like( '&' -> '&' ). + * Returns result of replacements as new string or original if nothing replaced. + * + * @param {string} str - Source string to parse. + * @returns {string} Returns string with result of replacements. + * + * @example + * //returns <&test &text &here> + * _.strHtmlEscape( '<&test &text &here>' ); + * + * @example + * //returns 1 < 2 + * _.strHtmlEscape( '1 < 2' ); + * + * @example + * //returns //test// + * _.strHtmlEscape( '//test//' ); + * + * @example + * //returns &,< + * _.strHtmlEscape( ['&','<'] ); + * + * @example + * //returns <div class="cls"></div> + * _.strHtmlEscape('
'); + * + * @function strHtmlEscape + * @throws { Exception } Throws a exception if no argument provided. + * @namespace Tools + * @module Tools/base/l5/StringTools + * + */ + +function strHtmlEscape( str ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + return String( str ).replace( /[&<>"'\/]/g, function( s ) + { + return _strHtmlEscapeMap[ s ]; + }); +} + +// + +function strSearch_head( routine, args ) +{ + let o = args[ 0 ]; + + if( args.length === 2 ) + o = { src : args[ 0 ], ins : args[ 1 ] } + + _.assert( arguments.length === 2 ); + _.assert( args.length === 1 || args.length === 2 ); + _.routine.options_( routine, o ); + + return o; +} + +function strSearch_body( o ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + + /* */ + + o.ins = _.array.as( o.ins ); + o.ins = _.regexpsMaybeFrom + ({ + srcStr : o.ins, + stringWithRegexp : o.stringWithRegexp, + toleratingSpaces : o.toleratingSpaces, + }); + + if( _.arrayIs( o.excludingTokens ) || _.strIs( o.excludingTokens ) ) + { + o.excludingTokens = _.path.globShortSplitsToRegexps( o.excludingTokens ); + o.excludingTokens = _.regexpsAny( o.excludingTokens ); + } + + /* */ + + o.parcels = []; + let found = _.strFindAll( o.src, o.ins ); + + found.forEach( ( it ) => splitAdjust( it ) ); + + return o; + + /* */ + + function splitAdjust( it ) + { + + // it.charsRangeLeft = it.range; /* yyy */ + it.charsRangeRight = [ o.src.length - it.charsRangeLeft[ 0 ], o.src.length - it.charsRangeLeft[ 1 ] ]; + + let first; + if( o.determiningLineNumber ) + { + first = o.src.substring( 0, it.charsRangeLeft[ 0 ] ).split( '\n' ).length; + it.linesRange = [ first, first+o.src.substring( it.charsRangeLeft[ 0 ], it.charsRangeLeft[ 1 ] ).split( '\n' ).length ]; + } + + if( o.nearestLines ) + it.nearest = _.strLinesNearest + ({ + src : o.src, + charsRangeLeft : it.charsRangeLeft, + nearestLines : o.nearestLines, + }).splits; + + if( o.determiningLineNumber ) + it.linesOffsets = [ first - _.strLinesCount( it.nearest[ 0 ] ) + 1, first, first + _.strLinesCount( it.nearest[ 1 ] ) ]; + + if( o.onTokenize ) + { + let tokens = o.onTokenize( it.nearest.join( '' ) ); + + // let ranges = _.select( tokens, '*/charsRangeLeft/0' ); /* Dmytro : new realization of Selector require quantitative number selector */ + let ranges = _.select( tokens, '*/charsRangeLeft/#0' ); + let range = [ it.nearest[ 0 ].length, it.nearest[ 0 ].length + it.nearest[ 1 ].length ]; + let having = _.sorted.lookUpIntervalHaving( ranges, range ); + + _.assert( ranges[ having[ 0 ] ] <= range[ 0 ] ); + _.assert( having[ 1 ] === ranges.length || ranges[ having[ 1 ] ] >= range[ 1 ] ); + + if( o.excludingTokens ) + { + let tokenNames = _.select( tokens, '*/tokenName' ); + tokenNames = tokenNames.slice( having[ 0 ], having[ 1 ] ); + let pass = _.none( _.regexpTest( o.excludingTokens, tokenNames ) ); + if( !pass ) + return; + } + + } + + if( !o.nearestSplitting ) + it.nearest = it.nearest.join( '' ); + + o.parcels.push( it ); + } +} + +strSearch_body.defaults = +{ + src : null, + ins : null, + nearestLines : 3, + nearestSplitting : 1, + determiningLineNumber : 0, + stringWithRegexp : 0, + toleratingSpaces : 0, + onTokenize : null, + excludingTokens : null, +} + +let strSearch = _.routine.uniteCloning_replaceByUnite( strSearch_head, strSearch_body ); + +// + +function strSearchLog_body( o ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + let o2 = _.mapOnly_( null, o, this.strSearch.defaults ); + this.strSearch( o2 ); + _.props.extend( o, o2 ); + + _.each( o.parcels, ( parcel ) => + { + parcel.log = _.strLinesNearestLog + ({ + src : o.src, + sub : o.sub, + charsRangeLeft : parcel.charsRangeLeft, + nearestLines : o.nearestLines, + nearest : parcel.nearest, + gray : o.gray, + }).log; + if( o.sub !== undefined ) + parcel.sub = o.sub; + }); + + o.log = o.parcels.map( ( parcel ) => parcel.log ).join( '\n' ); + + return o; +} + +strSearchLog_body.defaults = +{ + ... strSearch.defaults, + sub : null, /* qqq2 : cover the option */ + gray : 0, +} + +let strSearchLog = _.routine.uniteCloning_replaceByUnite( strSearch_head, strSearchLog_body ); + +// + +function strSearchReplace_body( o ) +{ + let result = ''; + let last = 0; + _.routine.options_( strSearchReplace_body, o ); + _.assert( arguments.length === 1 ); + _.assert( _.strIs( o.src ) ); + + if( _.boolLikeTrue( o.logger ) ) + o.logger = _global_.logger; + + o.log = ''; + + for( let i = 0 ; i < o.parcels.length ; i++ ) + { + let parcel = o.parcels[ i ]; + + if( o.verbosity ) + { + if( o.log ) + o.log += '\n' + parcel.log; + else + o.log += parcel.log; + if( o.logger ) + o.logger.log( parcel.log ); + } + + result += o.src.slice( last, o.src.length - parcel.charsRangeRight[ 0 ] ); + + _.sure( _.strIs( parcel.sub ), 'Expects string::parcel.sub' ); + _.sure + ( + parcel.match === undefined + || parcel.match === o.src.substring( o.src.length-parcel.charsRangeRight[ 0 ], o.src.length-parcel.charsRangeRight[ 1 ] ) + , () => `Match does not match:` + + ` - ${parcel.match}` + + ` - ${o.src.slice( parcel.charsRangeRight[ 0 ], parcel.charsRangeRight[ 1 ] )}` + ); + + last = o.src.length - parcel.charsRangeRight[ 1 ]; + result += parcel.sub; + + } + + result += o.src.slice( last, o.src.length ); + + return result; + +} + +strSearchReplace_body.defaults = +{ + src : null, + parcels : null, + logger : 0, + verbosity : 0, + // direct : 1, +} + +let strSearchReplace = _.routine.uniteCloning_replaceByUnite( strSearch_head, strSearchReplace_body ); + +// + +function strFindAll( src, ins ) +{ + let o; + + if( arguments.length === 2 ) + { + o = { src : arguments[ 0 ], ins : arguments[ 1 ] }; + } + else if( arguments.length === 1 ) + { + o = arguments[ 0 ]; + } + + if( _.strIs( o.ins ) || _.regexpIs( o.ins ) ) + o.ins = [ o.ins ]; + + /* */ + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.strIs( o.src ) ); + _.assert( _.argumentsArray.like( o.ins ) || _.object.isBasic( o.ins ) ); + _.routine.options_( strFindAll, o ); + + /* */ + + let tokensSyntax = _.tokensSyntaxFrom( o.ins ); + let descriptorsArray = []; + let execeds = []; + let closests = []; + let closestTokenId = -1; + let closestIndex = o.src.length; + let currentIndex = 0; + let descriptorFor = o.fast ? descriptorForFast : descriptorForFull; + + /* */ + + tokensSyntax.idToValue.forEach( ( ins, tokenId ) => + { + // Dmytro : not optimal - double check. qqq : ? + _.assert( _.strIs( ins ) || _.regexpIs( ins ) ); + + if( _.regexpIs( ins ) ) + _.assert( !ins.sticky ); + + let found = find( o.src, ins, tokenId ); + closests[ tokenId ] = found; + if( found < closestIndex ) + { + closestIndex = found + closestTokenId = tokenId; + } + }); + + /* */ + + while( closestIndex < o.src.length ) + { + + if( o.tokenizingUnknown && closestIndex > currentIndex ) + { + descriptorFor( o.src, currentIndex, -1 ); + } + + descriptorFor( o.src, closestIndex, closestTokenId ); + + closestIndex = o.src.length; + closests.forEach( ( index, tokenId ) => + { + if( index < currentIndex ) + index = closests[ tokenId ] = find( o.src, tokensSyntax.idToValue[ tokenId ], tokenId ); + + _.assert( closests[ tokenId ] >= currentIndex ); + + if( index < closestIndex ) + { + closestIndex = index + closestTokenId = tokenId; + } + }); + + _.assert( closestIndex <= o.src.length ); + } + + if( o.tokenizingUnknown && closestIndex > currentIndex ) + { + descriptorFor( o.src, currentIndex, -1 ); + } + + /* */ + + return descriptorsArray; + + /* */ + + function find( src, ins, tokenId ) + { + let result; + + if( _.strIs( ins ) ) + { + result = findWithString( o.src, ins, tokenId ); + } + else if( _.regexpIs( ins ) ) + { + if( ins.source === '(?:)' ) + result = src.length; + else + result = findWithRegexp( o.src, ins, tokenId ); + } + else _.assert( 0 ); + + _.assert( result >= 0 ); + return result; + } + + /* */ + + function findWithString( src, ins ) + { + + if( !ins.length ) + return src.length; + + let index = src.indexOf( ins, currentIndex ); + + if( index < 0 ) + return src.length; + + return index; + } + + /* */ + + function findWithRegexp( src, ins, tokenId ) + { + let execed; + let result = src.length; + + if( currentIndex === 0 || ins.global ) + { + + do + { + + execed = ins.exec( src ); + if( execed ) + result = execed.index; + else + result = src.length; + + } + while( result < currentIndex ); + + } + else + { + execed = ins.exec( src.substring( currentIndex ) ); + + if( execed ) + result = execed.index + currentIndex; + + } + + if( execed ) + execeds[ tokenId ] = execed; + + return result; + } + + /* */ + + function descriptorForFast( src, index, tokenId ) + { + let originalIns = tokensSyntax.idToValue[ tokenId ]; + let match; + let it = []; + + if( tokenId === -1 ) + originalIns = src.substring( index, closestIndex ); + + if( _.strIs( originalIns ) ) + { + match = originalIns; + } + else + { + let execed = execeds[ tokenId ]; + _.assert( !!execed ); + match = execed[ 0 ]; + } + + it[ 0 ] = index; + it[ 1 ] = index + match.length; + it[ 2 ] = tokenId; + + descriptorsArray.push( it ); + + _.assert( _.strIs( match ) ); + if( match.length > 0 ) + currentIndex = index + match.length; + else + currentIndex = index + 1; + + o.counter += 1; + } + + /* */ + + function descriptorForFull( src, index, tokenId ) + { + let originalIns = tokensSyntax.idToValue[ tokenId ]; + let match; + let it = Object.create( null ); + let groups; + + if( tokenId === -1 ) + originalIns = src.substring( index, closestIndex ); + + if( _.strIs( originalIns ) ) + { + match = originalIns; + groups = []; + } + else + { + let execed = execeds[ tokenId ]; + _.assert( !!execed ); + match = execed[ 0 ]; + groups = _.longSlice( execed, 1, execed.length ); + } + + it.match = match; + it.groups = groups; + it.tokenId = tokenId; + it.charsRangeLeft = [ index, index + match.length ]; /* yyy */ + it.counter = o.counter; + it.input = src; + + if( tokensSyntax.idToName && tokensSyntax.idToName[ tokenId ] ) + it.tokenName = tokensSyntax.idToName[ tokenId ]; + + descriptorsArray.push( it ); + + _.assert( _.strIs( match ) ); + if( match.length > 0 ) + currentIndex = index + match.length; + else + currentIndex = index + 1; + + o.counter += 1; + } + + /* */ + +} + +strFindAll.defaults = +{ + src : null, + ins : null, + fast : 0, + counter : 0, + tokenizingUnknown : 0, +} + +// + +let TokensSyntax = _.blueprint.defineConstructor +({ + idToValue : null, + idToName : _.define.shallow( [] ), + nameToId : _.define.shallow( {} ), + alternatives : _.define.shallow( {} ), + typed : _.trait.typed(), +}); + +// + +function tokensSyntaxFrom( ins ) +{ + + if( ins instanceof _.TokensSyntax ) + return ins + + let result = TokensSyntax(); + + if( _.strIs( ins ) || _.regexpIs( ins ) ) + ins = [ ins ]; + + /* */ + + _.assert( arguments.length === 1 ); + _.assert( _.argumentsArray.like( ins ) || _.object.isBasic( ins ) ); + + /* */ + + result.idToValue = ins; + if( _.mapIs( ins ) ) + { + result.idToValue = []; + result.idToName = []; + let i = 0; + for( var name in ins ) + { + let element = ins[ name ]; + if( _.longIs( element ) ) + { + let alternative = result.alternatives[ name ] = result.alternatives[ name ] || []; + for( let e = 0 ; e < element.length ; e++ ) + { + let name2 = name + '_' + element[ e ]; + result.idToValue[ i ] = ins[ name ][ e ]; // qqq : ? Dmytro : better to use local variable 'let element'. Also, maybe, needs check type of element - regexp or string. + result.idToName[ i ] = name2; + result.nameToId[ name2 ] = i; + alternative.push( name2 ); + i += 1; + } + } + else + { + result.idToValue[ i ] = ins[ name ]; // qqq : ? Dmytro : better to use local variable 'let element' + result.idToName[ i ] = name; + result.nameToId[ name ] = i; + i += 1; + } + } + } + + return result; +} + +// + +function _strReplaceMapPrepare( o ) +{ + + /* verify */ + + _.map.assertHasAll( o, _strReplaceMapPrepare.defaults ); + _.assert( arguments.length === 1 ); + _.assert( _.object.isBasic( o.dictionary ) || _.longIs( o.dictionary ) || o.dictionary === null ); + _.assert( ( _.longIs( o.ins ) && _.longIs( o.sub ) ) || ( o.ins === null && o.sub === null ) ); + + /* head */ + + if( o.dictionary ) + { + + o.ins = []; + o.sub = []; + + if( _.object.isBasic( o.dictionary ) ) + { + let i = 0; + for( let d in o.dictionary ) + { + o.ins[ i ] = d; + o.sub[ i ] = o.dictionary[ d ]; + i += 1; + } + } + else + { + let i = 0; + o.dictionary.forEach( ( d ) => + { + let ins = d[ 0 ]; + let sub = d[ 1 ]; + _.assert( d.length === 2 ); + // _.assert( !( _.arrayIs( ins ) ^ _.arrayIs( sub ) ) ); + // debugger; + _.assert( _.arrayIs( ins ) === _.arrayIs( sub ) ); + if( _.arrayIs( ins ) ) + { + _.assert( ins.length === sub.length ) + for( let n = 0 ; n < ins.length ; n++ ) + { + o.ins[ i ] = ins[ n ]; + o.sub[ i ] = sub[ n ]; + i += 1; + } + } + else + { + o.ins[ i ] = ins; + o.sub[ i ] = sub; + i += 1; + } + }); + } + + o.dictionary = null; + } + + /* verify */ + + _.assert( !o.dictionary ); + _.assert( o.ins.length === o.sub.length ); + + if( Config.debug ) + { + o.ins.forEach( ( ins ) => _.assert( _.strIs( ins ) || _.regexpIs( ins ) ), 'Expects String or RegExp' ); + o.sub.forEach( ( sub ) => _.assert( _.strIs( sub ) || _.routineIs( sub ) ), 'Expects String or Routine' ); + } + + return o; +} + +_strReplaceMapPrepare.defaults = +{ + dictionary : null, + ins : null, + sub : null, +} + +// + +/** + * Routine strReplaceAll() searches each occurrence of element of {-ins-} container in source string {-src-} + * and replaces it to corresponding element in {-sub-} container. + * Returns result of replacements as new string or original string if no matches found in source( src ). + * + * Routine can be called in three different ways. + * + * Three arguments: + * @param { String } src - Source string to parse. + * @param { String|RegExp|Long } ins - String or regexp pattern to search in source string. Also, it can be a + * set of string and regexp patterns passed as Long. If {-ins-} is a Long, then {-but-} should be long with the + * same length. + * @param { String|Long } but - String or a Long with strings to replace occurrences {-ins-}. If {-but-} is a + * Long, then it should contains only strings and {-ins-} should be a long with the same length. + * + * Two arguments: + * @param { String } src - Source string to parse. + * @param { Long|Map } dictionary - Long or map that contains pattern/replacement pairs. If {-dictionary-} is a + * Long, then it looks like [ [ ins1, sub1 ], [ ins2, sub2 ] ], otherwise, it is like { ins1 : sub1, ins2 : sub2 }. + * + * One argument: + * @param { ObjectLike } o - Object, which can contains options: + * @param { String } o.src - Source string to parse. + * @param { Long|Map } o.dictionary - Long or map that contains pattern/replacement pairs, transforms to {-o.ins-} + * and {-o.but-}. If {-dictionary-} is a Long, then it looks like [ [ ins1, sub1 ], [ ins2, sub2 ] ], otherwise, it + * is like { ins1 : sub1, ins2 : sub2 }. + * @param { Long } o.ins - A Long with string or regexp patterns to search in source string {-o.src-}. + * @param { Long } o.sub - String that replaces found occurrence( ins ). + * Note. If {-o.ins-} and {-o.sub-} options is used, then {-o.dictionary-} should be not provided, otherwise, + * {-o.dictionary-} values replace elements of {-o.ins-} and {-o.sub-} + * @param { BoolLike } o.joining - A parameter which control output value. If {-o.joining-} is true, then routine + * returns string, otherwise, the array with parsed parts of source string is returned. Default value is 1. + * @param { Routine } o.onUnknown - A callback, which transforms parts of source string that not found by a pattern. + * {-o.onUnknown-} accepts three parameters: {-unknown-} - part of string, {-it-} - data structure with information + * about found pattern in format of routine strFindAll(), {-o-} - the map options. + * Option {-o.onUnknown-} does not transforms part of source string after last entry of a {-o.ins-} pattern. + * + * @example + * _.strReplaceAll( 'abcdef', 'b', 'w' ); + * //returns 'awcdef' + * + * @example + * _.strReplaceAll( 'abcdef', [ 'b', /d/g, 'f' ], [ 'w', 'x', 'y' ] ); + * //returns 'awcxey' + * + * @example + * _.strReplaceAll( 'abcdef', [ [ 'b', 'w' ], [ 'd', 'x' ], [ /f$/g, 'y' ] ] ); + * //returns 'awcxey' + * + * @example + * _.strReplaceAll( 'abcdef', { 'b' : 'w', 'd' : 'x', 'f' : 'y' } ); + * //returns 'awcxey' + * + * @example + * _.strReplaceAll( { src : 'abcdef', dictionary : [ [ 'b', 'w' ], [ 'd', 'x' ], [ 'f', 'y' ] ] } ); + * //returns 'awcxey' + * + * @example + * _.strReplaceAll( { src : 'abcdef', dictionary : { 'b' : 'w', 'd' : 'x', 'f' : 'y' }, joining : 0 } ); + * //returns [ 'a', 'w', 'c', 'x', 'e', 'y' ] + * + * @example + * _.strReplaceAll( { src : 'abcdefg', ins : [ 'b', 'd', 'f' ], but : [ 'w', 'x', 'y' ], onUnknown : ( e, c, o ) => '|' } ); + * //returns '|w|x|yg' + * + * @returns { String|Long } - By default, routine returns string with result of replacements. If map options is used and + * option {-o.joining-} is false like, then routine returns array with parts of resulted string. + * @function strReplaceAll + * @throws { Error } If arguments.length is less then one or more then three. + * @throws { Error } If {-src-} or {-o.src-} is not a String. + * @throws { Error } If {-ins-} is not a String, not a RegExp or not a Long with strings and regexps. + * @throws { Error } If {-sub-} is not a String or not a Long with strings. + * @throws { Error } If one of the {-ins-} or {-sub-} is a Long, and the other is not. + * @throws { Error } If {-ins-} and {-sub-} is Longs, and has different length. + * @throws { Error } If {-dictionary-} or {-o.dictionary-} is not an Object or Long. + * @throws { Error } If {-o.onUnknown-} is not a routine or not null. + * @throws { Error } If map options {-o-} has unnecessary fields. + * @namespace Tools + * + */ + +/* aaa : extend coverage */ /* Dmytro : covered */ + +/* aaa Does not work: `_.strReplaceAll( arg, quote, ( match, it ) => ` */ +/* + Dmytro : covered, it works. Maybe, the case described above uses illegal call - if {-ins-} is an Array, then + {-sub-} should be an Array + Please, see test routine strReplaceAllSubIsRoutine +*/ + +function strReplaceAll( src, ins, sub ) +{ + let o; + let foundArray = []; + + if( arguments.length === 3 ) + { + o = { src }; + o.dictionary = [ [ ins, sub ] ]; + } + else if( arguments.length === 2 ) + { + o = { src : arguments[ 0 ], dictionary : arguments[ 1 ] }; + } + else if( arguments.length === 1 ) + { + o = arguments[ 0 ]; + } + else + { + _.assert( 0, 'Expects at least single options map {-o-} or a combination of arguments : src-dictionary, src-ins-sub. ' ); + } + + /* verify */ + + _.routine.options_( strReplaceAll, o ); + _.assert( _.strIs( o.src ) ); + + _._strReplaceMapPrepare( o ); + + /* */ + + let found = _.strFindAll( o.src, o.ins ); + let result = []; + let index = 0; + + found.forEach( ( it ) => + { + let sub = o.sub[ it.tokenId ]; + + let unknown = o.src.substring( index, it.charsRangeLeft[ 0 ] ); + if( unknown && o.onUnknown ) + unknown = o.onUnknown( unknown, it, o ); + + if( unknown !== '' ) + result.push( unknown ); + + if( _.routineIs( sub ) ) + sub = sub.call( o, it.match, it ); + + if( sub !== '' ) + result.push( sub ); + + index = it.charsRangeLeft[ 1 ]; + }); + + result.push( o.src.substring( index, o.src.length ) ); + + if( o.joining ) + result = result.join( '' ) + + return result; +} + +strReplaceAll.defaults = +{ + src : null, + dictionary : null, + ins : null, + sub : null, + joining : 1, + onUnknown : null, + // counter : 0, +} + +// + +var JsTokensDefinition = +{ + 'comment/multiline' : /\/\*(?:\n|.)*?\*\//, + 'comment/singleline' : /\/\/.*?(?=\n|$)/, + 'string/single' : /'(?:\\\n|\\'|[^'\n])*?'/, + 'string/double' : /"(?:\\\n|\\"|[^"\n])*?"/, + 'string/multiline' : /`(?:\\\n|\\`|[^`])*?`/, + 'whitespace' : /\s+/, + 'keyword' : /\b(?:arguments|async|await|boolean|break|byte|case|catch|char|class|const|debugger|default|delete|do|double|else|enum|eval|export|extends|false|final|finally|float|for|function|goto|if|implements|import|in|instanceof|interface|let|long|native|new|null|package|private|protected|public|return|short|static|super|switch|this|throw|throws|transient|true|try|typeof|var|void|volatile|while|with|yield)\b/, // Dmytro : added new keywords and sorted in alphabetic order + 'regexp' : /\/((?:\\\/|[^\/\n])+?)\/(\w*)/, + 'name' : /[a-z_\$][0-9a-z_\$]*/i, + 'number' : /(?:0x(?:\d|[a-f])+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i, + 'parenthes' : /[\(\)]/, + 'curly' : /[{}]/, + 'square' : /[\[\]]/, + 'punctuation' : /;|,|\.\.\.|\.|\:|\?|=>|>=|<=|<|>|!==|===|!=|==|=|!|&|<<|>>|>>>|\+\+|--|\*\*|\+|-|\^|\||\/|\*|%|~|\!/, + 'name/function' : /[a-zA-Z_$][a-zA-Z0-9_$]*(?=\()/, // Dmytro : added + 'number/binary' : /0[bB][01]+n?/, // Dmytro : added + 'number/octal' : /0[oO][0-7]+n?/, // Dmytro : added + 'number/hex' : /0[xX][0-9a-fA-F]+n?/, // Dmytro : added + 'unicodeEscapeSequence' : /u[0-9a-fA-F]{4}/, // Dmytro : added + 'tab' : /\t+/, // Dmytro : added + 'comment/jsdoc' : /\/\*\*(?:\n|.)*?\*\//, // Dmytro : added +} + +function strTokenizeJs( o ) +{ + if( _.strIs( o ) ) + o = { src : o } + + let result = _.strFindAll + ({ + src : o.src, + ins : JsTokensDefinition, + tokenizingUnknown : o.tokenizingUnknown, + }); + + return result; +} + +strTokenizeJs.defaults = +{ + src : null, + tokenizingUnknown : 0, +} + +// + +var CppTokensDefinition = +{ + 'comment/multiline' : /\/\*.*?\*\//, + 'comment/singleline' : /\/\/.*?(?=\n|$)/, + 'string/single' : /'(?:\\\n|\\'|[^'\n])*?'/, + 'string/double' : /"(?:\\\n|\\"|[^"\n])*?"/, + 'string/multiline' : /`(?:\\\n|\\`|[^`])*?`/, + 'whitespace' : /\s+/, + 'keyword' : /\b(?:alignas|alignof|and|and_eq|asm|auto|bitand|bitor|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|false|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|noexcept|not|not_eq|nullptr|operator|or|or_eq|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|true|try|typedef|typeid|typename|union|unsigned|using(1)|virtual|void|volatile|wchar_t|while|xor|xor_eq)\b/, // Dmytro : added new keywords and sorted in alphabetic order + 'regexp' : /\/(?:\\\/|[^\/])*?\/(\w+)/, + 'name' : /[a-z_\$][0-9a-z_\$]*/i, + 'number' : /(?:0x(?:\d|[a-f])+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i, + 'parenthes' : /[\(\)]/, + 'curly' : /[{}]/, + 'square' : /[\[\]]/, + 'punctuation' : /;|,|\.\.\.|\.|\:|\?|=>|>=|<=|<|>|!=|!=|==|=|!|&|<<|>>|\+\+|--|\*\*|\+|-|\^|\||\/|\*|%|~|\!/, + 'char/literal' : /(?:L|u|u8|U)?'\w'/, // Dmytro : added + 'tab' : /\t+/, // Dmytro : added +} + +function strTokenizeCpp( o ) +{ + if( _.strIs( o ) ) + o = { src : o } + + let result = _.strFindAll + ({ + src : o.src, + ins : JsTokensDefinition, + tokenizingUnknown : o.tokenizingUnknown, + }); + + return result; +} + +strTokenizeCpp.defaults = +{ + src : null, + tokenizingUnknown : 0, +} + +// // +// +// function strSub( srcStr, range ) +// { +// _.assert( arguments.length === 2, 'Expects exactly two arguments' ); +// _.assert( _.strIs( srcStr ) ); +// _.assert( _.cinterval.is( sparse ) ); +// return srcStr.substring( cinterval[ 0 ], cinterval[ 1 ]+1 ); +// } + +// + +/** + * @summary Splits string into a parts using ranges from ( sparce ) sparce array. + * @param {String} srcStr - Source string to parse. + * @param {Array} sparse - Sparse array with ranges. + * @returns {Array} Returns array with parts of string. + * + * @example + * _.strSubs( 'aabbcc', [ ] );// + * + * @function strSubs + * @throws { Exception } If not enough argumets provided. + * @throws { Exception } If ( srcStr ) is not a string. + * @throws { Exception } If ( sparce ) is not a sparce array. + * @namespace Tools + * @module Tools/base/l5/StringTools + * + */ + +function strSubs( srcStr, sparse ) +{ + var result = []; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strIs( srcStr ) ); + _.assert( _.sparse.is( sparse ) ); + + _.sparse.eachRange( sparse, ( cinterval ) => + { + result.push( srcStr.substring( cinterval[ 0 ], cinterval[ 1 ]+1 ) ); + }); + + return result; +} + +// + +function strSorterParse( o ) +{ + + if( arguments.length === 1 ) + { + if( _.strIs( o ) ) + o = { src : o } + } + + if( arguments.length === 2 ) + { + o = + { + src : arguments[ 0 ], + fields : arguments[ 1 ] + } + } + + _.routine.options_( strSorterParse, o ); + _.assert( o.fields === null || _.objectLike( o.fields ) ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + + let map = + { + '>' : 1, + '<' : 0 + } + + let delimeters = _.props.onlyOwnKeys( map ); + let splitted = _.strSplit + ({ + src : o.src, + delimeter : delimeters, + stripping : 1, + preservingDelimeters : 1, + preservingEmpty : 0, + }); + + let parsed = []; + + if( splitted.length >= 2 ) + for( let i = 0; i < splitted.length; i+= 2 ) + { + let field = splitted[ i ]; + let postfix = splitted[ i + 1 ]; + + _.assert( o.fields ? !!o.fields[ field ] : true, 'Field: ', field, ' is not allowed.' ); + _.assert( _.strIs( postfix ), 'Field: ', field, ' doesn\'t have a postfix.' ); + /* qqq : for junior : use template-string where it is required */ + + let valueForPostfix = map[ postfix ]; + + if( valueForPostfix === undefined ) + _.assert( 0, 'unknown postfix: ', postfix ) + else + parsed.push( [ field, valueForPostfix ] ) + + // if( valueForPostfix !== undefined ) + // { + // parsed.push( [ field, valueForPostfix ] ) + // } + // else + // { + // _.assert( 0, 'unknown postfix: ', postfix ) + // } + } + + return parsed; +} + +strSorterParse.defaults = +{ + src : null, + fields : null, +} + +// + +function jsonParse( o ) +{ + let result; + + if( _.strIs( o ) ) + o = { src : o } + _.routine.options_( jsonParse, o ); + _.assert( arguments.length === 1 ); + _.assert( !!_.Gdf ); + + let jsonParser = _.gdf.selectSingleContext({ inFormat : 'string', outFormat : 'structure', ext : 'json' }); + + result = jsonParser.encode({ data : o.src }).out.data; + + return result.data; +} + +jsonParse.defaults = +{ + src : null, +} + +// -- +// format +// -- + +/** + * Converts string( str ) to array of unsigned 8-bit integers. + * + * @param {string} str - Source string to convert. + * @returns {typedArray} Returns typed array that represents string characters in 8-bit unsigned integers. + * + * @example + * //returns [ 101, 120, 97, 109, 112, 108, 101 ] + * _.strToBytes( 'example' ); + * + * @function strToBytes + * @throws { Exception } Throws a exception if( src ) is not a String. + * @throws { Exception } Throws a exception if no argument provided. + * @namespace Tools + * @module Tools/base/l5/StringTools + * + */ + +function strToBytes( src ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ) ); + + let result = new U8x( src.length ); + + for( let s = 0, sl = src.length ; s < sl ; s++ ) + { + result[ s ] = src.charCodeAt( s ); + } + + return result; +} + +// + +/** +* @summary Contains metric prefixes. +* @enum {} _metrics +* @module Tools/base/l5/StringTools +*/ + +let _metrics = +{ + + '24' : { name : 'yotta', symbol : 'Y', word : 'septillion' }, + '21' : { name : 'zetta', symbol : 'Z', word : 'sextillion' }, + '18' : { name : 'exa', symbol : 'E', word : 'quintillion' }, + '15' : { name : 'peta', symbol : 'P', word : 'quadrillion' }, + '12' : { name : 'tera', symbol : 'T', word : 'trillion' }, + '9' : { name : 'giga', symbol : 'G', word : 'billion' }, + '6' : { name : 'mega', symbol : 'M', word : 'million' }, + '3' : { name : 'kilo', symbol : 'k', word : 'thousand' }, + '2' : { name : 'hecto', symbol : 'h', word : 'hundred' }, + '1' : { name : 'deca', symbol : 'da', word : 'ten' }, + + '0' : { name : '', symbol : '', word : '' }, + + '-1' : { name : 'deci', symbol : 'd', word : 'tenth' }, + '-2' : { name : 'centi', symbol : 'c', word : 'hundredth' }, + '-3' : { name : 'milli', symbol : 'm', word : 'thousandth' }, + '-6' : { name : 'micro', symbol : 'μ', word : 'millionth' }, + '-9' : { name : 'nano', symbol : 'n', word : 'billionth' }, + '-12' : { name : 'pico', symbol : 'p', word : 'trillionth' }, + '-15' : { name : 'femto', symbol : 'f', word : 'quadrillionth' }, + '-18' : { name : 'atto', symbol : 'a', word : 'quintillionth' }, + '-21' : { name : 'zepto', symbol : 'z', word : 'sextillionth' }, + '-24' : { name : 'yocto', symbol : 'y', word : 'septillionth' }, + + 'range' : [ -24, +24 ], + +} + +/** + * Returns string that represents number( src ) with metric unit prefix that depends on options( o ). + * If no options provided function start calculating metric with default options. + * Example: for number ( 50000 ) function returns ( "50.0 k" ), where "k"- thousand. + * + * @param {(number|string)} src - Source object. + * @param {object} o - conversion options. + * @param {number} [ o.divisor=3 ] - Sets count of number divisors. + * @param {number} [ o.thousand=1000 ] - Sets integer power of one thousand. + * @param {boolean} [ o.fixed=1 ] - The number of digits to appear after the decimal point, example : [ '58912.001' ]. + * Number must be between 0 and 20. + * @param {number} [ o.dimensions=1 ] - Sets exponent of a number. + * @param {number} [ o.metric=0 ] - Sets the metric unit type from the map( _metrics ). + * @returns {string} Returns number with metric prefix as a string. + * + * @example + * //returns "1.0 M" + * _.strMetricFormat( 1, { metric : 6 } ); + * + * @example + * //returns "100.0 " + * _.strMetricFormat( "100m", { } ); + * + * @example + * //returns "100.0 T + * _.strMetricFormat( "100m", { metric : 12 } ); + * + * @example + * //returns "2 k" + * _.strMetricFormat( "1500", { fixed : 0 } ); + * + * @example + * //returns "1.0 M" + * _.strMetricFormat( "1000000",{ divisor : 2, thousand : 100 } ); + * + * @example + * //returns "10.0 h" + * _.strMetricFormat( "10000", { divisor : 2, thousand : 10, dimensions : 3 } ); + * + * @function strMetricFormat + * @namespace Tools + * @module Tools/base/l5/StringTools + * + */ + +/* qqq : cover routine strMetricFormat | Dmytro : covered */ +/* xxx : use it for time measurement */ + +function strMetricFormat( number, o ) +{ + + if( _.strIs( number ) ) + number = parseFloat( number ); + + o = _.routine.options_( strMetricFormat, o || null ); + + if( o.metrics === null ) + o.metrics = _metrics; + + _.assert( _.numberIs( number ), '"number" should be Number' ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.object.isBasic( o ) || o === undefined, 'Expects map {-o-}' ); + _.assert( _.numberIs( o.fixed ) ); + _.assert( o.fixed <= 20 ); + + let original = number; + + if( o.dimensions !== 1 ) + o.thousand = Math.pow( o.thousand, o.dimensions ); + + if( number !== 0 ) + { + + if( Math.abs( number ) >= o.thousand ) + { + + while( Math.abs( number ) >= o.thousand || !o.metrics[ String( o.metric ) ] ) + { + + if( o.metric + o.divisor > o.metrics.range[ 1 ] ) + break; + + number /= o.thousand; + o.metric += o.divisor; + + } + + } + else if( Math.abs( number ) < 1 ) + { + + while( Math.abs( number ) < 1 || !o.metrics[ String( o.metric ) ] ) + { + + if( o.metric - o.divisor < o.metrics.range[ 0 ] ) + break; + + number *= o.thousand; + o.metric -= o.divisor; + + } + + if( number / o.thousand > 1 ) + { + let o2 = + { + thousand : o.thousand, + metric : o.metric, + fixed : o.fixed, + divisor : o.divisor, + metrics : o.metrics, + dimensions : o.dimensions + }; + return strMetricFormat( number, o2 ); + } + + } + + } + + let result = ''; + + if( o.metrics[ String( o.metric ) ] ) + { + result = number.toFixed( o.fixed ) + ' ' + o.metrics[ String( o.metric ) ].symbol; + } + else + { + result = original.toFixed( o.fixed ) + ' '; + } + + return result; +} + +strMetricFormat.defaults = +{ + divisor : 3, + thousand : 1000, + fixed : 1, + dimensions : 1, + metric : 0, + metrics : null, +} + +// + +/** + * Short-cut for strMetricFormat() function. + * Converts number( number ) to specific count of bytes with metric prefix. + * Example: ( 2048 -> 2.0 kb). + * + * @param {string|number} str - Source number to convert. + * @param {object} o - conversion options. + * @param {number} [ o.divisor=3 ] - Sets count of number divisors. + * @param {number} [ o.thousand=1024 ] - Sets integer power of one thousand. + * @see {@link wTools.strMetricFormat} Check out main function for more usage options and details. + * @returns {string} Returns number of bytes with metric prefix as a string. + * + * @example + * //returns "100.0 b" + * _.strMetricFormatBytes( 100 ); + * + * @example + * //returns "4.0 kb" + * _.strMetricFormatBytes( 4096 ); + * + * @example + * //returns "1024.0 Mb" + * _.strMetricFormatBytes( Math.pow( 2, 30 ) ); + * + * @function strMetricFormatBytes + * @namespace Tools + * @module Tools/base/l5/StringTools + * + */ + +function strMetricFormatBytes( number, o ) +{ + + o = o || Object.create( null ); + let defaultOptions = + { + divisor : 3, + thousand : 1024, + }; + + _.props.supplement( o, defaultOptions ); + + return _.strMetricFormat( number, o ) + 'b'; +} + +// + +/** + * Short-cut for strMetricFormat() function. + * Converts number( number ) to specific count of seconds with metric prefix. + * Example: ( 1000 (ms) -> 1.000 s). + * + * @param {number} str - Source number to convert. + * @param {number} [ o.fixed=3 ] - The number of digits to appear after the decimal point, example : [ '58912.001' ]. + * Can`t be changed. + * @see {@link wTools.strMetricFormat} Check out main function for more usage options and details. + * @returns {string} Returns number of seconds with metric prefix as a string. + * + * @example + * //returns "1.000 s" + * _.strTimeFormat( 1000 ); + * + * @example + * //returns "10.000 ks" + * _.strTimeFormat( Math.pow( 10, 7 ) ); + * + * @example + * //returns "78.125 s" + * _.strTimeFormat( Math.pow( 5, 7 ) ); + * + * @function strTimeFormat + * @namespace Tools + * @module Tools/base/l5/StringTools + * + */ + +function strTimeFormat( time ) +{ + _.assert( arguments.length === 1 ); + time = _.time.from( time ); + let result = _.strMetricFormat( time * 0.001, { fixed : 3 } ) + 's'; + return result; +} + +// + +function strCsvFrom( src, o ) +{ + + let result = ''; + o = o || Object.create( null ); + + if( !o.header ) + { + + o.header = []; + + _.look( _.entityValueWithIndex( src, 0 ), function( e, k, i ) + { + o.header.push( k ); + }); + + } + + if( o.cellSeparator === undefined ) o.cellSeparator = ','; + if( o.rowSeparator === undefined ) o.rowSeparator = '\n'; + if( o.substitute === undefined ) o.substitute = ''; + if( o.withHeader === undefined ) o.withHeader = 1; + + //console.log( 'o',o ); + + if( o.withHeader ) + { + _.look( o.header, function( e, k, i ) + { + result += e + o.cellSeparator; + }); + result = result.substr( 0, result.length-o.cellSeparator.length ) + o.rowSeparator; + } + + _.each( src, function( row ) + { + + let rowString = ''; + + _.each( o.header, function( key ) + { + + let element = _.entityWithKeyRecursive( row, key ); + if( element === undefined ) element = ''; + element = String( element ); + if( element.indexOf( o.rowSeparator ) !== -1 ) + element = _.strReplaceAll( element, o.rowSeparator, o.substitute ); + if( element.indexOf( o.cellSeparator ) !== -1 ) + element = _.strReplaceAll( element, o.cellSeparator, o.substitute ); + + rowString += element + o.cellSeparator; + + }); + + result += rowString.substr( 0, rowString.length - o.cellSeparator.length ) + o.rowSeparator; + + }); + + return result; +} + +// + +// function strToDom( xmlStr ) +// { +// +// let xmlDoc = null; +// let isIEParser = window.ActiveXObject || 'ActiveXObject' in window; +// +// if( xmlStr === undefined ) +// return xmlDoc; +// +// if( window.DOMParser ) +// { +// +// let parser = new window.DOMParser(); +// let parsererrorNS = null; +// +// if( !isIEParser ) +// { +// try +// { +// parsererrorNS = parser.parseFromString( 'INVALID', 'text/xml' ).childNodes[ 0 ].namespaceURI; +// } +// catch( err ) +// { +// parsererrorNS = null; +// } +// } +// +// try +// { +// xmlDoc = parser.parseFromString( xmlStr, 'text/xml' ); +// if( parsererrorNS !== null && xmlDoc.getElementsByTagNameNS( parsererrorNS, 'parsererror' ).length > 0 ) +// { +// throw Error( 'Error parsing XML' ); +// xmlDoc = null; +// } +// } +// catch( err ) +// { +// throw Error( 'Error parsing XML' ); +// xmlDoc = null; +// } +// } +// else +// { +// if( xmlStr.indexOf( '' ) + 2 ); +// } +// xmlDoc = new ActiveXObject( 'Microsoft.XMLDOM' ); +// xmlDoc.async = 'false'; +// xmlDoc.loadXML( xmlStr ); +// } +// +// return xmlDoc; +// } + +// + +function strToConfig( src, o ) +{ + let result = Object.create( null ); + if( !_.strIs( src ) ) + throw _.err( '_.strToConfig :', 'require string' ); + + o = o || Object.create( null ); + if( o.delimeter === undefined ) o.delimeter = ' :'; + + let splitted = src.split( '\n' ); + + for( let s = 0 ; s < splitted.length ; s++ ) + { + + let row = splitted[ s ]; + let i = row.indexOf( o.delimeter ); + if( i === -1 ) + continue; + + let key = row.substr( 0, i ).trim(); + let val = row.substr( i + 1 ).trim(); + + result[ key ] = val; + + } + + return result; +} + +// // +// + +// function numberFromStrMaybe( src ) +// { +// _.assert( _.strIs( src ) || _.numberIs( src ) ); +// if( _.numberIs( src ) ) +// return src; +// +// // if( /^\s*\d+\.{0,1}\d*\s*$/.test( src ) ) +// // return parseFloat( src ); +// // return src +// // xxx2 +// // let parsed = parseFloat( src ); +// +// let parsed = Number( src ); +// if( !isNaN( parsed ) ) +// return parsed; +// return src; +// } + +// function strToNumberMaybe( src ) +// { +// _.assert( arguments.length === 1 ); /* Dmytro : prevents passing two or more arguments */ +// _.assert( _.strIs( src ) || _.numberIs( src ) ); +// +// if( _.numberIs( src ) ) +// return src; +// +// // if( /^\s*\d+\.{0,1}\d*\s*$/.test( src ) ) +// // return parseFloat( src ); +// // return src +// // xxx2 +// // let parsed = parseFloat( src ); +// +// let parsed = Number( src ); +// if( !isNaN( parsed ) ) +// return parsed; +// return src; +// } + +// + +/* +qqq : routine strStructureParse requires good coverage and extension | Dmytro : test coverage improved, added test routine `strStructureParseExperiment` with variants of extension + +Dmytro : below added new version of routine strStructureParse for new features +*/ + +// function strStructureParse( o ) +// { +// +// if( _.strIs( o ) ) +// o = { src : o } +// +// _.routine.options_( strStructureParse, o ); +// _.assert( !!o.keyValDelimeter ); +// _.assert( _.strIs( o.entryDelimeter ) ); +// _.assert( _.strIs( o.src ) ); +// _.assert( arguments.length === 1 ); +// _.assert( _.longHas( [ 'map', 'array', 'string' ], o.defaultStructure ) ); +// +// if( o.arrayElementsDelimeter === null ) +// o.arrayElementsDelimeter = [ ' ', ',' ]; +// +// let src = o.src.trim(); +// +// if( o.parsingArrays ) +// if( _.strIs( _.strInsideOf( src, o.longLeftDelimeter, o.longRightDelimeter ) ) ) +// { +// let r = strToArrayMaybe( src ); +// if( _.arrayIs( r ) ) +// return r; +// } +// +// src = _.strSplit +// ({ +// src, +// delimeter : o.keyValDelimeter, +// stripping : 0, +// quoting : o.quoting, +// preservingEmpty : 1, +// preservingDelimeters : 1, +// preservingQuoting : o.quoting ? 0 : 1 +// }); +// +// if( src.length === 1 && src[ 0 ] ) +// return src[ 0 ]; +// +// /* */ +// +// let pairs = []; +// for( let a = 0 ; a < src.length-2 ; a += 2 ) +// { +// let left = src[ a ]; +// let right = src[ a+2 ].trim(); +// +// _.assert( _.strIs( left ) ); +// _.assert( _.strIs( right ) ); +// +// while( a < src.length-3 ) +// { +// let cuts = _.strIsolateRightOrAll( right, o.entryDelimeter ); +// if( cuts[ 1 ] === undefined ) +// { +// right = src[ a+2 ] = src[ a+2 ] + src[ a+3 ] + src[ a+4 ]; +// right = right.trim(); +// // src.splice( a+2, 2 ); // Dmytro : splices new src[ a+2 ] and next iteration deletes previous 2 elements +// src.splice( a+3, 2 ); +// continue; +// } +// right = cuts[ 0 ]; +// src[ a+2 ] = cuts[ 2 ]; +// break; +// } +// +// pairs.push( left.trim(), right.trim() ); +// } +// +// /* */ +// +// _.assert( pairs.length % 2 === 0 ); +// let result = Object.create( null ); +// for( let a = 0 ; a < pairs.length-1 ; a += 2 ) +// { +// let left = pairs[ a ]; +// let right = pairs[ a+1 ]; +// +// _.assert( _.strIs( left ) ); +// _.assert( _.strIs( right ) ); +// +// if( o.toNumberMaybe ) +// right = _.numberFromStrMaybe( right ); +// +// if( o.parsingArrays ) +// right = strToArrayMaybe( right ); +// +// result[ left ] = right; +// +// } +// +// // if( src.length === 1 && src[ 0 ] ) +// // return src[ 0 ]; +// // +// +// if( _.props.keys( result ).length === 0 ) +// { +// if( o.defaultStructure === 'map' ) +// return result; +// else if( o.defaultStructure === 'array' ) +// return []; +// else if( o.defaultStructure === 'string' ) +// return ''; +// } +// +// return result; +// +// /**/ +// +// function strToArrayMaybe( str ) +// { +// let result = str; +// if( !_.strIs( result ) ) +// return result; +// let inside = _.strInsideOf( result, o.longLeftDelimeter, o.longRightDelimeter ); +// if( inside !== false ) +// { +// let splits = _.strSplit +// ({ +// src : inside, +// delimeter : o.arrayElementsDelimeter, +// stripping : 1, +// quoting : 1, +// preservingDelimeters : 0, +// preservingEmpty : 0, +// }); +// result = splits; +// if( o.toNumberMaybe ) +// result = result.map( ( e ) => _.numberFromStrMaybe( e ) ); +// } +// return result; +// } +// +// } +// +// strStructureParse.defaults = +// { +// src : null, +// keyValDelimeter : ':', +// entryDelimeter : ' ', +// arrayElementsDelimeter : null, +// longLeftDelimeter : '[', +// longRightDelimeter : ']', +// quoting : 1, +// parsingArrays : 0, +// toNumberMaybe : 1, +// defaultStructure : 'map', /* map / array / string */ +// } + +// + +function strStructureParse( o ) +{ + + if( _.strIs( o ) ) + o = { src : o } + + _.routine.options_( strStructureParse, o ); + _.assert( arguments.length === 1 ); + _.assert( !!o.keyValDelimeter ); + _.assert( _.strIs( o.entryDelimeter ) ); + _.assert( _.strIs( o.src ) ); + _.assert( _.longHas( [ 'map', 'array', 'string' ], o.defaultStructure ) ); + + if( o.arrayElementsDelimeter === null ) + o.arrayElementsDelimeter = [ ' ', ',' ]; + + let src = o.src.trim(); + + if( _.strIs( _.strInsideOf( src, o.mapLeftDelimeter, o.mapRightDelimeter ) ) ) + { + let inside = _.strInsideOf( src, o.mapLeftDelimeter, o.mapRightDelimeter ); + if( new RegExp( '^\\s*\\W*\\w+\\W*\\s*\\' + o.keyValDelimeter +'\\s*\\W*\\w+' ).test( inside ) ) + src = inside; + else if( /\s*/.test( inside ) ) + return Object.create( null ); + } + else if( o.parsingArrays ) + { + if( _.strIs( _.strInsideOf( src, o.longLeftDelimeter, o.longRightDelimeter ) ) ) + { + let r = strToArrayMaybe( src, o.depth ); + if( _.arrayIs( r ) ) + return r; + } + } + + src = _.strSplit + ({ + src, + delimeter : o.keyValDelimeter, + stripping : 0, + quoting : o.quoting, + preservingEmpty : 1, + preservingDelimeters : 1, + preservingQuoting : 0 + }); + + if( src.length === 1 && src[ 0 ] ) + return src[ 0 ]; + + strSplitsParenthesesBalanceJoin( src ); + + /* */ + + let pairs = []; + for( let a = 0 ; a < src.length-2 ; a += 2 ) + { + let left = src[ a ]; + let right = src[ a+2 ].trim(); + + _.assert( _.strIs( left ) ); + _.assert( _.strIs( right ) ); + + while( a < src.length-3 ) + { + let cuts = _.strIsolateRightOrAll( right, o.entryDelimeter ); + if( cuts[ 1 ] === undefined ) + { + right = src[ a+2 ] = src[ a+2 ] + src[ a+3 ] + src[ a+4 ]; + right = right.trim(); + src.splice( a+3, 2 ); + continue; + } + right = cuts[ 0 ]; + src[ a+2 ] = cuts[ 2 ]; + break; + } + + pairs.push( left.trim(), right.trim() ); + } + + /* */ + + _.assert( pairs.length % 2 === 0 ); + let result = Object.create( null ); + for( let a = 0 ; a < pairs.length-1 ; a += 2 ) + { + let left = pairs[ a ]; + let right = pairs[ a+1 ]; + + _.assert( _.strIs( left ) ); + _.assert( _.strIs( right ) ); + + if( o.toNumberMaybe ) + right = _.numberFromStrMaybe( right ); + + if( o.parsingArrays ) + right = strToArrayMaybe( right, o.depth ); + + + if( o.depth > 0 ) + { + let options = _.props.extend( null, o ); + options.depth = o.depth - 1; + if( _.strIs( right ) ) + { + options.src = right; + right = _.strStructureParse( options ); + } + } + + if( o.onTerminal && _.strIs( right ) ) + right = o.onTerminal( right ); + + if( o.severalValues ) + { + result[ left ] = _.scalarAppendOnce( result[ left ], right ); + } + else + { + result[ left ] = right; + } + + } + + if( _.props.keys( result ).length === 0 ) + { + if( o.defaultStructure === 'map' ) + return result; + else if( o.defaultStructure === 'array' ) + return []; + else if( o.defaultStructure === 'string' ) + return ''; + } + + return result; + + /**/ + + function strToArrayMaybe( str, depth ) + { + let result = str; + if( !_.strIs( result ) ) + return result; + let inside = _.strInsideOf( result, o.longLeftDelimeter, o.longRightDelimeter ); + if( inside !== undefined ) + { + let splits = _.strSplit + ({ + src : inside, + delimeter : o.arrayElementsDelimeter, + stripping : 1, + quoting : o.quoting, + preservingDelimeters : 0, + preservingEmpty : 0, + preservingQuoting : 0, + }); + result = splits; + + if( o.toNumberMaybe ) + result = result.map( ( e ) => _.numberFromStrMaybe( e ) ); + if( depth > 0 ) + { + depth--; + + strSplitsParenthesesBalanceJoin( result ); + let options = _.props.extend( null, o ); + options.depth = depth; + for( let i = 0; i < result.length; i++ ) + { + if( _.strIs( result[ i ] ) ) + { + options.src = result[ i ]; + result[ i ] = _.strStructureParse( options ); + } + } + } + if( o.onTerminal ) + result = result.map( ( e ) => o.onTerminal( e ) ) + } + return result; + } + + /* */ + + function strSplitsParenthesesBalanceJoin( splits ) + { + let stack = []; + let postfixes = [ _.regexpFrom( o.longRightDelimeter ), _.regexpFrom( o.mapRightDelimeter ) ]; + let map = + { + [ o.longLeftDelimeter ] : o.longRightDelimeter, + [ o.mapLeftDelimeter ] : o.mapRightDelimeter + }; + + for( let i = 0; i < splits.length; i++ ) + { + if( !_.strIs( splits[ i ] ) ) + { + continue; + } + if( splits[ i ] in map ) + { + stack.push( i ); + } + else if( _.regexpsTestAny( postfixes, splits[ i ] ) ) + { + if( stack.length === 0 ) + continue; + + let start = -1; + let end = i; + + for( let k = stack.length - 1 ; k >= 0 ; k-- ) + if( map[ splits[ stack[ k ] ] ] === splits[ end ] ) + { + start = stack[ k ]; + stack.splice( k, stack.length ); + break; + } + + if( start === -1 ) + continue; + + let length = end - start; + + splits[ start ] = splits.splice( start, length + 1, null ).join( o.entryDelimeter ); + i -= length; + } + } + } + +} + +strStructureParse.defaults = +{ + src : null, + keyValDelimeter : ':', + entryDelimeter : ' ', + arrayElementsDelimeter : null, + mapLeftDelimeter : '{', + mapRightDelimeter : '}', + longLeftDelimeter : '[', + longRightDelimeter : ']', + quoting : 1, + parsingArrays : 0, + severalValues : 0, + depth : 0, + onTerminal : null, + toNumberMaybe : 1, + defaultStructure : 'map', /* map / array / string */ +} + +// function strStructureParse( o ) +// { +// +// if( _.strIs( o ) ) +// o = { src : o } +// +// _.routine.options_( strStructureParse, o ); +// _.assert( !!o.keyValDelimeter ); +// _.assert( _.strIs( o.entryDelimeter ) ); +// _.assert( _.strIs( o.src ) ); +// _.assert( arguments.length === 1 ); +// _.assert( _.longHas( [ 'map', 'array', 'string' ], o.defaultStructure ) ); +// +// if( o.arrayElementsDelimeter === null ) +// o.arrayElementsDelimeter = [ ' ', ',' ]; +// +// let src = o.src.trim(); +// +// if( o.parsingArrays ) +// if( _.strIs( _.strInsideOf( src, o.longLeftDelimeter, o.longRightDelimeter ) ) ) +// { +// let r = strToArrayMaybe( src ); +// if( _.arrayIs( r ) ) +// return r; +// } +// +// src = _.strSplit +// ({ +// src, +// delimeter : o.keyValDelimeter, +// stripping : 1, +// quoting : o.quoting, +// preservingEmpty : 1, +// preservingDelimeters : 0, +// preservingQuoting : o.quoting ? 0 : 1 +// }); +// +// /* */ +// +// // let pairs = []; +// // for( let a = 0 ; a < src.length ; a++ ) +// // { +// // let left = src[ a ]; +// // let right = src[ a+1 ]; +// // +// // _.assert( _.strIs( left ) ); +// // _.assert( _.strIs( right ) ); +// // +// // while( a < src.length - 1 ) +// // { +// // let cuts = _.strIsolateRightOrAll( right, o.entryDelimeter ); +// // if( cuts[ 1 ] === undefined ) +// // { +// // right = src[ a+1 ] = src[ a ] + src[ a+1 ] + src[ a+1 ]; +// // src.splice( a+1, 1 ); +// // continue; +// // } +// // right = cuts[ 0 ]; +// // src[ a ] = cuts[ 2 ]; +// // break; +// // } +// // +// // } +// +// /* */ +// +// let result = Object.create( null ); +// for( let a = 1 ; a < src.length ; a++ ) +// { +// let left = src[ a-1 ]; +// let right = src[ a+0 ]; +// +// _.assert( _.strIs( left ) ); +// _.assert( _.strIs( right ) ); +// +// while( a < src.length - 1 ) +// { +// let cuts = _.strIsolateRightOrAll( right, o.entryDelimeter ); +// // if( cuts[ 1 ] === undefined ) +// // { +// // right = src[ a ] = src[ a ] + src[ a+1 ]; +// // src.splice( a+1, 1 ); +// // continue; +// // } +// right = cuts[ 0 ]; +// src[ a ] = cuts[ 2 ]; +// break; +// } +// +// result[ left ] = right; +// +// if( o.toNumberMaybe ) +// result[ left ] = _.numberFromStrMaybe( result[ left ] ); +// +// if( o.parsingArrays ) +// result[ left ] = strToArrayMaybe( result[ left ] ); +// +// } +// +// if( src.length === 1 && src[ 0 ] ) +// return src[ 0 ]; +// +// if( _.props.keys( result ).length === 0 ) +// { +// if( o.defaultStructure === 'map' ) +// return result; +// else if( o.defaultStructure === 'array' ) +// return []; +// else if( o.defaultStructure === 'string' ) +// return ''; +// } +// +// return result; +// +// /**/ +// +// function strToArrayMaybe( str ) +// { +// let result = str; +// if( !_.strIs( result ) ) +// return result; +// let inside = _.strInsideOf( result, o.longLeftDelimeter, o.longRightDelimeter ); +// if( inside !== false ) +// { +// let splits = _.strSplit +// ({ +// src : inside, +// delimeter : o.arrayElementsDelimeter, +// stripping : 1, +// quoting : 1, +// preservingDelimeters : 0, +// preservingEmpty : 0, +// }); +// result = splits; +// if( o.toNumberMaybe ) +// result = result.map( ( e ) => _.numberFromStrMaybe( e ) ); +// } +// return result; +// } +// +// } +// +// strStructureParse.defaults = +// { +// src : null, +// keyValDelimeter : ':', +// entryDelimeter : ' ', +// arrayElementsDelimeter : null, +// longLeftDelimeter : '[', +// longRightDelimeter : ']', +// quoting : 1, +// parsingArrays : 0, +// toNumberMaybe : 1, +// defaultStructure : 'map', /* map / array / string */ +// } + +// + +/* +qqq : routine strWebQueryParse requires good coverage and extension | Dmytro : coverage added, extension of routine and coverage after routine strStructureParse +*/ + +function strWebQueryParse( o ) +{ + + if( _.strIs( o ) ) + o = { src : o } + + _.routine.options_( strWebQueryParse, o ); + _.assert( arguments.length === 1 ); + + if( o.keyValDelimeter === null ) + o.keyValDelimeter = [ ':', '=' ]; + + return _.strStructureParse( o ); +} + +var defaults = strWebQueryParse.defaults = Object.create( strStructureParse.defaults ); + +defaults.defaultStructure = 'map'; +defaults.parsingArrays = 0; +defaults.keyValDelimeter = null; /* [ ':', '=' ] */ +defaults.entryDelimeter = '&'; +defaults.toNumberMaybe = 1; +/* toNumberMaybe must be on by default */ + +// Dmytro : missed, produces bug if value in key-value pairs starts with number literal or need improve condition in routine numberFromStrMaybe +// qqq + +// + +/* +qqq : routine strWebQueryStr requires good coverage | Dmytro : covered +*/ + +function strWebQueryStr( o ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); // Dmytro : missed + + if( _.strIs( o ) ) + return o; + + _.routine.options_( strWebQueryStr, o ); // Dmytro : missed + + let result = _.mapToStr( o ); + + return result; +} + +var defaults = strWebQueryStr.defaults = Object.create( null ); +defaults.src = null; // Dmytro : missed +defaults.keyValDelimeter = ':'; +defaults.entryDelimeter = '&'; + +// + +function strRequestParse( o ) +{ + + if( _.strIs( o ) ) + o = { src : o }; + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.strIs( o.src ) ); + o = _.routine.options_( strRequestParse, o ); + + if( _.boolLike( o.quoting ) && o.quoting ) + o.quoting = [ '"', '`', '\'' ]; + if( o.quoting ) + o.quoting = _.strQuotePairsNormalize( o.quoting ); + + let result = Object.create( null ); + result.subject = ''; + result.map = Object.create( null ); + result.subjects = []; + result.maps = []; + result.keyValDelimeter = o.keyValDelimeter; + result.commandsDelimeter = o.commandsDelimeter; + result.original = o.src; + + o.src = o.src.trim(); + + if( !o.src ) + return result; + + if( o.unquoting && o.quoting ) + { + // let isolated = _.strIsolateInside( o.src, o.quoting ); + // if( isolated[ 0 ] === '' && isolated[ 4 ] === '' ) + // o.src = isolated[ 2 ]; + o.src = _.strUnquote( o.src, o.quoting ); + } + + /* should be strSplit, not strIsolateLeftOrAll because of quoting */ + + let commands + + if( o.commandsDelimeter ) + commands = _.strSplit + ({ + src : o.src, + delimeter : o.commandsDelimeter, + stripping : 1, + quoting : o.quoting, + preservingDelimeters : 0, + preservingEmpty : 0, + }); + else + commands = [ o.src ]; /* qqq : cover the case */ + + /* */ + + for( let c = 0 ; c < commands.length ; c++ ) + { + + /* xxx : imlement parsing with template routine _.strShape() + + b ?** ':' ** e + b ?** ':' ?** ':' ** e + b ?*+ s+ ??*+ ':' *+ e + b ( ?*+ )? <&( s+ )&> ( ??*+ ':' *+ )? e + + b subject:?** s+ map:** e + // 'c:/dir1 debug:0' -> subject : 'c:/dir1', debug:0 + + // test.identical( _.strCount( op.output, /program.end(.|\n|\r)*timeout1/mg ), 1 ); + test.identical( _.strCount( op.output, `'program.end'**'timeout1'` ), 1 ); + + */ + + let mapEntries = [ commands[ c ], null, '' ]; + + // if( o.keyValDelimeter ) + // mapEntries = _.strSplit + // ({ + // src : commands[ c ], + // delimeter : o.keyValDelimeter, + // stripping : 1, + // quoting : o.quoting, + // preservingDelimeters : 1, + // preservingEmpty : 0, + // }); + + if( o.keyValDelimeter ) + mapEntries = _.strIsolateLeftOrAll + ({ + src : commands[ c ], + delimeter : o.keyValDelimeter, + quote : o.quoting, + }) + + // let subjectAndKey = _.strIsolateRightOrAll + // ({ + // src : mapEntries[ 0 ].trim(), + // delimeter : ' ', + // quote : o.quoting, + // }) + // let subject = subjectAndKey[ 0 ]; + // mapEntries[ 0 ] = subjectAndKey[ 2 ]; + + + let subject; + let map = Object.create( null ); + // let subject, map; + // if( mapEntries.length === 1 ) + if( mapEntries[ 1 ] ) + { + // let subjectAndKey = _.strIsolateRightOrAll( mapEntries[ 0 ].trim(), ' ' ); + // subject = subjectAndKey[ 0 ]; + // mapEntries[ 0 ] = subjectAndKey[ 2 ]; + + let subjectAndKey = _.strIsolateRightOrAll + ({ + src : mapEntries[ 0 ].trim(), + delimeter : ' ', + quote : o.quoting, + }) + subject = subjectAndKey[ 0 ]; + mapEntries[ 0 ] = subjectAndKey[ 2 ]; + + let splits = _.strSplit + ({ + src : mapEntries.join( '' ), + delimeter : o.keyValDelimeter, + stripping : 0, + quoting : o.quoting, + preservingEmpty : 1, + preservingDelimeters : 1, + preservingQuoting : 1, + }); + + let pairs = []; + for( let a = 0 ; a < splits.length-2 ; a += 2 ) + { + let left = splits[ a ]; + let right = splits[ a+2 ].trim(); + + _.assert( _.strIs( left ) ); + _.assert( _.strIs( right ) ); + + while( a < splits.length-3 ) + { + /* qqq : for Dmytro : ?? */ + // let cuts = _.strIsolateRightOrAll({ src : right, delimeter : o.entryDelimeter, quote : 1, times : 1 }); + let cuts = _.strIsolateRightOrAll({ src : right, quote : 1, times : 1 }); + if( cuts[ 1 ] === undefined ) + { + right = splits[ a+2 ] = splits[ a+2 ] + splits[ a+3 ] + splits[ a+4 ]; + right = right.trim(); + splits.splice( a+3, 2 ); + continue; + } + right = cuts[ 0 ]; + splits[ a+2 ] = cuts[ 2 ]; + break; + } + + left = left.trim(); + right = right.trim(); + if( o.unquoting ) + { + left = _.strUnquote( left ); + right = _.strUnquote( right ); + } + + pairs.push( left, right ); + } + + for( let a = 0 ; a < pairs.length-1 ; a += 2 ) + { + let left = pairs[ a ]; + let right = pairs[ a+1 ]; + right = _.numberFromStrMaybe( right ); + right = strToArrayMaybe( right ); + + if( o.severalValues ) + map[ left ] = _.scalarAppendOnce( map[ left ], right ); + else + map[ left ] = right; + } + } + else + { + subject = mapEntries[ 0 ]; + } + // if( !mapEntries[ 1 ] ) + // { + // subject = mapEntries[ 0 ]; + // // map = Object.create( null ); + // } + // else + // { + // // let subjectAndKey = _.strIsolateRightOrAll( mapEntries[ 0 ].trim(), ' ' ); + // // subject = subjectAndKey[ 0 ]; + // // mapEntries[ 0 ] = subjectAndKey[ 2 ]; + // + // let subjectAndKey = _.strIsolateRightOrAll + // ({ + // src : mapEntries[ 0 ].trim(), + // delimeter : ' ', + // quote : o.quoting, + // }) + // subject = subjectAndKey[ 0 ]; + // mapEntries[ 0 ] = subjectAndKey[ 2 ]; + // + // // map = _.strStructureParse + // // ({ + // // src : mapEntries.join( '' ), + // // keyValDelimeter : o.keyValDelimeter, + // // parsingArrays : o.parsingArrays, + // // quoting : o.quoting, + // // severalValues : o.severalValues, + // // }); + // + // /* Dmytro : it uses to get valid result when the quotes is used, also, it used no additional options, so performance is improved */ + // + // let splits = _.strSplit + // ({ + // src : mapEntries.join( '' ), + // delimeter : o.keyValDelimeter, + // stripping : 0, + // quoting : 0, + // preservingEmpty : 1, + // preservingDelimeters : 1, + // preservingQuoting : 0 + // }); + // + // let pairs = []; + // for( let a = 0 ; a < splits.length-2 ; a += 2 ) + // { + // let left = splits[ a ]; + // let right = splits[ a+2 ].trim(); + // + // _.assert( _.strIs( left ) ); + // _.assert( _.strIs( right ) ); + // + // while( a < splits.length-3 ) + // { + // let cuts = _.strIsolateRightOrAll({ src : right, delimeter : o.entryDelimeter, quote : 1, times : 1 }); + // if( cuts[ 1 ] === undefined ) + // { + // right = splits[ a+2 ] = splits[ a+2 ] + splits[ a+3 ] + splits[ a+4 ]; + // right = right.trim(); + // splits.splice( a+3, 2 ); + // continue; + // } + // right = cuts[ 0 ]; + // splits[ a+2 ] = cuts[ 2 ]; + // break; + // } + // + // left = left.trim(); + // right = right.trim(); + // if( o.quoting ) + // { + // left = _.strUnquote( left ); + // right = _.strUnquote( right ); + // } + // + // pairs.push( left, right ); + // } + // + // for( let a = 0 ; a < pairs.length-1 ; a += 2 ) + // { + // let left = pairs[ a ]; + // let right = pairs[ a+1 ]; + // right = _.numberFromStrMaybe( right ); + // right = strToArrayMaybe( right ); + // + // if( o.severalValues ) + // map[ left ] = _.scalarAppendOnce( map[ left ], right ); + // else + // map[ left ] = right; + // } + // + // } + + // let mapEntries = [ commands[ c ] ]; + // if( o.keyValDelimeter ) + // mapEntries = _.strSplit + // ({ + // src : commands[ c ], + // delimeter : o.keyValDelimeter, + // stripping : 1, + // quoting : o.quoting, + // preservingDelimeters : 1, + // preservingEmpty : 0, + // }); + // + // let subject, map; + // if( mapEntries.length === 1 ) + // { + // subject = mapEntries[ 0 ]; + // map = Object.create( null ); + // } + // else + // { + // let subjectAndKey = _.strIsolateRightOrAll( mapEntries[ 0 ], ' ' ); + // subject = subjectAndKey[ 0 ]; + // mapEntries[ 0 ] = subjectAndKey[ 2 ]; + // + // map = _.strStructureParse + // ({ + // src : mapEntries.join( '' ), + // keyValDelimeter : o.keyValDelimeter, + // parsingArrays : o.parsingArrays, + // quoting : o.quoting, + // }); + // + // } + + if( o.unquoting ) + subject = _.strUnquote( subject ); + + if( o.subjectWinPathsMaybe ) + subject = winPathSubjectCheck( subject, map ); + + result.subjects.push( subject ); + result.maps.push( map ); + } + + if( result.subjects.length ) + result.subject = result.subjects[ 0 ]; + if( result.maps.length ) + result.map = result.maps[ 0 ]; + + return result; + + /* */ + + function strToArrayMaybe( str ) + { + if( !_.strIs( str ) ) + return str; + + let inside = _.strInsideOf( str, '[', ']' ); + if( inside === undefined ) + return str; + + let result = _.strSplit + ({ + src : inside, + delimeter : [ ' ', ',' ], + stripping : 1, + quoting : o.quoting, + preservingDelimeters : 0, + preservingEmpty : 0, + preservingQuoting : 0, + }); + return result.map( ( e ) => _.numberFromStrMaybe( e ) ); + } + + /* */ + + function winPathSubjectCheck( subject, srcMap ) + { + + for( let key in srcMap ) + { + if( _.strIs( srcMap[ key ] ) && _.strBegins( srcMap[ key ], '\\' ) && key.length === 1 ) + { + subject += subject ? ` ${ key }:${ srcMap[ key ] }` : `${ key }:${ srcMap[ key ] }`; + delete srcMap[ key ]; + } + else + { + break; + } + } + + return subject; + } +} + +var defaults = strRequestParse.defaults = Object.create( null ); +defaults.keyValDelimeter = ':'; +defaults.commandsDelimeter = ';'; +defaults.quoting = 1; +defaults.unquoting = 1; +defaults.parsingArrays = 1; +defaults.severalValues = 0; +defaults.subjectWinPathsMaybe = 0; +defaults.src = null; + +// + +/** + * Routine strRequestStr() rebuilds original command string from parsed structure {-o-}. + * + * @param { ObjectLike } o - Object, which represents parsed command: + * @param { String } o.subject - First command in sequence of commands. + * @param { Map } o.map - Map options for first command {-o.subject-}. + * @param { Long } o.subjects - An array of commands. + * @param { Map } o.maps - Map options for commands. + * @param { String } o.keyValDelimeter - Delimeter for key and vals in map options. + * @param { String } o.commandsDelimeter - Delimeter for sequence of commands, each + * pair of subject-map will be separated by it. + * @param { String } o.original - Original command string, if this option is defined, + * then routine returns {-o.original-}. + * Note. Routine try to make command by using options {-o.subjects-} and {-o.subject-}. + * Firstly, routine checks {-o.subjects-} and appends options for each command. If + * {-o.subjects-} not exists, then routine check {-o.subject-} and append options from + * {-o.map-}. Otherwise, empty string returns. + * + * @example + * _.strRequestStr( { original : '.build abc debug:0 ; .set v:10' } ); + * //returns '.build abc debug:0 ; .set v:10' + * + * @example + * _.strRequestStr( { original : '.build abc debug:0 ; .set v:10', subjects : [ '.build some', '.set' ], maps : [ { debug : 1 }, { v : 1 } ] } ); + * //returns '.build abc debug:0 ; .set v:10' + * + * @example + * _.strRequestStr( { subjects : [ '.build some', '.set' ], maps : [ { debug : 1 }, { v : 1 } ] } ); + * //returns '.build some debug:1 ; .set v:1' + * + * @example + * _.strRequestStr( { subjects : [ '.build some', '.set' ], maps : [ { debug : 1 }, { v : 1 } ], subject : '.run /home/user', map : { v : 5 } } ); + * //returns '.build some debug:1 ; .set v:1' + * + * @example + * _.strRequestStr( { subject : '.run /home/user', map : { v : 5 } } ); + * //returns '.run /home/user v:5' + * + * @example + * _.strRequestStr( { subjects : [ '.run /home/user' ], map : { v : 5 } } ); + * //returns '.run /home/user' + * + * @example + * _.strRequestStr( { map : { v : 5 }, maps : [ { v : 5 }, { routine : 'strIs' } ] } ); + * //returns '' + * + * @returns { String } - Returns original command builded from parsed structure. + * @function strRequestStr + * @throws { Error } If arguments.length is less or more then one. + * @throws { Error } If {-o.original-} exists and it is not a String. + * @throws { Error } If {-o.subject-} is not a String. + * @throws { Error } If {-o.map-} is not map like. + * @throws { Error } If elements of {-o.subjects-} is not a Strings. + * @throws { Error } If elements of {-o.maps-} is not map like. + * @namespace Tools + * + */ + +function strRequestStr( o ) +{ + + _.assert( arguments.length === 1 ); + o = _.routine.options_( strRequestStr, arguments ); + + if( o.original ) + { + _.assert( _.strIs( o.original ) ); + return o.original; + } + + let result = ''; + + if( o.subjects.length > 0 ) + { + + for( let i = 0 ; i < o.subjects.length ; i++ ) + { + if( o.subjects[ i ] !== undefined ) + { + _.assert( _.strIs( o.subjects[ i ] ) ); + if( o.subjects[ i ] !== '' ) + result += o.subjects[ i ] + ' '; + } + if( o.maps[ i ] !== undefined ) + { + _.assert( _.mapIs( o.maps[ i ] ) ); + let map = o.maps[ i ]; + for( let k in map ) + { + result += k + o.keyValDelimeter; + if( _.longIs( map[ k ] ) ) + result += '[' + map[ k ] + '] '; + else + result += map[ k ] + ' '; + } + } + if( o.subjects[ i + 1 ] !== undefined ) + result += o.commandsDelimeter + ' '; + } + + } + else if( o.subject ) + { + + if( o.subject ) + { + _.assert( _.strIs( o.subject ) ); + result += o.subject + ' '; + } + if( o.map ) + { + for( let k in o.map ) + { + _.assert( _.mapIs( o.map ) ); + result += k + o.keyValDelimeter; + if( _.longIs( o.map[ k ] ) ) + result += '[' + o.map[ k ] + '] '; + else + result += o.map[ k ] + ' '; + } + } + + } + + return result.trim(); +} + +var defaults = strRequestStr.defaults = Object.create( null ); + +defaults.subject = null; +defaults.map = null; +defaults.subjects = null; +defaults.maps = null; +defaults.keyValDelimeter = strRequestParse.defaults.keyValDelimeter; +defaults.commandsDelimeter = strRequestParse.defaults.commandsDelimeter; +defaults.original = null; + +// + +function strCommandParse( o ) +{ + if( _.strIs( o ) ) + o = { src : o } + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.strIs( o.src ) ); + o = _.routine.options_( strCommandParse, o ); + + let tokens = _.strSplit({ src : o.commandFormat, delimeter : [ '?', 'subject', 'options' ], preservingEmpty : 0 }); + + _.each( tokens, ( token ) => _.assert( _.longHas( [ '?', 'subject', 'options' ], token ), 'Unknown token:', token ) ); + + let subjectToken = _.strHas( o.commandFormat, 'subject' ); + let subjectTokenMaybe = _.strHas( o.commandFormat, 'subject?' ); + let optionsToken = _.strHas( o.commandFormat, 'options' ); + let optionsTokenMaybe = _.strHas( o.commandFormat, 'options?' ); + + let result = Object.create( null ); + + result.subject = ''; + result.map = Object.create( null ); + result.subjects = []; + result.maps = []; + result.keyValDelimeter = o.keyValDelimeter; + result.commandsDelimeter = o.commandsDelimeter; + + if( !o.src ) + return result; + + /* */ + + let mapEntries = [ o.src ]; + if( o.keyValDelimeter ) + mapEntries = _.strSplit + ({ + src : o.src, + delimeter : o.keyValDelimeter, + stripping : 1, + quoting : 1, + preservingDelimeters : 1, + preservingEmpty : 0, + }); + + let subject = ''; + let map = Object.create( null ); + + if( mapEntries.length === 1 ) + { + if( subjectToken ) + subject = mapEntries[ 0 ]; + } + else + { + if( subjectToken ) + { + let subjectAndKey; + + if( !optionsToken ) + subject = _.strStrip( o.src ); + else if( _.strBegins( o.commandFormat, 'subject' ) ) + { + subjectAndKey = _.strIsolateRightOrAll( mapEntries[ 0 ], ' ' ); + subject = subjectAndKey[ 0 ]; + mapEntries[ 0 ] = subjectAndKey[ 2 ]; + + if( !subject.length && !subjectTokenMaybe ) + { + let src = mapEntries.splice( 0, 3 ).join( '' ); + subjectAndKey = _.strIsolateLeftOrAll( src, ' ' ); + subject = subjectAndKey[ 0 ]; + mapEntries.unshift( subjectAndKey[ 2 ] ) + } + } + else + { + subjectAndKey = _.strIsolateLeftOrAll( mapEntries[ mapEntries.length - 1 ], ' ' ); + subject = subjectAndKey[ 2 ]; + mapEntries[ mapEntries.length - 1 ] = subjectAndKey[ 0 ]; + + if( !subject.length && !subjectTokenMaybe ) + { + let src = mapEntries.splice( -3 ).join( '' ); + subjectAndKey = _.strIsolateLeftOrAll( src, ' ' ); + subject = subjectAndKey[ 2 ]; + mapEntries.push( subjectAndKey[ 0 ] ) + } + + } + } + + if( optionsToken ) + { + map = _.strStructureParse + ({ + src : mapEntries.join( '' ), + keyValDelimeter : o.keyValDelimeter, + parsingArrays : o.parsingArrays, + quoting : o.quoting + }); + } + } + + if( subjectToken ) + _.sure( subjectTokenMaybe || subject.length, 'No subject found in string:', o.src ) + + if( optionsToken ) + _.sure( optionsTokenMaybe || _.props.keys( map ).length, 'No options found in string:', o.src ) + + result.subjects.push( subject ); + result.maps.push( map ); + + result.subject = subject; + result.map = map; + + return result; +} + +var defaults = strCommandParse.defaults = Object.create( null ); +defaults.keyValDelimeter = ':'; +defaults.quoting = 1; +defaults.parsingArrays = 1; +defaults.src = null; +defaults.commandFormat = 'subject? options?'; + +// + +function strCommandsParse( o ) +{ + if( _.strIs( o ) ) + o = { src : o } + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.strIs( o.src ) ); + o = _.routine.options_( strCommandsParse, o ); + + let result = Object.create( null ); + + result.subject = ''; + result.map = Object.create( null ); + result.subjects = []; + result.maps = []; + result.keyValDelimeter = o.keyValDelimeter; + result.commandsDelimeter = o.commandsDelimeter; + + if( !o.src ) + return result; + + /* should be strSplit, but not strIsolateLeftOrAll because of quoting */ + + let commands = _.strSplit + ({ + src : o.src, + delimeter : o.commandsDelimeter, + stripping : 1, + quoting : 1, + preservingDelimeters : 0, + preservingEmpty : 0, + }); + + let o2 = _.mapOnly_( null, o, strCommandParse.defaults ); + + for( let c = 0 ; c < commands.length ; c++ ) + { + o2.src = commands[ c ]; + let parsedCommand = _.strCommandParse( o2 ); + _.arrayAppendArray( result.subjects, parsedCommand.subjects ); + _.arrayAppendArray( result.maps, parsedCommand.maps ); + } + + result.subject = result.subjects[ 0 ]; + result.map = result.maps[ 0 ]; + + return result; +} + +var defaults = strCommandsParse.defaults = Object.create( strCommandParse.defaults ); +defaults.commandsDelimeter = ';'; + +// + +function strJoinMap( o ) +{ + + _.routine.options_( strJoinMap, o ); + _.assert( _.strIs( o.keyValDelimeter ) ); + _.assert( _.strIs( o.entryDelimeter ) ); + _.assert( _.object.isBasic( o.src ) ); + _.assert( arguments.length === 1 ); + + let result = ''; + let c = 0; + for( let s in o.src ) + { + if( c > 0 ) + result += o.entryDelimeter; + result += s + o.keyValDelimeter + o.src[ s ]; + c += 1; + } + + return result; +} + +strJoinMap.defaults = +{ + src : null, + keyValDelimeter : ':', + entryDelimeter : ' ', +} + +// -- +// strTable +// -- + +function strTable( o ) +{ + + if( !_.mapIs( o ) ) + o = { data : arguments[ 0 ], dim : ( arguments.length > 1 ? arguments[ 1 ] : null ) }; + + _.routine.options_( strTable, o ); + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects single argument' ); + _.assert( o.data !== undefined ); + _.assert( _.longIs( o.dim ) && o.dim.length === 2 && _.numbersAreAll( o.dim ), 'Expects defined {- o.dim -}' ); + + if( _.strIs( o.style ) ) + { + _.assert( !!strTable.style[ o.style ], `Unknown style ${o.style}` ); + o.style = strTable.style[ o.style ]; + } + _.mapSupplementNulls( o, o.style ); + + if( o.onCellGet === null ) + o.onCellGet = onCellGetDefault; + if( o.onCellDrawAfter === null ) + o.onCellDrawAfter = onCellDrawAfterDefault; + if( o.onCellDraw === null ) + o.onCellDraw = cellDraw; + + /* should go after refining onCellGet */ + if( o.topHead || o.bottomHead || o.leftHead || o.rightHead ) + return headsIntegrate(); + + o.rowHeight = _.scalarToVector( o.rowHeight, o.dim[ 0 ] ); + o.minRowHeight = _.scalarToVector( o.minRowHeight, o.dim[ 0 ] ); + o.maxRowHeight = _.scalarToVector( o.maxRowHeight, o.dim[ 0 ] ); + o.colWidth = _.scalarToVector( o.colWidth, o.dim[ 1 ] ); + o.minColWidth = _.scalarToVector( o.minColWidth, o.dim[ 1 ] ); + o.maxColWidth = _.scalarToVector( o.maxColWidth, o.dim[ 1 ] ); + + o.cellAlign = scalarToVector( o.cellAlign, 2 ); + o.cellAlign = o.cellAlign.map( ( cellAlign ) => cellAlign === null ? 'center' : cellAlign ); + o.cellPadding = scalarToVector( o.cellPadding, 4 ); + o.tablePadding = scalarToVector( o.tablePadding, 4 ); + o.topHead = o.topHead ? scalarToVector( o.topHead, o.dim[ 1 ] ) : o.topHead; + o.bottomHead = o.bottomHead ? scalarToVector( o.bottomHead, o.dim[ 1 ] ) : o.bottomHead; + o.leftHead = o.leftHead ? scalarToVector( o.leftHead, o.dim[ 0 ] ) : o.leftHead; + o.rightHead = o.rightHead ? scalarToVector( o.rightHead, o.dim[ 0 ] ) : o.rightHead; + + sizeEval(); + + _.assert( o.rowHeight.length === o.dim[ 0 ] ); + _.assert( o.minRowHeight.length === o.dim[ 0 ] ); + _.assert( o.maxRowHeight.length === o.dim[ 0 ] ); + _.assert( o.colWidth.length === o.dim[ 1 ] ); + _.assert( o.minColWidth.length === o.dim[ 1 ] ); + _.assert( o.maxColWidth.length === o.dim[ 1 ] ); + _.assert( o.style === null || _.mapIs( o.style ) ); + _.assert( _.all( o.cellAlign, ( cellAlign ) => cellAlign === 'center' ), 'not implemented' ); + _.assert( o.topHead === null || _.all( o.topHead, ( h ) => _.strIs( o.topHead ) ) ); + _.assert( o.bottomHead === null || _.all( o.bottomHead, ( h ) => _.strIs( o.bottomHead ) ) ); + _.assert( o.leftHead === null || _.all( o.leftHead, ( h ) => _.strIs( o.leftHead ) ) ); + _.assert( o.rightHead === null || _.all( o.rightHead, ( h ) => _.strIs( o.rightHead ) ) ); + _.assert( o.cellAlign.length === 2 ); + _.assert( _.numbersAreAll( o.rowHeight ) ); + _.assert( _.numbersAreAll( o.colWidth ) ); + _.assert( _.all( o.bottomHead, ( h ) => h === null ), 'not implemented' ); + _.assert( _.all( o.leftHead, ( h ) => h === null ), 'not implemented' ); + _.assert( _.all( o.rightHead, ( h ) => h === null ), 'not implemented' ); + _.assert( o.cellAlign[ 0 ] === 'center' && o.cellAlign[ 1 ] === 'center', 'not implemented' ); + _.assert( o.cellPadding.length === 4 ); + _.assert( o.tablePadding.length === 4 ); + _.routineIs( o.onCellGet ); + _.routineIs( o.onCellDrawAfter ); + _.assert + ( + _.all( o.minColWidth, ( n ) => n === null || _.numberIs( n ) ) + , () => 'Expects number or null {- o.minColWidth -}' + ); + _.assert + ( + _.all( o.maxColWidth, ( n ) => n === null || _.numberIs( n ) ) + , () => 'Expects number or null {- o.maxColWidth -}' + ); + _.assert + ( + _.all( o.minRowHeight, ( n ) => n === null || _.numberIs( n ) ) + , () => 'Expects number or null {- o.minRowHeight -}' + ); + _.assert + ( + _.all( o.maxRowHeight, ( n ) => n === null || _.numberIs( n ) ) + , () => 'Expects number or null {- o.maxRowHeight -}' + ); + + tableDraw(); + + delete o.i2d; + delete o.sz; + delete o.lines; + + return o; + + /* */ + + function sizeEval() + { + let h = _.longSlice( o.rowHeight ); + let w = _.longSlice( o.colWidth ); + + for( let i = 0 ; i < o.dim[ 0 ] ; i++ ) + if( h[ i ] === undefined || h[ i ] === null ) + { + o.rowHeight[ i ] = null; + h[ i ] = 0; + } + + for( let j = 0 ; j < o.dim[ 1 ] ; j++ ) + if( w[ j ] === undefined || w[ j ] === null ) + { + o.colWidth[ j ] = null; + w[ j ] = 0; + } + + let i2d = []; + for( let i = 0 ; i < o.dim[ 0 ] ; i++ ) + { + i2d[ 0 ] = i; + for( let j = 0 ; j < o.dim[ 1 ] ; j++ ) + { + i2d[ 1 ] = j; + let e = cellGet( i2d ); + let sz = _.strLinesSize({ src : e, onLength : o.onLength }); + if( o.rowHeight[ i ] === null ) + h[ i ] = Math.max( h[ i ], sz[ 0 ] ); + if( o.colWidth[ j ] === null ) + w[ j ] = Math.max( w[ j ], sz[ 1 ] ); + } + } + + for( let i = 0 ; i < o.dim[ 0 ] ; i++ ) + { + if( o.minRowHeight[ i ] ) + { + _.assert( 0, 'not tested' ); + h[ i ] = Math.max( h[ i ], o.minRowHeight[ i ] ); + } + if( o.maxRowHeight[ i ] ) + { + _.assert( 0, 'not tested' ); + h[ i ] = Math.min( h[ i ], o.maxRowHeight[ i ] ); + } + } + + for( let j = 0 ; j < o.dim[ 1 ] ; j++ ) + { + if( o.minColWidth[ j ] ) + { + _.assert( 0, 'not tested' ); + w[ j ] = Math.max( w[ j ], o.minColWidth[ j ] ); + } + if( o.maxColWidth[ j ] ) + { + _.assert( 0, 'not tested' ); + w[ j ] = Math.min( w[ j ], o.maxColWidth[ j ] ); + } + } + + o.rowHeight = h; + o.colWidth = w; + } + + /* */ + + function borderTopDraw( it ) + { + border( o.ltThickToken ); + if( o.withBorder && o.tThickToken ) + for( let j = 0 ; j < o.dim[ 1 ] ; j++ ) + { + for( let k = o.colWidth[ j ]-1 ; k >= 0 ; k-- ) + { + o.result += o.tThickToken; + } + + if( o.ncToken && j < o.dim[ 1 ] -1 ) + for( let k = lengthOf( o.ncToken )-1 ; k >= 0 ; k-- ) + { + o.result += o.tThickToken; + } + if( o.lThinToken && colSplitHas( j ) ) + for( let k = lengthOf( o.lThinToken )-1 ; k >= 0 ; k-- ) + { + o.result += o.tTlikeThickToken; + } + } + border( o.rtThickToken ); + border( o.nlToken ); + } + + /* */ + + function borderBottomDraw( it ) + { + border( o.nlToken ); + border( o.lbThickToken ); + if( o.withBorder && o.bThickToken ) + for( let j = 0 ; j < o.dim[ 1 ] ; j++ ) + { + for( let k = o.colWidth[ j ]-1 ; k >= 0 ; k-- ) + { + o.result += o.bThickToken; + } + + if( o.ncToken && j < o.dim[ 1 ] -1 ) + for( let k = lengthOf( o.ncToken )-1 ; k >= 0 ; k-- ) + { + o.result += o.bThickToken; + } + if( o.lThinToken && colSplitHas( j ) ) + for( let k = lengthOf( o.lThinToken )-1 ; k >= 0 ; k-- ) + { + o.result += o.bTlikeThickToken; + } + } + border( o.rbThickToken ); + } + + /* */ + + function tableDraw() + { + let it = o; + it.i2d = []; + it.sz = []; + it.lines = []; + + borderTopDraw( it ); + + for( let i = 0 ; i < o.dim[ 0 ] ; i++ ) + { + it.i2d[ 0 ] = i; + it.sz[ 0 ] = o.rowHeight[ i ]; + + for( let j = 0 ; j < o.dim[ 1 ] ; j++ ) + { + it.i2d[ 1 ] = j; + it.sz[ 1 ] = o.colWidth[ j ]; + linesPredraw( it ); + } + + linesDraw( it ); + rowSplitDraw( it ); + + } + + borderBottomDraw(); + + } + + /* */ + + function colSplitHas( j ) + { + if( !o.colSplits ) + return false; + if( j >= o.dim[ 1 ]-1 ) + return false; + if( _.boolLikeTrue( o.colSplits ) ) + return true; + return _.longHas( o.colSplits, j ); + } + + /* */ + + function rowSplitDraw( it ) + { + if( !o.withBorder || !o.rowSplits ) + return; + if( _.longIs( o.rowSplits ) && !_.longHas( o.rowSplits, it.i2d[ 0 ] ) ) + return; + if( it.i2d[ 0 ] === o.dim[ 0 ] - 1 ) + return; + border( o.nlToken ); + border( o.lTlikeThickToken ); + for( let j = 0 ; j < o.dim[ 1 ] ; j++ ) + { + for( let k = o.colWidth[ j ]-1 ; k >= 0 ; k-- ) + { + o.result += o.tThinToken; + } + if( o.ncToken && j < o.dim[ 1 ] ) + for( let k = lengthOf( o.ncToken )-1 ; k >= 0 ; k-- ) + { + o.result += o.tThinToken; + } + if( o.lThinToken && colSplitHas( j ) ) + for( let k = lengthOf( o.lThinToken )-1 ; k >= 0 ; k-- ) + { + o.result += o.xThinToken; + } + } + border( o.rTlikeThickToken ); + } + + /* */ + + function linesPredraw( it ) + { + it.cellOriginal = cellGet( it.i2d ); + it.cellDrawn = it.onCellDraw( it ); + it.cellDrawn = it.onCellDrawAfter( it ); + if( _.longIs( it.cellDrawn ) ) + { + it.cellDrawn.forEach( ( cellDrawn, k ) => + { + _.assert( _.strIs( cellDrawn ) ); + it.lines[ k ] = it.lines[ k ] || []; + it.lines[ k ].push( cellDrawn ); + if( it.ncToken && it.i2d[ 1 ] < o.dim[ 1 ]-1 ) + it.lines[ k ].push( it.ncToken ); + if( it.lThinToken && it.i2d[ 1 ] < o.dim[ 1 ]-1 && colSplitHas( it.i2d[ 1 ] ) ) + it.lines[ k ].push( it.lThinToken ); + }); + } + else + { + _.assert( _.strIs( it.cellDrawn ) ); + it.lines[ 0 ] = it.lines[ 0 ] || []; + it.lines[ 0 ].push( it.cellDrawn ); + if( it.ncToken && it.i2d[ 1 ] < o.dim[ 1 ]-1 ) + it.lines[ 0 ].push( it.ncToken ); + if( it.lThinToken && it.i2d[ 1 ] < o.dim[ 1 ]-1 && colSplitHas( it.i2d[ 1 ] ) ) + it.lines[ 0 ].push( it.lThinToken ); + } + } + + /* */ + + function linesDraw( it ) + { + it.lines.forEach( ( line, k ) => + { + if( it.nlToken ) + if( it.i2d[ 0 ] > 0 || k > 0 ) + it.result += it.nlToken; + border( o.lThickToken ); + it.result += line.join( '' ); + border( o.rThickToken ); + }); + it.lines.splice( 0, it.lines.length ); + } + + /* */ + + function cellDraw( it ) + { + let sz = _.strLinesSize({ src : it.cellOriginal, onLength : o.onLength }); + + if( it.sz[ 0 ] > 1 ) + { + let lines = _.strLinesSplit( it.cellOriginal ); + let hf = ( it.sz[ 0 ] - lines.length ) / 2; + let result = _.filter_( null, lines, ( line, k ) => + { + if( k < it.sz[ 0 ] - 1 || it.sz[ 0 ] === 1 || ( k === it.sz[ 0 ] - 1 && sz[ 0 ] <= it.sz[ 0 ] ) ) + return cellRowDraw( line, it ); + else if( k === it.sz[ 0 ] - 1 ) + return cellRowDraw( o.moreToken, it ); + }); + for( let k = Math.floor( hf )-1 ; k >= 0 ; k-- ) + result.unshift( _.strDup( it.spaceToken, it.sz[ 1 ] ) ); + for( let k = Math.ceil( hf )-1 ; k >= 0 ; k-- ) + result.push( _.strDup( it.spaceToken, it.sz[ 1 ] ) ); + return result; + } + + return cellRowDraw( it.cellOriginal, it );; + } + + /* */ + + function cellRowDraw( line, it ) + { + + _.assert( _.strIs( line ) ); + + let l = lengthOf( line ); + if( l < it.sz[ 1 ] ) + { + let hf = ( it.sz[ 1 ] - l ) / 2; + return _.strDup( it.spaceToken, Math.ceil( hf ) ) + line + _.strDup( it.spaceToken, Math.floor( hf ) ); + } + else + { + // return _.strShort_ + // ({ + // src : line, + // widthLimit : it.sz[ 1 ], + // onLength : o.onLength, + // }); + let lineDescriptor = _.strShort_ + ({ + src : line, + widthLimit : it.sz[ 1 ], + onLength : o.onLength, + }); + return lineDescriptor.result; + } + + } + + /* */ + + function border( token ) + { + if( o.withBorder && token ) + o.result += token; + } + + /* */ + + function cellGet( i2d ) + { + let e = o.onCellGet( i2d, o ); + _.assert( _.primitiveIs( e ) && e !== undefined, () => `Cell ${i2d} is ${_.entity.strType( e )}` ); + e = String( e ); + return e; + } + + /* */ + + function scalarToVector( src, length ) + { + if( _.mapIs( src ) ) + return sideMapToArray( sideMap, length ) + return _.scalarToVector( src, length ); + } + + /* */ + + function sideMapToArray( sideMap, length ) + { + let result = _.dup( null, length ); + _.assert( _.object.isBasic( sideMap ) ); + _.assert( 0, 'not tested' ); + for( let s in sideMap ) + { + _.assert( _.Side[ s ] >= 0, () => `Unknown side ${s}` ); + result[ _.Side[ s ] ] = sideMap[ s ]; + } + return result; + } + + /* */ + + function lengthOf( src ) + { + let l = o.onLength ? o.onLength( src ) : src.length; + return l; + } + + /* */ + + function headsIntegrate() + { + let o2 = _.props.extend( null, o ); + + o2.onCellGet = onCellGetWithHeads_functor(); + o2.topHead = null; + o2.bottomHead = null; + o2.leftHead = null; + o2.rightHead = null; + o2.dim = _.array.slice( o2.dim ); + + if( o.topHead ) + { + o2.dim[ 0 ] += 1; + if( _.longIs( o2.rowHeight ) ) + { + o2.rowHeight = _.array.slice( o2.rowHeight ); + o2.rowHeight.unshift( null ); + } + if( _.longIs( o2.minRowHeight ) ) + { + o2.minRowHeight = _.array.slice( o2.minRowHeight ); + o2.minRowHeight.unshift( null ); + } + if( _.longIs( o2.maxRowHeight ) ) + { + o2.maxRowHeight = _.array.slice( o2.maxRowHeight ); + o2.maxRowHeight.unshift( null ); + } + if( _.longIs( o2.rowSplits ) ) + { + o2.rowSplits = o2.rowSplits.map( ( e ) => e+1 ); + } + else + { + let val = o2.rowSplits; + o2.rowSplits = []; + if( val ) + { + for( let i = 1 ; i < o.dim[ 0 ] ; i++ ) + o2.rowSplits.push( i ); + } + } + o2.rowSplits.unshift( 0 ); + } + + if( o.bottomHead ) + { + o2.dim[ 0 ] += 1; + if( _.longIs( o2.rowHeight ) ) + { + o2.rowHeight = _.array.slice( o2.rowHeight ); + o2.rowHeight.push( null ); + } + if( _.longIs( o2.minRowHeight ) ) + { + o2.minRowHeight = _.array.slice( o2.minRowHeight ); + o2.minRowHeight.push( null ); + } + if( _.longIs( o2.maxRowHeight ) ) + { + o2.maxRowHeight = _.array.slice( o2.maxRowHeight ); + o2.maxRowHeight.push( null ); + } + if( _.longIs( o2.rowSplits ) ) + { + o2.rowSplits = _.array.slice( o2.rowSplits ); + } + else + { + let val = o2.rowSplits; + o2.rowSplits = []; + if( val ) + { + for( let i = 0 ; i < o.dim[ 0 ]-1 ; i++ ) + o2.rowSplits.push( i ); + } + } + o2.rowSplits.push( o2.dim[ 0 ]-2 ); + } + + if( o.leftHead ) + { + o2.dim[ 1 ] += 1; + if( _.longIs( o2.colWidth ) ) + { + o2.colWidth = _.array.slice( o2.colWidth ); + o2.colWidth.unshift( null ); + } + if( _.longIs( o2.minColWidth ) ) + { + o2.minColWidth = _.array.slice( o2.minColWidth ); + o2.minColWidth.unshift( null ); + } + if( _.longIs( o2.maxColWidth ) ) + { + o2.maxColWidth = _.array.slice( o2.maxColWidth ); + o2.maxColWidth.unshift( null ); + } + if( _.longIs( o2.colSplits ) ) + { + o2.colSplits = o2.colSplits.map( ( e ) => e+1 ); + } + else + { + let val = o2.colSplits; + o2.colSplits = []; + if( val ) + { + for( let i = 1 ; i < o.dim[ 1 ] ; i++ ) + o2.colSplits.push( i ); + } + } + o2.colSplits.unshift( 0 ); + } + + if( o.rightHead ) + { + o2.dim[ 1 ] += 1; + if( _.longIs( o2.colWidth ) ) + { + o2.colWidth = _.array.slice( o2.colWidth ); + o2.colWidth.push( null ); + } + if( _.longIs( o2.minColWidth ) ) + { + o2.minColWidth = _.array.slice( o2.minColWidth ); + o2.minColWidth.push( null ); + } + if( _.longIs( o2.maxColWidth ) ) + { + o2.maxColWidth = _.array.slice( o2.maxColWidth ); + o2.maxColWidth.push( null ); + } + if( _.longIs( o2.colSplits ) ) + { + o2.colSplits = _.array.slice( o2.colSplits ); + } + else + { + let val = o2.colSplits; + o2.colSplits = []; + if( val ) + { + for( let i = 0 ; i < o.dim[ 1 ]-1 ; i++ ) + o2.colSplits.push( i ); + } + } + o2.colSplits.push( o2.dim[ 1 ]-2 ); + } + + _.assert + ( + o.topHead === null || o.topHead.length === o2.dim[ 1 ], + () => `topHead should have ${o2.dim[ 1 ]} elements, but have ${o.topHead.length}` + ); + _.assert + ( + o.bottomHead === null || o.bottomHead.length === o2.dim[ 1 ], + () => `bottomHead should have ${o2.dim[ 1 ]} elements, but have ${o.bottomHead.length}` + ); + _.assert + ( + o.leftHead === null || o.leftHead.length === o2.dim[ 0 ], + () => `leftHead should have ${o2.dim[ 0 ]} elements, but have ${o.leftHead.length}` + ); + _.assert + ( + o.rightHead === null || o.rightHead.length === o2.dim[ 0 ], + () => `rightHead should have ${o2.dim[ 0 ]} elements, but have ${o.rightHead.length}` + ); + + _.strTable( o2 ); + + o.result = o2.result; + + return o; + } + + function onCellGetWithHeads_functor() + { + let i2d0 = []; + let d = [ 0, 0 ] + if( o.topHead ) + d[ 0 ] = 1; + if( o.leftHead ) + d[ 1 ] = 1; + + return function onCellGetWithHeads( i2d, o2 ) + { + + if( o.topHead ) + if( i2d[ 0 ] === 0 ) + return o.topHead[ i2d[ 1 ] ]; + if( o.bottomHead ) + if( i2d[ 0 ] === o2.dim[ 0 ]-1 ) + return o.bottomHead[ i2d[ 1 ] ]; + if( o.leftHead ) + if( i2d[ 1 ] === 0 ) + return o.leftHead[ i2d[ 0 ] ]; + if( o.rightHead ) + if( i2d[ 1 ] === o2.dim[ 1 ]-1 ) + return o.rightHead[ i2d[ 0 ] ]; + + i2d0[ 0 ] = i2d[ 0 ] - d[ 0 ]; + i2d0[ 1 ] = i2d[ 1 ] - d[ 1 ]; + + return o.onCellGet( i2d0, o ); + } + + } + + /* */ + + function onCellGetDefault( i2d, o ) + { + let iFlat = i2d[ 1 ] + i2d[ 0 ]*o.dim[ 1 ]; + return o.data[ iFlat ]; + } + + /* */ + + function onCellDrawAfterDefault( it ) + { + return it.cellDrawn; + } +} + +strTable.defaults = +{ + data : null, + dim : null, + topHead : null, + bottomHead : null, + leftHead : null, + rightHead : null, + rowHeight : null, + minRowHeight : null, /* qqq : cover */ + maxRowHeight : null, /* qqq : cover */ + colWidth : null, + minColWidth : null, /* qqq : cover */ + maxColWidth : null, /* qqq : cover */ + rowSplits : null, + colSplits : null, + /* qqq : implement option tableWidth */ + /* qqq : implement option tableHeight */ + /* qqq : implement option minTableWidth */ + /* qqq : implement option minTableHeight */ + /* qqq : implement option maxTableWidth */ + /* qqq : implement option maxTableHeight */ + + /* qqq : cover topHead and other options in vector form having value { left, right, top, bottom } */ + + result : '', + cellAlign : 'center', /* qqq : implement and cover */ + cellPadding : null, /* qqq : implement and cover */ + tablePadding : null, /* qqq : implement and cover */ + onCellGet : null, + onCellDraw : null, + onCellDrawAfter : null, /* qqq : cover */ + onLength : null, + + style : 'borderless', + withBorder : null, /* qqq : cover */ + spaceToken : null, + ncToken : null, + nlToken : null, + moreToken : null, /* qqq : cover */ + + lThickToken : null, + rThickToken : null, + tThickToken : null, + bThickToken : null, + ltThickToken : null, + rtThickToken : null, + lbThickToken : null, + rbThickToken : null, + lTlikeThickToken : null, + rTlikeThickToken : null, + tTlikeThickToken : null, + bTlikeThickToken : null, + xThickToken : null, + + lThinToken : null, + rThinToken : null, + tThinToken : null, + bThinToken : null, + ltThinToken : null, + rtThinToken : null, + lbThinToken : null, + rbThinToken : null, + lTlikeThinToken : null, + rTlikeThinToken : null, + tTlikeThinToken : null, + bTlikeThinToken : null, + xThinToken : null, +}; + +strTable.style = Object.create( null ); + +strTable.style.borderless = +{ + withBorder : 0, + spaceToken : ' ', + ncToken : '\t', + nlToken : '\n', + moreToken : '...', +}; + +strTable.style.doubleBorder = +{ + withBorder : 1, + spaceToken : ' ', + ncToken : '', + nlToken : '\n', + moreToken : '...', + + lThickToken : '║', + rThickToken : '║', + tThickToken : '═', + bThickToken : '═', + ltThickToken : '╔', + rtThickToken : '╗', + lbThickToken : '╚', + rbThickToken : '╝', + lTlikeThickToken : '╟', + rTlikeThickToken : '╢', + tTlikeThickToken : '╤', + bTlikeThickToken : '╧', + xThickToken : '╬', + + lThinToken : '│', + rThinToken : '│', + tThinToken : '─', + bThinToken : '─', + ltThinToken : '┌', + rtThinToken : '┐', + lbThinToken : '└', + rbThinToken : '┘', + lTlikeThinToken : '├', + rTlikeThinToken : '┤', + tTlikeThinToken : '┬', + bTlikeThinToken : '┴', + xThinToken : '┼', +}; + +strTable.style.border = /* qqq : cover style ( lightly ) */ +{ + withBorder : 1, + spaceToken : ' ', + ncToken : '', + nlToken : '\n', + moreToken : '...', + + lThickToken : '│', + rThickToken : '│', + tThickToken : '─', + bThickToken : '─', + ltThickToken : '┌', + rtThickToken : '┐', + lbThickToken : '└', + rbThickToken : '┘', + lTlikeThickToken : '├', + rTlikeThickToken : '┤', + tTlikeThickToken : '┬', + bTlikeThickToken : '┴', + xThickToken : '┼', + + lThinToken : '│', + rThinToken : '│', + tThinToken : '─', + bThinToken : '─', + ltThinToken : '┌', + rtThinToken : '┐', + lbThinToken : '└', + rbThinToken : '┘', + lTlikeThinToken : '├', + rTlikeThinToken : '┤', + tTlikeThinToken : '┬', + bTlikeThinToken : '┴', + xThinToken : '┼', +}; + +// + +// function strTable_old( o ) +// { +// _.assert( arguments.length === 1, 'Expects single argument' ); +// +// if( !_.object.isBasic( o ) ) +// o = { data : o } +// _.routine.options_( strTable_old,o ); +// _.assert( _.longIs( o.data ) ); +// +// if( typeof module !== 'undefined' ) +// { +// if( !_.cliTable ) +// try +// { +// _.cliTable = require( 'cli-table2' ); +// } +// catch( err ) +// { +// } +// } +// +// if( _.cliTable == undefined ) +// { +// if( !o.silent ) +// throw _.err( 'version of strTable_old without support of cli-table2 is not implemented' ); +// else +// return; +// } +// +// /* */ +// +// let isArrayOfArrays = true; +// let maxLen = 0; +// for( let i = 0; i < o.data.length; i++ ) +// { +// if( !_.longIs( o.data[ i ] ) ) +// { +// isArrayOfArrays = false; +// break; +// } +// +// maxLen = Math.max( maxLen, o.data[ i ].length ); +// } +// +// let onCellGet = strTable_old.onCellGet; +// o.onCellGet = o.onCellGet || isArrayOfArrays ? onCellGet.ofArrayOfArray : onCellGet.ofFlatArray ; +// o.onCellAfter = o.onCellAfter || strTable_old.onCellAfter; +// +// if( isArrayOfArrays ) +// { +// o.rowsNumber = o.data.length; +// o.colsNumber = maxLen; +// } +// else +// { +// _.assert( _.numberIs( o.rowsNumber ) && _.numberIs( o.colsNumber ) ); +// } +// +// /* */ +// +// makeWidth( 'colWidths', o.colWidth, o.colsNumber ); +// makeWidth( 'colAligns', o.colAlign, o.colsNumber ); +// makeWidth( 'rowWidths', o.rowWidth, o.rowsNumber ); +// makeWidth( 'rowAligns', o.rowAlign, o.rowsNumber ); +// +// let tableOptions = +// { +// head : o.head, +// colWidths : o.colWidths, +// rowWidths : o.rowWidths, +// colAligns : o.colAligns, +// rowAligns : o.rowAligns, +// style : +// { +// compact : !!o.compact, +// 'padding-left' : o.paddingLeft, +// 'padding-right' : o.paddingRight, +// } +// } +// +// let table = new _.cliTable( tableOptions ); +// +// /* */ +// +// for( let y = 0; y < o.rowsNumber; y++ ) +// { +// let row = []; +// table.push( row ); +// +// for( let x = 0; x < o.colsNumber; x++ ) +// { +// let index2d = [ y, x ]; +// let cellData = o.onCellGet( o.data, index2d, o ); +// let cellStr; +// +// if( cellData === undefined ) +// cellData = cellStr = ''; +// else +// cellStr = _.entity.exportString( cellData, { wrap : 0, stringWrapper : '' } ); +// +// cellStr = o.onCellAfter( cellStr, index2d, o ); +// row.push( cellStr ); +// } +// } +// +// return table.toString(); +// +// /* */ +// +// function makeWidth( propertyName, def, len ) +// { +// let property = o[ propertyName ]; +// let _property = _.longFill( [], def, len ); +// if( property ) +// { +// _.assert( _.mapIs( property ) || _.longIs( property ) , 'routine expects colWidths/rowWidths property as Object or Array-Like' ); +// for( let k in property ) +// { +// k = _.numberFrom( k ); +// if( k < len ) +// { +// _.assert( _.numberIs( property[ k ] ) ); +// _property[ k ] = property[ k ]; +// } +// } +// } +// o[ propertyName ] = _property; +// } +// +// } +// +// strTable_old.defaults = + +// { +// data : null, +// rowsNumber : null, +// colsNumber : null, +// +// head : null, +// +// rowWidth : 5, +// rowWidths : null, +// rowAlign : 'center', +// rowAligns : null, +// +// colWidth : 5, +// colWidths : null, +// colAlign : 'center', +// colAligns : null, +// +// compact : 1, +// silent : 1, +// +// paddingLeft : 0, +// paddingRight : 0, +// +// onCellGet : null, +// onCellAfter : null, +// } +// +// strTable_old.onCellGet = +// { +// ofFlatArray : ( data, index2d, o ) => data[ index2d[ 0 ] * o.colsNumber + index2d[ 1 ] ], +// ofArrayOfArray : ( data, index2d, o ) => data[ index2d[ 0 ] ][ index2d[ 1 ] ] +// } +// +// strTable_old.onCellAfter = ( cellStr, index2d, o ) => cellStr + +// + +function strsSort( srcs ) +{ + + _.assert( _.strsAreAll( srcs ) ); + + let result = srcs.sort( function( a, b ) + { + if( a < b ) + return -1; + if( a > b ) + return +1; + return 0; + }); + + return result; +} + +// + +function strSimilarity( src1, src2 ) +{ + _.assert( _.strIs( src1 ) ); + _.assert( _.strIs( src2 ) ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + + let spectres = [ _.strLattersSpectre( src1 ), _.strLattersSpectre( src2 ) ]; + let result = _.strLattersSpectresSimilarity( spectres[ 0 ], spectres[ 1 ] ); + + return result; +} + +// + +function strLattersSpectre( src ) +{ + let total = 0; + let result = new U32x( 257 ); + + _.assert( arguments.length === 1 ); + + for( let s = 0 ; s < src.length ; s++ ) + { + let c = src.charCodeAt( s ); + result[ c & 0xff ] += 1; + total += 1; + c = c >> 8; + if( c === 0 ) + continue; + result[ c & 0xff ] += 1; + total += 1; + if( c === 0 ) + continue; + result[ c & 0xff ] += 1; + total += 1; + if( c === 0 ) + continue; + result[ c & 0xff ] += 1; + total += 1; + } + + result[ 256 ] = total; + + return result; +} + +// + +function strLattersSpectresSimilarity( src1, src2 ) +{ + let result = 0; + let minl = Math.min( src1[ 256 ], src2[ 256 ] ); + let maxl = Math.max( src1[ 256 ], src2[ 256 ] ); + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( src1.length === src2.length ); + + for( let s = 0 ; s < src1.length-1 ; s++ ) + result += Math.abs( src1[ s ] - src2[ s ] ); + + result = ( minl / maxl ) - ( 0.5 * result / maxl ); + + result = _.numberClamp( result, [ 0, 1 ] ); + + return result; +} + +// +// +// function lattersSpectreComparison( src1,src2 ) +// { +// +// let same = 0; +// +// if( src1.length === 0 && src2.length === 0 ) return 1; +// +// for( let l in src1 ) +// { +// if( l === 'length' ) continue; +// if( src2[ l ] ) same += Math.min( src1[ l ],src2[ l ] ); +// } +// +// return same / Math.max( src1.length,src2.length ); +// } + +// -- +// declare +// -- + +let Side = +{ + top : 0, + right : 1, + bottom : 2, + left : 3, + vertical : 0, + horizontal : 1, +} + +let Extension = +{ + + // strDecamelize, /* qqq : implement */ + strCamelize, + strToTitle, + + strFilenameFor, + strVarNameFor, + strHtmlEscape, + + strSearch, /* xxx : move out? */ + strSearchLog, /* qqq2 : cover please */ + strSearchReplace, /* qqq2 : cover please */ + + strFindAll, + + TokensSyntax, + tokensSyntaxFrom, + + _strReplaceMapPrepare, + strReplaceAll, + strTokenizeJs, + strTokenizeCpp, + + strSubs, // xxx : rename + + strSorterParse, + jsonParse, + + // format + + strToBytes, + strMetricFormat, + strMetricFormatBytes, + + strTimeFormat, + + strCsvFrom, /* experimental */ + // strToDom, /* experimental */ // qqq xxx : move it out + strToConfig, /* experimental */ + + // numberFromStrMaybe, + strStructureParse, + strWebQueryParse, + strWebQueryStr, + strRequestParse, + strRequestStr, + strCommandParse, + strCommandsParse, + + strJoinMap, + + strTable, + // strTable_old, + strsSort, + + strSimilarity, /* experimental */ + strLattersSpectre, /* experimental */ + strLattersSpectresSimilarity, + // lattersSpectreComparison, /* experimental */ + + // fields + + // split, + Side, + +} + +_.props.extend( _, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +{ + require( './Dissector.s' ); +} + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wstringsextra/proto/wtools/abase/l5/StringTools.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wstringsextra/proto/wtools/abase/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, StringTools_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file StringTools_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wtraverser/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wtraverser/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wtraverser */ ( function wtraverser() { function wtraverser_naked() { +module.exports = require( '../wtools/abase/l4/Traverser.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wTraverser', 'wtraverser' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wtraverser/proto/node_modules/wtraverser' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wtraverser/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wtraverser_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wtraverser */ })(); + +/* */ /* begin of file Traverser_s */ ( function Traverser_s() { function Traverser_s_naked() { ( function _Taverser_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to traverse data structures, no matter how compex and cycled them are. Traverser may be used to inspect data, make some transformation or duplication. Traverser relies on class relations definition for traversing. Use the module to traverse your data. + @module Tools/base/Traverser + @extends Tools +*/ + +/** + * */ + +/** + * Collection of cross-platform routines to traverse data structures, no matter how compex and cycled them are. +*/ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + + _.include( 'wProto' ); + +} + +const _global = _global_; +const _ = _global_.wTools; + +_.assert( _.routineIs( _.workpiece.instanceIsStandard ) ); + +// -- +// implementation +// -- + +var TraverseIterator = Object.create( null ); + +// + +TraverseIterator.iterationClone = function iterationClone() +{ + _.assert( arguments.length === 0, 'Expects no arguments' ); + var newIteration = Object.create( this ); + return newIteration; +} + +// + +TraverseIterator.iterationNew = function iterationNew( key ) +{ + var it = this; + var iterator = this.iterator; + var result = Object.create( iterator ); + + _.assert( arguments.length === 0 || arguments.length === 1 ); + _.assert( _.numberIs( it.copyingDegree ) ); + + result.iterationPrev = it; + + // if( it !== iterator ) + // { + // result.down = it; + // + // result.path = null; + // result.level = it.level; + // result.copyingDegree = it.copyingDegree; + // + // result.proto = null; + // result.dst = null; + // result.src = null; + // result.key = null; + // + // result.customFields = null; + // result.dropFields = null; + // result.screenFields = null; + // } + // else + // { + // result.down = null; + // + // result.level = iterator.level; + // result.copyingDegree = iterator.copyingDegree; + // + // result.proto = iterator.proto; + // result.dst = iterator.dst; + // result.src = iterator.src; + // result.key = iterator.key; + // result.path = iterator.path ? iterator.path : '/'; + // + // result.customFields = iterator.customFields; + // result.dropFields = iterator.dropFields; + // result.screenFields = iterator.screenFields; + // } + + if( it === iterator ) + { + result.down = null; + + result.level = iterator.level; + result.copyingDegree = iterator.copyingDegree; + + result.proto = iterator.proto; + result.dst = iterator.dst; + result.src = iterator.src; + result.key = iterator.key; + result.path = iterator.path ? iterator.path : '/'; + + result.customFields = iterator.customFields; + result.dropFields = iterator.dropFields; + result.screenFields = iterator.screenFields; + } + else + { + result.down = it; + + result.path = null; + result.level = it.level; + result.copyingDegree = it.copyingDegree; + + result.proto = null; + result.dst = null; + result.src = null; + result.key = null; + + result.customFields = null; + result.dropFields = null; + result.screenFields = null; + } + + /* */ + + _.assert( _.object.isBasic( result.iterator ) ); + + if( key !== undefined ) + result.select( key ); + + return result; +} + +// + +TraverseIterator.select = function select( key ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( this.path === null ); + + this.src = this.iterationPrev.src[ key ]; + this.key = key; + this.path = this.iterationPrev.path === '/' ? '/' + key : this.iterationPrev.path + '/' + key; + + this.level = this.level+1; + + if( this.copyingDegree === 2 ) + this.copyingDegree -= 1; + + return this; +} + +// + +function _traverseIterator( o ) +{ + var iterator = Object.create( TraverseIterator ); + + _.props.extend( iterator, o ); + + iterator.rootSrc = o.rootSrc || o.src; + iterator.iterator = iterator; + + iterator.onCompactField = iterator.onCompactField || function compact( it, eit ) + { + if( it.proto && it.proto.compactField ) + { + return it.proto.compactField.call( it.src, eit ); + } + else + { + if( _.instanceIs( eit.down.src ) ) + if( eit.dst === null || eit.dst === undefined ) + return; + } + return eit.dst; + } + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( iterator.level === 0 ); + _.assert( iterator.copyingDegree >= 0 ); + _.assert( iterator.iterator === iterator ); + _.routine.assertOptions( _traverseIterator, o ); + + Object.preventExtensions( iterator ); + + return iterator; +} + +// + +function _traverseIteration( o ) +{ + _.assert( _.mapIs( o ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + var iterator = _traverseIterator( o ); + var it = iterator.iterationNew();; + + return it; +} + +// + +function _traverser( routine, o ) +{ + var routine = _traverser; + + _.assert( _.routineIs( routine ) ); + _.assert( _.object.isBasic( routine.iterationDefaults ) ); + _.assert( !routine.iteratorDefaults ); + _.assert( _.object.isBasic( routine.defaults ) ); + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.routine.options_( routine, o ); + _.map.assertHasNoUndefine( o ); + _.assert( _.object.isBasic( o ) ); + + /* */ + + o.iterationDefaults = routine.iterationDefaults; + o.defaults = routine.defaults; + + o.onMapUp = _.routinesComposeAll( o.onMapUp ); + o.onMapElementUp = _.routinesComposeAll( o.onMapElementUp ); + o.onMapElementDown = _.routinesCompose( o.onMapElementDown ); + o.onArrayUp = _.routinesComposeAll( o.onArrayUp ); + o.onArrayElementUp = _.routinesComposeAll( o.onArrayElementUp ); + o.onArrayElementDown = _.routinesCompose( o.onArrayElementDown ); + o.onBuffer = _.routinesComposeAll( o.onBuffer ); + o.onSet = _.routinesComposeAll( o.onSet ); + + var it = _traverseIteration( o ); + + return it; +} + +_traverser.iterationDefaults = +{ + + src : null, + key : null, + dst : null, + proto : null, + level : 0, + path : '', + customFields : null, + dropFields : null, + screenFields : null, + instanceAsMap : 0, + usingInstanceCopy : 1, + compact : 0, + + copyingDegree : 3, + +} + +_traverser.defaults = +{ + + copyingComposes : 3, + copyingAggregates : 1, + copyingAssociates : 1, + copyingMedials : 0, + // copyingMedialRestricts : 1, + copyingMedialRestricts : 0, + copyingRestricts : 0, + copyingBuffers : 3, + copyingCustomFields : 0, + + rootSrc : null, + levels : 999, + technique : null, + deserializing : 0, + + onEntityUp : null, + onEntityDown : null, + onContainerUp : null, + onContainerDown : null, + + onHashMap : null, + onDate : null, + onString : null, + onRegExp : null, + onRoutine : null, + onBuffer : null, + onSet : null, + onInstanceCopy : null, + onCompactField : null, + + onMapUp : null, + onMapElementUp : null, + onMapElementDown : null, + onArrayUp : null, + onArrayElementUp : null, + onArrayElementDown : null, + +} + +_.props.extend( _traverser.defaults, _traverser.iterationDefaults ); + +_traverseIterator.defaults = Object.create( _traverser.defaults ); +_traverseIterator.defaults.defaults = null; +_traverseIterator.defaults.iterationDefaults = null; + +// + +function _traverseEntityUp( it ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( it.onEntityUp ) + { + var c = it.onEntityUp( it ); + _.assert( c === undefined || c === false ); + if( c === false ) + return false; + } + + return true; +} + +// + +function _traverseEntityDown( it ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( it.onEntityDown ) + { + var c = it.onEntityDown( it ); + _.assert( c === undefined ); + } + +} + +// + +function _traverseMap( it ) +{ + var result; + + _.assert( it.copyingDegree >= 1 ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.objectLike( it.src ) || _.workpiece.instanceIsStandard( it.src ) ); + + /* */ + + if( it.onContainerUp ) + { + var c0 = it.onContainerUp( it ); + _.assert( c0 === undefined || c0 === false ); + if( c0 === false ) + return it.dst; + } + + var c1 = it.onMapUp( it ); + _.assert( c1 === false || _.arrayIs( c1 ) || c1 === _.dont ); + if( c1 === false || c1 === _.dont ) + return it.dst; + + /* */ + + var screen = it.screenFields ? it.screenFields : it.src; + + if( it.copyingDegree ) + for( var key in screen ) + { + + if( screen[ key ] === undefined ) + continue; + + if( it.src[ key ] === undefined ) + continue; + + if( it.dropFields ) + if( it.dropFields[ key ] !== undefined ) + continue; + + var mapLike = _.aux.is( it.src ) || it.instanceAsMap; + if( !mapLike && !it.screenFields ) + if( !Object.hasOwnProperty.call( it.src, key ) ) + { + continue; + } + + var newIteration = it.iterationNew( key ); + + // if( it.path === '/output' ) + // debugger; + + let c = it.onMapElementUp( it, newIteration ) ; + _.assert( c === false || c === _.dont || _.arrayIs( c ) ); + if( c === false || c === _.dont ) + continue; + + _traverseAct( newIteration ); + + it.onMapElementDown( it, newIteration ); + + } + + /* container down */ + + if( it.onContainerDown ) + { + var c = it.onContainerDown( it ); + _.assert( c === undefined ); + } + + /* */ + + return it.dst; +} + +// + +function _traverseArray( it ) +{ + + _.assert( it.copyingDegree >= 1 ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.longIs( it.src ) ); + _.assert( !_.bufferAnyIs( it.src ) ); + + /* */ + + if( it.onContainerUp ) + { + var c0 = it.onContainerUp( it ); + _.assert( c0 === undefined || c0 === false ); + if( c0 === false ) + return it.dst; + } + + var c1 = it.onArrayUp( it ); + _.assert( c1 === false || _.arrayIs( c1 ) ); + if( c1 === false ) + return it.dst; + + /* */ + + if( it.copyingDegree > 1 ) + { + for( var key = 0 ; key < it.src.length ; key++ ) + { + var newIteration = it.iterationNew( key ); + + if( it.onArrayElementUp( it, newIteration ) === false ) + continue; + + _traverseAct( newIteration ); + + it.onArrayElementDown( it, newIteration ); + } + } + + /* container down */ + + if( it.onContainerDown ) + { + var c = it.onContainerDown( it ); + _.assert( c === undefined ); + } + + return it.dst; +} + +// + +function _traverseBuffer( it ) +{ + it.copyingDegree = Math.min( it.copyingBuffers, it.copyingDegree ); + + _.assert( it.copyingDegree >= 1, 'not tested' ); + _.assert( !_.bufferNodeIs( it.src ), 'not tested' ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.bufferAnyIs( it.src ) ); + _.assert( it.copyingDegree > 0 ); + + if( it.onContainerUp ) + { + var c0 = it.onContainerUp( it ); + _.assert( c0 === undefined || c0 === false ); + if( c0 === false ) + return it.dst; + } + + /* buffer */ + + var c1 = it.onBuffer( it.src, it ); + _.assert( c1 === false || _.arrayIs( c1 ) ); + if( c1 === false ) + return it.dst; + + /* container down */ + + if( it.onContainerDown ) + { + var c = it.onContainerDown( it ); + _.assert( c === undefined ); + } + + return it.dst; +} + +// + +function _traverseSet( it ) +{ + it.copyingDegree = Math.min( it.copyingBuffers, it.copyingDegree ); + + _.assert( it.copyingDegree >= 1, 'not tested' ); + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.setIs( it.src ) ); + _.assert( it.copyingDegree > 0 ); + + if( it.onContainerUp ) + { + var c0 = it.onContainerUp( it ); + _.assert( c0 === undefined || c0 === false ); + if( c0 === false ) + return it.dst; + } + + /* buffer */ + + var c1 = it.onSet( it.src, it ); + if( c1 === false ) + return it.dst; + + /* container down */ + + if( it.onContainerDown ) + { + var c = it.onContainerDown( it ); + _.assert( c === undefined ); + } + + return it.dst; +} + +// + +function _traverseAct( it ) +{ + var handled = 0; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( it.level >= 0 ); + _.assert( it.copyingDegree > 0 ); + _.assert( _.object.isBasic( it.iterator ) ); + _.assert( _.strIs( it.path ) ); + _.assert( !( _.objectLike( it.src ) && _.longIs( it.src ) ) ); + + if( !( it.level <= it.iterator.levels ) ) + throw _.err + ( + 'failed to traverse structure', _.entity.strType( it.iterator.rootSrc ) + + '\nat ' + it.path + + '\ntoo deep structure' + + '\nrootSrc : ' + _.entity.exportString( it.iterator.rootSrc ) + + '\niteration : ' + _.entity.exportString( it ) + + '\niterator : ' + _.entity.exportString( it.iterator ) + ); + + /* */ + + if( !_._traverseEntityUp( it ) ) + return it.dst; + + /* class instance */ + + if( it.copyingDegree > 1 && it.usingInstanceCopy ) + { + + if( it.onInstanceCopy ) + { + it.onInstanceCopy( it.src, it ); + } + + if( _.workpiece.instanceLikeStandard( it.dst ) && _.routineIs( it.dst._traverseAct ) ) + { + it.dst._traverseAct( it ); + return it.dst; + } + else if( _.workpiece.instanceLikeStandard( it.src ) && _.routineIs( it.src._traverseAct ) ) + { + it.src._traverseAct( it ); + return it.dst; + } + + } + + /* !!! else if required here */ + + /* object like */ + + if( _.workpiece.instanceIsStandard( it.src ) ) + { + handled = 1; + _._traverseMap( it ); + } + + /* array like */ + + var bufferAnyIs = _.bufferAnyIs( it.src ); + if( _.longIs( it.src ) && !bufferAnyIs ) + { + handled = 1; + _._traverseArray( it ); + } + + /* set like */ + + if( _.setIs( it.src ) ) + { + handled = 1; + _._traverseSet( it ); + } + + /* buffer like */ + + if( bufferAnyIs ) + { + handled = 1; + _._traverseBuffer( it ); + } + + /* routine */ + + if( _.routineIs( it.src ) ) + { + handled = 1; + if( it.onRoutine ) + it.onRoutine( it.src, it ); + } + + /* string */ + + if( _.strIs( it.src ) ) + { + handled = 1; + if( it.onString ) + it.onString( it.src, it ); + } + + /* regexp */ + + if( _.regexpIs( it.src ) ) + { + handled = 1; + if( it.onRegExp ) + it.onRegExp( it.src, it ); + } + + /* date */ + + if( _.dateIs( it.src ) ) + { + handled = 1; + if( it.onDate ) + it.onDate( it.src, it ); + } + + /* set */ + + if( _.setLike( it.src ) ) + { + handled = 1; + if( it.onSet ) + it.onSet( it.src, it ); + } + + /* hash map */ + + if( _.hashMapLike( it.src ) ) + { + handled = 1; + if( it.onHashMap ) + it.onHashMap( it.src, it ); + } + + /* object like */ + + if( _.objectLike( it.src ) ) + if( !_.objectLikeStandard( it.src ) ) + // if( _.objectLike( it.src ) && !_.regexpIs( it.src ) && !_.dateIs( it.src ) ) + { + // if( _.regexpIs( it.src ) ) + // debugger; + handled = 1; + _._traverseMap( it ); + } + + /* atomic */ + + if( _.primitiveIs( it.src ) ) + { + handled = 1; + } + + if( it.dst === null ) + it.dst = it.src; + + /* */ + + if( !handled && it.copyingDegree > 1 ) + { + _.assert( 0, 'unknown type of src : ' + _.entity.strType( it.src ) ); + } + + /* */ + + _traverseEntityDown( it ); + + return it.dst; +} + +// -- +// +// -- + +/** + * @typedef {Object} iterationDefaults + * @property {Object} src=null + * @property {Object} dst=null + * @property {String} key=null + * @property {Object} proto=null + * @property {Number} level=0 + * @property {String} path='' + * @property {Object} customFields=null + * @property {Object} dropFields=null + * @property {Object} screenFields=null + * @property {Boolean} instanceAsMap=0 + * @property {Boolean} usingInstanceCopy=1 + * @property {Boolean} compact=0 + * @property {Number} copyingDegree=3 + * @namespace Tools + * @module Tools/base/Traverser + */ + +/** + * @typedef {Object} traverseOptions + * @property {Number} copyingComposes=3 + * @property {Number} copyingAggregates=1 + * @property {Number} copyingAssociates=1 + * @property {Number} copyingMedials=0 + * @property {Number} copyingMedialRestricts=1 + * @property {Number} copyingMedialRestricts=0 + * @property {Number} copyingRestricts=0 + * @property {Number} copyingBuffers=3 + * @property {Number} copyingCustomFields=0 + + * @property {Object} rootSrc=null + * @property {Number} levels=999 + * @property {String} technique=null + * @property {Boolean} deserializing=0 + + * @property {Function} onEntityUp=null + * @property {Function} onEntityDown=null + * @property {Function} onContainerUp=null + * @property {Function} onContainerDown=null + + * @property {Function} onDate=null + * @property {Function} onRegExp=null + * @property {Function} onRoutine=null + * @property {Function} onBuffer=null + * @property {Function} onInstanceCopy=null + * @property {Function} onCompactField=null + * + * @property {Function} onMapUp=null + * @property {Function} onMapElementUp=null + * @property {Function} onMapElementDown=null + * @property {Function} onArrayUp=null + * @property {Function} onArrayElementUp=null + * @property {Function} onArrayElementDown=null + * @namespace Tools + * @module Tools/base/Traverser + */ + +/** + * @summary Traverses a complex data structure. + * @param {Object} o Options map, look {@link module:Tools/base/Traverser.wTools.Traverser~traverseOptions traverseOptions} for details. + * + * @example + * var src = { buffer : new F32x([ 1,2,3 ]) }; + * + * var onBufferPaths = []; + * function onBuffer( src,it ) + * { + * onBufferPaths.push( it.path ); + * return it; + * } +* + * var r = _.traverse + * ({ + * src, + * onBuffer, + * }) + * console.log( onBufferPaths ); //["/buffer"] + * + * @returns {Object} Returns modified `o.src` object. + * @function traverse + * @namespace Tools + * @module Tools/base/Traverser + */ + +function traverse( o ) +{ + var it = _._traverser( traverse, o ); + var result = _._traverseAct( it ); + return result; +} + +traverse.defaults = Object.create( _traverser.defaults ); + +// -- +// declare +// -- + +const Proto = +{ + + _traverseIterator, + _traverseIteration, + + _traverser, + _traverseEntityUp, + _traverseEntityDown, + + _traverseMap, + _traverseArray, + _traverseBuffer, + _traverseSet, + _traverseAct, + + traverse, + +} + +_.props.extend( _, Proto ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wtraverser/proto/wtools/abase/l4/Traverser.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wtraverser/proto/wtools/abase/l4' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Traverser_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Traverser_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wunit/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wunit/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wunit */ ( function wunit() { function wunit_naked() { +module.exports = require( '../wtools/abase/l5/Units.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wUnit', 'wunit' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wunit/proto/node_modules/wunit' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wunit/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wunit_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wunit */ })(); + +/* */ /* begin of file Units_s */ ( function Units_s() { function Units_s_naked() { ( function _Units_s_() +{ + +'use strict'; + +/** + * Collection of sophisticated routines for operations with different units. + * @module Tools/base/l5/Units + * @extends Tools +*/ + +if( typeof module !== 'undefined' ) +{ + const _ = require( '../../../node_modules/Tools' ); +} + +const _ = _global_.wTools; +_.units = _.units || Object.create( null ); + +// -- +// format +// -- + +/** + * Converts string( str ) to array of unsigned 8-bit integers. + * + * @param {string} str - Source string to convert. + * @returns {typedArray} Returns typed array that represents string characters in 8-bit unsigned integers. + * + * @example + * //returns [ 101, 120, 97, 109, 112, 108, 101 ] + * _.units.strToBytes( 'example' ); + * + * @function strToBytes + * @throws { Exception } Throws a exception if( src ) is not a String. + * @throws { Exception } Throws a exception if no argument provided. + * @namespace Tools + * @module Tools/base/l5/StringTools + * + */ + +function strToBytes( src ) +{ + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( src ) ); + + let result = new U8x( src.length ); + + for( let s = 0, sl = src.length ; s < sl ; s++ ) + { + result[ s ] = src.charCodeAt( s ); + } + + return result; +} + +// + +/** +* @summary Contains metric prefixes. +* @enum {} _metrics +* @module Tools/base/l5/StringTools +*/ + +let _metrics = +{ + + '24' : { name : 'yotta', symbol : 'Y', word : 'septillion' }, + '21' : { name : 'zetta', symbol : 'Z', word : 'sextillion' }, + '18' : { name : 'exa', symbol : 'E', word : 'quintillion' }, + '15' : { name : 'peta', symbol : 'P', word : 'quadrillion' }, + '12' : { name : 'tera', symbol : 'T', word : 'trillion' }, + '9' : { name : 'giga', symbol : 'G', word : 'billion' }, + '6' : { name : 'mega', symbol : 'M', word : 'million' }, + '3' : { name : 'kilo', symbol : 'k', word : 'thousand' }, + '2' : { name : 'hecto', symbol : 'h', word : 'hundred' }, + '1' : { name : 'deca', symbol : 'da', word : 'ten' }, + + '0' : { name : '', symbol : '', word : '' }, + + '-1' : { name : 'deci', symbol : 'd', word : 'tenth' }, + '-2' : { name : 'centi', symbol : 'c', word : 'hundredth' }, + '-3' : { name : 'milli', symbol : 'm', word : 'thousandth' }, + '-6' : { name : 'micro', symbol : 'μ', word : 'millionth' }, + '-9' : { name : 'nano', symbol : 'n', word : 'billionth' }, + '-12' : { name : 'pico', symbol : 'p', word : 'trillionth' }, + '-15' : { name : 'femto', symbol : 'f', word : 'quadrillionth' }, + '-18' : { name : 'atto', symbol : 'a', word : 'quintillionth' }, + '-21' : { name : 'zepto', symbol : 'z', word : 'sextillionth' }, + '-24' : { name : 'yocto', symbol : 'y', word : 'septillionth' }, + + 'range' : [ -24, +24 ], + +} + +/** + * Returns string that represents number( src ) with metric unit prefix that depends on options( o ). + * If no options provided function start calculating metric with default options. + * Example: for number ( 50000 ) function returns ( "50.0 k" ), where "k"- thousand. + * + * @param {(number|string)} src - Source object. + * @param {object} o - conversion options. + * @param {number} [ o.divisor=3 ] - Sets count of number divisors. + * @param {number} [ o.thousand=1000 ] - Sets integer power of one thousand. + * @param {boolean} [ o.fixed=1 ] - The number of digits to appear after the decimal point, example : [ '58912.001' ]. + * Number must be between 0 and 20. + * @param {number} [ o.dimensions=1 ] - Sets exponent of a number. + * @param {number} [ o.metric=0 ] - Sets the metric unit type from the map( _metrics ). + * @returns {string} Returns number with metric prefix as a string. + * + * @example + * //returns "1.0 M" + * _.units.strMetricFormat( 1, { metric : 6 } ); + * + * @example + * //returns "100.0 " + * _.units.strMetricFormat( "100m", { } ); + * + * @example + * //returns "100.0 T + * _.units.strMetricFormat( "100m", { metric : 12 } ); + * + * @example + * //returns "2 k" + * _.units.strMetricFormat( "1500", { fixed : 0 } ); + * + * @example + * //returns "1.0 M" + * _.units.strMetricFormat( "1000000",{ divisor : 2, thousand : 100 } ); + * + * @example + * //returns "10.0 h" + * _.units.strMetricFormat( "10000", { divisor : 2, thousand : 10, dimensions : 3 } ); + * + * @function strMetricFormat + * @namespace Tools + * @module Tools/base/l5/StringTools + * + */ + +/* qqq : cover routine strMetricFormat */ /* aaa : Dmytro : covered */ +/* xxx : use it for time measurement */ + +function strMetricFormat( number, o ) +{ + + if( _.strIs( number ) ) + number = parseFloat( number ); + + o = _.routine.options_( strMetricFormat, o || null ); + + if( o.metrics === null ) + o.metrics = _metrics; + + _.assert( _.numberIs( number ), '"number" should be Number' ); + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.assert( _.object.isBasic( o ) || o === undefined, 'Expects map {-o-}' ); + _.assert( _.numberIs( o.fixed ) ); + _.assert( o.fixed <= 20 ); + + let original = number; + + if( o.dimensions !== 1 ) + o.thousand = Math.pow( o.thousand, o.dimensions ); + + if( number !== 0 ) + { + + if( Math.abs( number ) >= o.thousand ) + { + + while( Math.abs( number ) >= o.thousand || !o.metrics[ String( o.metric ) ] ) + { + + if( o.metric + o.divisor > o.metrics.range[ 1 ] ) + break; + + number /= o.thousand; + o.metric += o.divisor; + + } + + } + else if( Math.abs( number ) < 1 ) + { + + while( Math.abs( number ) < 1 || !o.metrics[ String( o.metric ) ] ) + { + + if( o.metric - o.divisor < o.metrics.range[ 0 ] ) + break; + + number *= o.thousand; + o.metric -= o.divisor; + + } + + if( number / o.thousand > 1 ) + { + let o2 = + { + thousand : o.thousand, + metric : o.metric, + fixed : o.fixed, + divisor : o.divisor, + metrics : o.metrics, + dimensions : o.dimensions + }; + return strMetricFormat( number, o2 ); + } + + } + + } + + let result = ''; + + if( o.metrics[ String( o.metric ) ] ) + { + result = number.toFixed( o.fixed ) + ' ' + o.metrics[ String( o.metric ) ].symbol; + } + else + { + result = original.toFixed( o.fixed ) + ' '; + } + + return result; +} + +strMetricFormat.defaults = +{ + divisor : 3, + thousand : 1000, + fixed : 1, + dimensions : 1, + metric : 0, + metrics : null, +} + +// + +/** + * Short-cut for strMetricFormat() function. + * Converts number( number ) to specific count of bytes with metric prefix. + * Example: ( 2048 -> 2.0 kb). + * + * @param {string|number} str - Source number to convert. + * @param {object} o - conversion options. + * @param {number} [ o.divisor=3 ] - Sets count of number divisors. + * @param {number} [ o.thousand=1024 ] - Sets integer power of one thousand. + * @see {@link wTools.strMetricFormat} Check out main function for more usage options and details. + * @returns {string} Returns number of bytes with metric prefix as a string. + * + * @example + * //returns "100.0 b" + * _.units.strMetricFormatBytes( 100 ); + * + * @example + * //returns "4.0 kb" + * _.units.strMetricFormatBytes( 4096 ); + * + * @example + * //returns "1024.0 Mb" + * _.units.strMetricFormatBytes( Math.pow( 2, 30 ) ); + * + * @function strMetricFormatBytes + * @namespace Tools + * @module Tools/base/l5/StringTools + * + */ + +function strMetricFormatBytes( number, o ) +{ + + o = o || Object.create( null ); + let defaultOptions = + { + divisor : 3, + thousand : 1024, + }; + + _.props.supplement( o, defaultOptions ); + + return _.units.strMetricFormat( number, o ) + 'b'; +} + +// + +/** + * Short-cut for strMetricFormat() function. + * Converts number( number ) to specific count of seconds with metric prefix. + * Example: ( 1000 (ms) -> 1.000 s). + * + * @param {number} str - Source number to convert. + * @param {number} [ o.fixed=3 ] - The number of digits to appear after the decimal point, example : [ '58912.001' ]. + * Can`t be changed. + * @see {@link wTools.strMetricFormat} Check out main function for more usage options and details. + * @returns {string} Returns number of seconds with metric prefix as a string. + * + * @example + * //returns "1.000 s" + * _.units.strTimeFormat( 1000 ); + * + * @example + * //returns "10.000 ks" + * _.units.strTimeFormat( Math.pow( 10, 7 ) ); + * + * @example + * //returns "78.125 s" + * _.units.strTimeFormat( Math.pow( 5, 7 ) ); + * + * @function strTimeFormat + * @namespace Tools + * @module Tools/base/l5/StringTools + * + */ + +function strTimeFormat( time ) +{ + _.assert( arguments.length === 1 ); + time = _.time.from( time ); + let result = _.units.strMetricFormat( time * 0.001, { fixed : 3 } ) + 's'; + return result; +} + +// + +function unitsConvert_functor( fo ) +{ + _.assert( arguments.length === 1 ); + _.routine.options( unitsConvert_functor, fo ); + _.assert( fo.unitsBaseRatio.default in fo.unitsBaseRatio ); + _.each( fo.unitsBaseRatio, ( e, k ) => _.assert( /[a-zA-Z]+$/.test( k ) ) ); + + if( fo.metrics === null ) + fo.metrics = _metrics; + + /* */ + + function unitsConvert( o ) + { + _.assert( arguments.length === 1 ); + _.routine.options( unitsConvert, o ); + _.assert( o.dstType in fo.unitsBaseRatio ); + + if( o.dstType === 'default' ) + o.dstType = fo.unitsBaseRatio[ o.dstType ]; + + if( _.str.is( o.src ) ) + { + const splits = _.strIsolateLeftOrAll( o.src, /[a-zA-Z]*$/ ); + if( splits[ 1 ] === undefined ) + { + const multiplier = multiplierGet( o.dstType, fo.unitsBaseRatio.default ); + return multiplier * _.number.from( o.src ); + } + + let multiplier = 1; + let type = splits[ 1 ]; + let prefix = ''; + if( !( type in fo.unitsBaseRatio ) ) + { + prefix = type[ 0 ]; + for( let key in fo.metrics ) + if( fo.metrics[ key ].symbol === prefix ) + { + multiplier = Math.pow( 10, _.number.from( key ) ); + type = type.substring( 1 ); + break; + } + } + + if( multiplier === 0.1 ) + if( prefix === 'd' && type[ 0 ] === 'a' && !( type in fo.unitsBaseRatio ) ) + { + multiplier = 10; + type = type.substring( 1 ); + } + + _.assert( _.number.is( multiplier ) ); + + const typeMultiplier = multiplierGet( o.dstType, type ); + return multiplier * typeMultiplier * _.number.from( splits[ 0 ] ); + } + else if( _.number.is( o.src ) ) + { + const multiplier = multiplierGet( o.dstType, fo.unitsBaseRatio.default ); + return multiplier * o.src; + } + else + { + _.assert( false, 'Unexpected type of of {-o.src-}.' ); + } + } + + unitsConvert.defaults = + { + src : null, + dstType : 'default', + }; + + return unitsConvert; + + /* */ + + function multiplierGet( dstType, baseType ) + { + if( dstType === baseType ) + return 1; + + if( dstType === fo.unitsBaseRatio.default ) + return fo.unitsBaseRatio[ dstType ] * fo.unitsBaseRatio[ baseType ]; + + return ( fo.unitsBaseRatio[ fo.unitsBaseRatio.default ] / fo.unitsBaseRatio[ dstType ] ) * fo.unitsBaseRatio[ baseType ]; + } +} + +unitsConvert_functor.defaults = +{ + unitsBaseRatio : null, + metrics : null, +}; + +// -- +// declare +// -- + +let Extension = +{ + + // format + + strToBytes, + strMetricFormat, + strMetricFormatBytes, + + strTimeFormat, + + unitsConvert_functor, +} + +_.props.extend( _.units, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = _; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wunit/proto/wtools/abase/l5/Units.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wunit/proto/wtools/abase/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Units_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Units_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wuribasic/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wuribasic/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wuribasic */ ( function wuribasic() { function wuribasic_naked() { +module.exports = require( '../wtools/abase/l4/Uri.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wUriBasic', 'wuribasic' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wuribasic/proto/node_modules/wuribasic' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wuribasic/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wuribasic_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wuribasic */ })(); + +/* */ /* begin of file Uri_s */ ( function Uri_s() { function Uri_s_naked() { ( function _Uri_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to operate URIs ( URLs ) in the reliable and consistent way. Path leverages parsing, joining, extracting, normalizing, nativizing, resolving paths. Use the module to get uniform experience from playing with paths on different platforms. + @module Tools/base/Uri +*/ + +/** + * Collection of cross-platform routines to operate URIs ( URLs ) in the reliable and consistent way. + @namespace wTools.uri + @extends Tools + @module Tools/base/Uri +*/ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + + _.include( 'wStringer' ); + _.include( 'wPathBasic' ); + _.include( 'wBlueprint' ); + +} + +// + +const _global = _global_; +const _ = _global_.wTools; +const Parent = _.path; +const Self = _.uriNew = _.uriNew || Object.create( Parent ); +_.uri = _.uriNew; + +// -- +// relation +// -- + +let Uri = _.Blueprint +({ + typed : _.trait.typed(), + extendable : _.trait.extendable(), /* qqq xxx : is it required? */ + protocol : null, + query : null, + hash : null, + tag : null, +}); + +// + +let UriFull = _.Blueprint +({ + extension : _.define.extension( Uri ), + + protocols : null, + postfixedPath : null, + resourcePath : null, + longPath : null, + full : null, + + hostFull : null, + host : null, + port : null, + user : null, + origin : null, + +}); + +// + +let UriAtomic = _.Blueprint +({ + extension : _.define.extension( Uri ), + + // resourcePath : null, + // host : null, +}); + +// + +let UriConsequtive = _.Blueprint +({ + extension : _.define.extension( Uri ), + + longPath : null, +}); + +/* qqq jsdoc structures Uri*. ask how to */ + +/** + * + * The URI component object. + * @typedef {Object} UrlComponents + * @property {string} protocol the URI's protocol scheme.; + * @property {string} host host portion of the URI; + * @property {string} port property is the numeric port portion of the URI + * @property {string} resourcePath the entire path section of the URI. + * @property {string} query the entire "query string" portion of the URI, not including '?' character. + * @property {string} hash property consists of the "fragment identifier" portion of the URI. + + * @property {string} uri the whole URI + * @property {string} hostFull host portion of the URI, including the port if specified. + * @property {string} origin protocol + host + port + * @private + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +// let UriComponents = +// { +// +// /* atomic */ +// +// protocol : null, /* 'svn+http' */ +// host : null, /* 'www.site.com' */ +// port : null, /* '13' */ +// resourcePath : null, /* '/path/name' */ +// query : null, /* 'query=here&and=here' */ +// hash : null, /* 'anchor' */ +// tag : null, /* tag */ +// +// /* composite */ +// +// // qqq !!! : implement queries +// // queries : null, /* { query : here, and : here } */ +// longPath : null, /* www.site.com:13/path/name */ +// postfixedPath : null, /* www.site.com:13/path/name?query=here#anchor@tag */ +// protocols : null, /* [ 'svn','http' ] */ +// hostFull : null, /* 'www.site.com:13' */ +// origin : null, /* 'svn+http://www.site.com:13' */ +// full : null, /* 'svn+http://www.site.com:13/path/name?query=here&and=here#anchor' */ +// +// } + +// -- +// internal +// -- + +function _filterOnlyUrl( e, k, c ) +{ + if( _.strIs( k ) ) + { + if( _.strEnds( k, 'Url' ) ) + return true; + else + return false + } + return this.is( e ); +} + +// + +function _filterNoInnerArray( arr ) +{ + return arr.every( ( e ) => !_.arrayIs( e ) ); +} + +// -- +// dichotomy +// -- + +// '^(https?:\\/\\/)?' // protocol +// + '(\\/)?' // relative +// + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' // domain +// + '((\\d{1,3}\\.){3}\\d{1,3}))' // ip +// + '(\\:\\d+)?' // port +// + '(\\/[-a-z\\d%_.~+]*)*' // path +// + '(\\?[;&a-z\\d%_.~+=-]*)?' // query +// + '(\\#[-a-z\\d_]*)?$'; // anchor + +let isRegExpString = + '^([\w\d]*:\\/\\/)?' // protocol + + '(\\/)?' // relative + + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' // domain + + '((\\d{1,3}\\.){3}\\d{1,3}))' // ip + + '(\\:\\d+)?' // port + + '(\\/[-a-z\\d%_.~+]*)*' // path + + '(\\?[;&a-z\\d%_.~+=-]*)?' // query + + '(\\#[-a-z\\d_]*)?$'; // anchor + +let isRegExp = new RegExp( isRegExpString, 'i' ); +function is( path ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + return _.strIs( path ); +} + +// + +/** + * @summary Checks if provided uri is safe. + * @param {String} filePath Source uri + * @param {Number} level Level of check + * + * @example + * _.uriNew.isSafe( 'https:///web.archive.org' )// false + * + * @example + * _.uriNew.isSafe( 'https:///web.archive.org/root' )// true + * + * @returns {Boolean} Returns result of check for safetiness. + * @function isSafe + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isSafe( path, level ) +{ + let parent = this.path; + + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects single argument' ); + _.assert( _.strDefined( path ) ); + + if( this.isGlobal( path ) ) + path = this.parseConsecutive( path ).longPath; + + return parent.isSafe.call( this, path, level ); +} + +/* +qqq : module:Tools? | Dmytro : changed similar to module wPathBasic +*/ + +// + +/** + * @summary Checks if provided uri is refined. + * @param {String} filePath Source uri + * + * @returns {Boolean} Returns true if {filePath} is refined, otherwise false. + * @function isRefined + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isRefined( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ).longPath; + + return parent.isRefined.call( this, filePath ); +} + +// // +// +// /** +// * @summary Checks if provided uri is refined. +// * @param {String} filePath Source uri +// * +// * @returns {Boolean} Returns true if {filePath} is refined, otherwise false. +// * @function isRefined +// * @module Tools/UriBasic +// * @namespace Tools.uri +// */ +// +// function isRefined( filePath ) +// { +// let parent = this.path; +// +// _.assert( arguments.length === 1, 'Expects single argument' ); +// _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); +// +// if( this.isGlobal( filePath ) ) +// filePath = this.parseConsecutive( filePath ).longPath; +// +// return parent.isRefined.call( this, filePath ); +// } + +// + +/** + * @summary Checks if provided uri is normalized. + * @param {String} filePath Source uri + * + * @returns {Boolean} Returns true if {filePath} is normalized, otherwise false. + * @function isNormalized + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isNormalized( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ).longPath; + + return parent.isNormalized.call( this, filePath ); +} + +// // +// +// /** +// * @summary Checks if provided uri is normalized. +// * @param {String} filePath Source uri +// * +// * @example +// * _.uriNew.isNormalized( 'https:///web.archive.org' ); // returns true +// * +// * @example +// * _.uriNew.isNormalized( 'https:/\\\\web.archive.org' ); // returns false +// * +// * @returns {Boolean} Returns true if {filePath} is normalized, otherwise false. +// * @function isNormalized +// * @module Tools/UriBasic +// * @namespace Tools.uri +// */ +// +// function isNormalized( path ) +// { +// _.assert( arguments.length === 1, 'Expects single argument' ); +// _.assert( _.strIs( path ), 'Expects string' ); +// return this.normalize( path ) === path; +// } + +// + +/** + * @summary Checks if provided uri is absolute. + * @param {String} filePath Source uri + * + * @example + * _.uriNew.isAbsolute( 'https:/web.archive.org' )// false + * + * @example + * _.uriNew.isAbsolute( 'https:///web.archive.org' )// true + * + * @returns {Boolean} Returns true if {filePath} is absolute, otherwise false. + * @function isAbsolute + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isAbsolute( path ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( path ), () => 'Expects string {-path-}, but got ' + _.entity.strType( path ) ); + + if( this.isGlobal( path ) ) + path = this.parseConsecutive( path ).longPath; + + return parent.isAbsolute.call( this, path ); +} + +// + +/** + * @summary Checks if provided uri is relative. + * @param {String} filePath Source uri + * + * @returns {Boolean} Returns true if {filePath} is relative, otherwise false. + * @function isRelative + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isRelative( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ).longPath; + + return parent.isRelative.call( this, filePath ); +} + +// + +/** + * @summary Checks if provided uri is root. + * @param {String} filePath Source uri + * + * @example + * _.uriNew.isRoot( 'https:/web.archive.org' )// false + * + * @example + * _.uriNew.isRoot( 'https:///' )// true + * + * @returns {Boolean} Returns true if {filePath} is root, otherwise false. + * @function isRoot + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isRoot( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ).longPath; + + return parent.isRoot.call( this, filePath ); +} + +// + +/** + * @summary Checks if provided uri begins with dot. + * @param {String} filePath Source uri + * + * @returns {Boolean} Returns true if path begins with dot, otherwise false. + * @function isDotted + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isDotted( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ).longPath; + + return parent.isDotted.call( this, filePath ); +} + +// + +/** + * @summary Checks if provided uri ends with slash. + * @param {String} filePath Source uri + * + * @returns {Boolean} Returns true if path ends with slash, otherwise false. + * @function isTrailed + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isTrailed( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ).longPath; + + return parent.isTrailed.call( this, filePath ); +} + +// + +/** + * @summary Checks if provided uri is glob. + * @param {String} filePath Source uri + * + * @returns {Boolean} Returns true if {filePath} is glob, otherwise false. + * @function isGlob + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isGlob( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ).longPath; + + return parent.isGlob.call( this, filePath ); +} + +// -- +// transformer +// -- + +function _parseOrigin( map, originPath ) +{ + let self = this; + + let isolates = _.strIsolateLeftOrNone.body + ({ + src : originPath, + delimeter : self.protocolToken, + times : 1, + quote : false, + }); + + map.portocol = isolates[ 0 ]; + map.hostFull = isolates[ 2 ]; + + self._parseHostFull( map, map.hostFull ); +} + +// + +function _parseLongPath( map, longPath ) +{ + let self = this; + let isAbsolute = false; + + if( !longPath ) + return; + + if( _.strBegins( longPath[ 0 ], self.rootToken ) ) + { + longPath = longPath.slice( self.rootToken.length ); + isAbsolute = true; + } + + let isolates = _.strIsolateLeftOrAll.body + ({ + src : longPath, + delimeter : self.upToken, + times : 1, + quote : false, + }); + + map.hostFull = isolates[ 0 ]; + if( isolates[ 1 ] ) + map.resourcePath = isolates[ 2 ]; + + if( isAbsolute ) + map.hostFull = self.rootToken + map.hostFull; + + self._parseHostFull( map, map.hostFull ); + +} + +// + +function _parseHostFull( map, hostFull ) +{ + let self = this; + let isAbsolute = false; + + // if( !hostFull ) + // return; + + if( _.strBegins( hostFull, self.rootToken ) ) + isAbsolute = true; + + let isolates2 = _.strIsolateRightOrNone.body + ({ + src : hostFull, + delimeter : self.portToken, + times : 1, + quote : false, + }); + map.host = isolates2[ 0 ]; + + if( isolates2[ 1 ] ) + map.port = _.numberFromStrMaybe( isolates2[ 2 ] ); + + let isolates3 = _.strIsolateLeftOrNone.body + ({ + src : map.host, + delimeter : self.userToken, + times : 1, + quote : false, + }); + + if( isAbsolute && isolates3[ 1 ] ) + { + isolates3[ 0 ] = isolates3[ 0 ].slice( self.rootToken.length ); + isolates3[ 2 ] = self.rootToken + isolates3[ 2 ]; + } + + if( isolates3[ 1 ] ) + map.user = isolates3[ 0 ]; + map.host = isolates3[ 2 ]; + +} + +// + +/* +http://www.site.com:13/path/name?query=here&and=here#anchor +2 - protocol +3 - hostFull( host + port ) +5 - resourcePath +6 - query +8 - hash +*/ + +/*{ + 'protocol' : 'complex+protocol', + 'host' : 'www.site.com', + 'port' : '13', + 'query' : 'query=here&and=here', + 'hash' : 'anchor', + 'resourcePath' : '/!a.js?', + 'longPath' : 'www.site.com:13/!a.js?', +}*/ + +function parse_head( routine, args ) +{ + _.assert( args.length === 1, 'Expects single argument' ); + + let o = { srcPath : args[ 0 ] }; + + _.routine.options_( routine, o ); + _.assert( _.strIs( o.srcPath ) || _.mapIs( o.srcPath ) ); + _.assert( _.longHas( routine.Kind, o.kind ), () => 'Unknown kind of parsing ' + o.kind ); + + return o; +} + +function parse_body( o ) +{ + let self = this; + let result = Object.create( null ); + + if( _.mapIs( o.srcPath ) ) + { + _.map.assertHasOnly( o.srcPath, this.UriFull.propsExtension ); + if( o.srcPath.protocols ) + return o.srcPath; + else if( o.srcPath.full ) + o.srcPath = o.srcPath.full; + else + o.srcPath = this.str( o.srcPath ); + } + + let postfixes = ''; + + longPathParse(); + + let delimeter = [ self.tagToken, self.hashToken, self.queryToken ]; + if( _.strHasAny( result.longPath, delimeter ) ) + postfixesParse( delimeter ); + + /* */ + + if( o.kind === 'full' ) + { + + result.postfixedPath = result.longPath + postfixes; + + self._parseLongPath( result, result.longPath ); + + if( result.protocol ) + result.protocols = result.protocol.split( '+' ); + else + result.protocols = []; + + if( _.strIs( result.protocol ) ) + result.origin = result.protocol + self.protocolToken + result.hostFull; + + result.full = o.srcPath; + + } + else if( o.kind === 'consecutive' ) + { + } + else if( o.kind === 'atomic' ) + { + self._parseLongPath( result, result.longPath ); + delete result.hostFull; + delete result.longPath; + } + else _.assert( 0 ); + + return result; + + /* */ + + function longPathParse() + { + + let isolates = _.strIsolateLeftOrNone.body + ({ + src : o.srcPath, + delimeter : self.protocolToken, + times : 1, + quote : false, + }); + + if( isolates[ 1 ] ) + result.protocol = isolates[ 0 ]; + + result.longPath = isolates[ 2 ]; + } + + /* */ + + function postfixesParse( delimeter ) + { + + let rest = ''; + let splits2 = _.path.split( result.longPath ); + let left, s; + + for( s = 0 ; s < splits2.length ; s++ ) + { + let split = splits2[ s ]; + if( _.path._unescape( split ).wasEscaped ) + continue; + left = _.strLeft_( split, delimeter ); + if( left.entry ) + { + if( s > 0 ) + { + result.longPath = splits2.slice( 0, s ).join( self.upToken ); + result.longPath += self.upToken + split.slice( 0, left.index ); + } + else + { + result.longPath = split.slice( 0, left.index ); + } + split = split.slice( left.index + 1 ); + splits2[ s ] = split + rest = splits2.slice( s ).join( self.upToken ); + break; + } + } + + if( left && left.entry ) + restParse( rest, left.entry, delimeter ); + + } + + /* */ + + function restParse( rest, entry, delimeter ) + { + + _.arrayRemoveOnceStrictly( delimeter, entry ); + + let isolates = _.strIsolateLeftOrAll( rest, delimeter ); + + if( entry === self.queryToken ) + result.query = isolates[ 0 ]; + else if( entry === self.hashToken ) + result.hash = isolates[ 0 ]; + else if( entry === self.tagToken ) + result.tag = isolates[ 0 ]; + + postfixes += entry + isolates[ 0 ]; + + // rest = isolates[ 2 ]; /* xxx : remove variable? */ + if( isolates[ 1 ] ) + { + restParse( isolates[ 2 ], isolates[ 1 ], delimeter ); + } + + } + + /* */ + +} + +parse_body.defaults = +{ + srcPath : null, + kind : 'full', +} + +parse_body.components = UriFull.propsExtension; + +parse_body.Kind = [ 'full', 'atomic', 'consecutive' ]; + +// + +/** + * Method parses URI string, and returns a UrlComponents object. + * @example + * + let uri = 'http://www.site.com:13/path/name?query=here&and=here#anchor' + + wTools.uri.parse( uri ); + + // { + // protocol : 'http', + // hostFull : 'www.site.com:13', + // resourcePath : /path/name, + // query : 'query=here&and=here', + // hash : 'anchor', + // host : 'www.site.com', + // port : '13', + // origin : 'http://www.site.com:13' + // } + + * @param {string} path Url to parse + * @param {Object} o - parse parameters + included into result + * @returns {UrlComponents} Result object with parsed uri components + * @throws {Error} If passed `path` parameter is not string + * @function parse + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +let parse = _.routine.uniteCloning_replaceByUnite( parse_head, parse_body ); + +parse.components = UriFull.propsExtension; + +// + +let parseFull = _.routine.uniteCloning_replaceByUnite( parse_head, parse_body ); +parseFull.defaults.kind = 'full'; +parseFull.components = UriFull.propsExtension; + +// + +let parseAtomic = _.routine.uniteCloning_replaceByUnite( parse_head, parse_body ); +parseAtomic.defaults.kind = 'atomic'; + +parseAtomic.components = UriAtomic.propsExtension; + +// + +let parseConsecutive = _.routine.uniteCloning_replaceByUnite( parse_head, parse_body ); +parseConsecutive.defaults.kind = 'consecutive'; + +// + +function localFromGlobal( globalPath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.boolLike( globalPath ) ) + return globalPath; + + if( _.strIs( globalPath ) ) + { + if( !this.isGlobal( globalPath ) ) + return globalPath; + + globalPath = this.parseConsecutive( globalPath ); + } + + _.assert( _.mapIs( globalPath ) ) ; + _.assert( _.strIs( globalPath.longPath ) ); + + return globalPath.longPath; +} + +// + +/** + * Routine str() assembles URI string from components. + * + * @example + * let components = + * { + * protocol : 'http', + * host : 'www.site.com', + * port : '13', + * resourcePath : '/path/name', + * query : 'query=here&and=here', + * hash : 'anchor', + * }; + * _.uri.str( UrlComponents ); + * // returns : 'http://www.site.com:13/path/name?query=here&and=here#anchor' + * + * @param { Map|Aux|String } map - Map with URI components. + * @returns { String } - Returns complete URI string. + * @throws { Error } If arguments.length is not equal to 1. + * @throws { Error } If {-map-} has incompatible type. + * @see { @link UrlComponents } + * @function str + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function str( map ) +{ + let self = this; + let result = ''; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.strIs( map ) ) + return map; + + if( Config.debug ) + { + _.assert + ( + map.longPath === undefined || map.longPath === null || longPathHas( map ), + 'Codependent components of URI map are not consistent', 'something wrong with {-longPath-}' + ); + _.assert + ( + map.protocols === undefined || map.protocols === null || protocolsHas( map ), + 'Codependent components of URI map are not consistent', 'something wrong with {-protocols-}' + ); + _.assert + ( + map.hostFull === undefined || map.hostFull === null || hostFullHas( map ), + 'Codependent components of URI map are not consistent', 'something wrong with {-hostFull-}' + ); + _.assert + ( + map.origin === undefined || map.origin === null || originHas( map ), + 'Codependent components of URI map are not consistent', 'something wrong with {-origin-}' + ); + _.assert + ( + map.full === undefined || map.full === null || fullHas( map ), + 'Codependent components of URI map are not consistent', 'something wrong with {-full-}' + ); + _.assert( _.strIs( map ) || _.mapIs( map ) ); + } + + _.map.assertHasOnly( map, this.UriFull.propsExtension ); + + /* */ + + if( map.full ) + { + _.assert( _.strDefined( map.full ) ); + return map.full; + } + + map = _.props.extend( null, map ); + + if( map.origin && ( map.protocol === null || map.protocol === undefined ) ) + if( _.strHas( map.origin, self.protocolToken ) ) + { + map.protocol = _.strIsolateLeftOrNone( map.origin, self.protocolToken )[ 0 ]; + } + + if( ( map.protocol === null || map.protocol === undefined ) && map.protocols && map.protocols.length ) + map.protocol = map.protocols.join( '+' ); + + if( map.origin ) + if + ( + ( map.user === null || map.user === undefined ) + || ( map.host === null || map.host === undefined ) + || ( map.port === null || map.port === undefined ) + ) + componentsFromOrigin( map ); + + if( map.longPath === undefined ) + map.longPath = longPathFrom( map ); + + return fullFrom( map ); + + /* */ + + return result; + + /* */ + + function componentsFromOrigin( map ) + { + self._parseOrigin( map, map.origin ); + } + + /* */ + + function longPathFrom( map ) + { + let hostFull = map.hostFull; + + if( _.strIs( map.resourcePath ) ) + { + if( !_.strIs( hostFull ) ) + hostFull = hostFullFrom( map ); + if( hostFull === undefined ) + return map.resourcePath; + else + return hostFull + self.upToken + map.resourcePath; + } + else if( map.longPath === undefined ) + { + if( !_.strIs( hostFull ) ) + hostFull = hostFullFrom( map ); + return hostFull || ''; + } + else + { + if( Config.debug ) + { + if( !_.strIs( hostFull ) ) + hostFull = hostFullFrom( map ); + if( hostFull ) + _.assert( _.strBegins( map.longPath, hostFull ) ); + } + return map.longPath; + } + + } + + /* */ + + function longPathHas( map ) + { + + if( map.host ) + if( !_.strHas( map.longPath, _.strRemoveBegin( map.host, self.rootToken ) ) ) + return false; + + if( map.user ) + if( !_.strHas( map.longPath, map.user + self.userToken ) ) + return false; + + if( map.port !== undefined && map.port !== null ) + if( !_.strHas( map.longPath, String( map.port ) ) ) + return false; + + if( map.resourcePath ) + if( !_.strEnds( map.longPath, map.resourcePath ) ) + return false; + + return true; + } + + /* */ + + function protocolsFrom( map ) + { + return map.protocol.split( '+' ); + } + + /* */ + + function protocolsHas( map ) + { + if( map.protocol !== null && map.protocol !== undefined ) + if( map.protocols.join( '+' ) !== map.protocol ) + return false; + return true; + } + + /* */ + + function hostFullFrom( map ) + { + let hostFull = ''; + let host = map.host || ''; + + if( map.host === undefined && map.user === undefined && map.port === undefined ) + { + return; + } + + if( _.strIs( map.user ) ) + { + let prefix = ''; + if( _.strBegins( host, self.rootToken ) ) + { + prefix = self.rootToken; + host = host.slice( self.rootToken.length ); + } + hostFull = prefix + map.user + self.userToken + host; + } + else + { + hostFull = host; + } + + if( map.port !== undefined && map.port !== null ) + if( hostFull ) + hostFull += self.portToken + map.port; + else + hostFull = self.portToken + map.port; + + return hostFull; + } + + /* */ + + function hostFullHas( map ) + { + + if( map.host ) + if( !_.strHas( map.hostFull, _.strRemoveBegin( map.host, self.rootToken ) ) ) + return false; + + if( map.user ) + if( !_.strHas( map.hostFull, map.user + self.userToken ) ) + return false; + + if( map.port !== null && map.port !== undefined ) + if( !_.strHas( map.hostFull, String( map.port ) ) ) + return false; + + return true; + } + + /* */ + + function originFrom( map ) + { + let result = ''; + let hostFull; + + if( map.hostFull ) + { + hostFull = map.hostFull; + } + else + { + hostFull = hostFullFrom( map ); + } + + if( _.strIs( map.protocol ) && !hostFull ) + hostFull = ''; + + if( _.strIs( map.protocol ) || _.strIs( hostFull ) ) + result += ( map.protocol || '' ) + self.protocolToken + ( hostFull || '' ); + + return result; + } + + /* */ + + function originHas( map ) + { + + if( map.protocol ) + if( !_.strBegins( map.origin, map.protocol ) ) + return false; + + if( map.host ) + if( !_.strHas( map.origin, _.strRemoveBegin( map.host, self.rootToken ) ) ) + return false; + + if( map.port !== null && map.port !== undefined ) + if( !_.strHas( map.origin, String( map.port ) ) ) + return false; + + return true; + } + + /* */ + + function fullFrom( map ) + { + _.assert( _.strIs( map.longPath ) ); + + if( _.strIs( map.protocol ) ) + result += ( map.protocol || '' ) + self.protocolToken; + + result += map.longPath; + + /**/ + + if( _.mapIs( map.query ) ) + map.query = _.strWebQueryStr({ src : map.query }); + + _.assert( !map.query || _.strIs( map.query ) ); + + if( map.query !== undefined && map.query !== undefined ) + result += self.queryToken + map.query; + + if( map.hash !== undefined && map.hash !== null ) + result += self.hashToken + map.hash; + + if( map.tag !== undefined && map.tag !== null ) + result += self.tagToken + map.tag; + + return result; + } + + /* */ + + function fullHas( map ) + { + if( map.protocol ) + if( !_.strBegins( map.full, map.protocol ) ) + return false; + + if( map.host ) + if( !_.strHas( map.full, _.strRemoveBegin( map.host, self.rootToken ) ) ) + return false; + + if( map.port !== null && map.port !== undefined ) + if( !_.strHas( map.full, String( map.port ) ) ) + return false; + + if( map.resourcePath ) + if( !_.strHas( map.full, map.resourcePath ) ) + return false; + + if( map.query ) + if( !_.strHas( map.full, map.query ) ) + return false; + + if( map.hash ) + if( !_.strHas( map.full, map.hash ) ) + return false; + + if( map.tag ) + if( !_.strHas( map.full, map.tag ) ) + return false; + + if( map.longPath ) + if( !_.strHas( map.full, map.longPath ) ) + return false; + + return true; + } + +} + +str.components = UriFull.propsExtension; + +// + +/** + * Complements current window uri origin by components passed in o. + * All components of current origin is replaced by appropriates components from o if they exist. + * If { o.full } exists and valid, method returns it. + * @example + * // current uri http://www.site.com:13/foo/baz + let components = + { + resourcePath : '/path/name', + query : 'query=here&and=here', + hash : 'anchor', + }; + let res = wTools.uri.full( o ); + // 'http://www.site.com:13/path/name?query=here&and=here#anchor' + * + * @returns {string} composed uri + * @function full + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function full( o ) +{ + + _.assert( arguments.length === 1 ); + _.assert( this.is( o ) || _.mapIs( o ) ); + + if( _.strIs( o ) ) + o = this.parseAtomic( o ) + + _.map.assertHasOnly( o, this.UriFull.propsExtension ); + + if( !_realGlobal_.location ) + return this.str( o ); + + let serverUri = this.server(); + let serverParsed = this.parseAtomic( serverUri ); + + _.props.extend( serverParsed, o ); + + return this.str( serverParsed ); +} + +// + +function refine( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ); + else + return parent.refine.call( this, filePath ); + + if( _.strDefined( filePath.longPath ) ) + filePath.longPath = parent.refine.call( this, filePath.longPath ); + + if( filePath.hash || filePath.tag ) + filePath.longPath = parent.detrail( filePath.longPath ); + + return this.str( filePath ); +} + +function normalize( filePath ) +{ + let parent = this.path; + _.assert( _.strIs( filePath ), 'Expects string {-filePath-}' ); + if( _.strIs( filePath ) ) + { + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ); + else + return parent.normalize.call( this, filePath ); + } + _.assert( !!filePath ); + filePath.longPath = parent.normalize.call( this, filePath.longPath ); + return this.str( filePath ); +} + +// + +function canonize( filePath ) +{ + let parent = this.path; + if( _.strIs( filePath ) ) + { + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ); + else + return parent.canonize.call( this, filePath ); + } + _.assert( !!filePath ); + filePath.longPath = parent.canonize.call( this, filePath.longPath ); + return this.str( filePath ); +} + +// + +function normalizeTolerant( filePath ) +{ + let parent = this.path; + if( _.strIs( filePath ) ) + { + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ); + else + return parent.normalizeTolerant.call( this, filePath ); + } + _.assert( !!filePath ); + filePath.longPath = parent.normalizeTolerant.call( this, filePath.longPath ); + return this.str( filePath ); +} + +// + +function dot( path ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strDefined( path ) ); + + if( !this.isGlobal( path ) ) + return parent.dot.call( this, path ); + + path = this.parseConsecutive( path ); + path.longPath = parent.dot( path.longPath ); + + return this.str( path ); +} + +// + +function trail( srcPath ) +{ + _.assert( arguments.length === 1 ); + return this.path.trail( srcPath ); +} + +// + +function detrail( srcPath ) +{ + _.assert( this.is( srcPath ) ); + _.assert( arguments.length === 1 ); + + // debugger; + if( _.strIs( srcPath ) ) + srcPath = this.parseConsecutive( srcPath ); + + srcPath.longPath = this.path.detrail( srcPath.longPath ); + + return this.str( srcPath ); +} + +// + +function name( o ) +{ + let parent = this.path; + if( _.strIs( o ) ) + o = { path : o } + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.mapIs( o ) ); + _.assert( _.strIs( o.path ) ); + _.routine.options_( name, o ); + + if( !this.isGlobal( o.path ) ) + return parent.name.call( this, o ); + + let path = this.parseConsecutive( o.path ); + + let o2 = _.props.extend( null, o ); + o2.path = path.longPath; + return parent.name.call( this, o2 ); +} + +name.defaults = Object.create( Parent.name.defaults ); + +// + +function ext( path ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( path ), 'Expects string' ); + + if( this.isGlobal( path ) ) + path = this.parseConsecutive( path ).longPath; + + return parent.ext.call( this, path ); +} + +// + +function exts( path ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strDefined( path ) ); + + if( this.isGlobal( path ) ) + path = this.parseConsecutive( path ).longPath; + + return parent.exts.call( this, path ); +} + +// + +function changeExt( path, ext ) +{ + let parent = this.path; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strDefined( path ) ); + _.assert( _.strIs( ext ) ); + + if( !this.isGlobal( path ) ) + return parent.changeExt.call( this, path, ext ); + + path = this.parseConsecutive( path ); + + path.longPath = parent.changeExt( path.longPath, ext ); + + return this.str( path ); +} + +// -- +// joiner +// -- + +function join_functor( gen ) +{ + + if( arguments.length === 2 ) + gen = { routineName : arguments[ 0 ], web : arguments[ 1 ] } + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.routine.assertOptions( join_functor, gen ); + + let routineName = gen.routineName; + let web = gen.web; + + return function joining() + { + + let parent = this.path; + let result = Object.create( null ); + let srcs = []; + let isGlobal = false; + + /* */ + + if( web ) + { + + for( let s = 0 ; s < arguments.length ; s++ ) + { + if( arguments[ s ] !== null && this.isGlobal( arguments[ s ] ) ) + { + isGlobal = true; + srcs[ s ] = this.parseAtomic( arguments[ s ] ); + } + else + { + isGlobal = arguments[ s ] !== null; + srcs[ s ] = { resourcePath : arguments[ s ] }; + } + } + + } + else + { + + for( let s = 0 ; s < arguments.length ; s++ ) + { + if( arguments[ s ] !== null && this.isGlobal( arguments[ s ] ) ) + { + isGlobal = true; + srcs[ s ] = this.parseConsecutive( arguments[ s ] ); + } + else + { + isGlobal = arguments[ s ] !== null; + srcs[ s ] = { longPath : arguments[ s ] }; + } + } + + } + + /* */ + + if( web ) + { + result.resourcePath = undefined; + } + else + { + result.longPath = undefined; + } + + /* */ + + for( let s = srcs.length-1 ; s >= 0 ; s-- ) + { + let src = srcs[ s ]; + + if( web ) + if( result.protocol && src.protocol ) + if( result.protocol !== src.protocol ) + continue; + + if( !result.protocol && src.protocol !== undefined ) + result.protocol = src.protocol; + + if( web ) + { + + let hostWas = result.host; + if( !result.host && src.host !== undefined ) + result.host = src.host; + + if( !result.user && src.user !== undefined ) + result.user = src.user; + + if( !result.port && src.port !== undefined ) + if( !hostWas || !src.host || hostWas === src.host ) + result.port = src.port; + + if( !result.resourcePath && src.resourcePath !== undefined ) + result.resourcePath = src.resourcePath; + else if( src.resourcePath ) + result.resourcePath = parent[ routineName ]( src.resourcePath, result.resourcePath ); + + if( src.resourcePath === null ) + break; + + } + else + { + + if( result.longPath === undefined && src.longPath !== undefined ) + result.longPath = src.longPath; + else if( src.longPath ) + result.longPath = parent[ routineName ]( src.longPath, result.longPath ); + + if( src.longPath === null ) + break; + + } + + if( src.query !== undefined ) + if( result.query ) + result.query = src.query + '&' + result.query; + else + result.query = src.query; + + if( !result.hash && src.hash !==undefined ) + result.hash = src.hash; + + if( !result.tag && src.tag !==undefined ) + result.tag = src.tag; + } + + /* */ + + if( !isGlobal ) + { + if( web ) + return result.resourcePath; + else + return result.longPath; + } + + if( ( result.hash || result.tag ) && result.longPath ) + result.longPath = parent.detrail( result.longPath ); + + return this.str( result ); + } + +} + +join_functor.defaults = +{ + routineName : null, + web : 0, +} + +// + +let join = join_functor({ routineName : 'join', web : 0 }); +let joinRaw = join_functor({ routineName : 'joinRaw', web : 0 }); +let reroot = join_functor({ routineName : 'reroot', web : 0 }); + +// + +function join_head( routine, args ) +{ + let o = args[ 0 ]; + + if( _.mapIs( o ) ) + _.assert( args.length === 1, 'Expects single options map {-o-}' ); + else + o = { args }; + + _.routine.options_( routine, o ); + _.assert( _.strIs( o.routineName ) ); + + return o; +} + +// + +function join_body( o ) +{ + let self = this; + let parent = self.path; + let isGlobal = false; + + /* */ + + let srcs = pathsParseConsecutiveAndSetIsGlobal( o.args ); + let result = resultMapMake( srcs ); + + /* */ + + if( !isGlobal ) + return result.longPath; + + if( ( result.hash || result.tag ) && result.longPath ) + result.longPath = parent.detrail( result.longPath ); + + return this.str( result ); + + /* */ + + function pathsParseConsecutiveAndSetIsGlobal( args ) + { + let result = _.array.make( args.length ); + + for( let s = 0 ; s < args.length ; s++ ) + { + if( args[ s ] !== null && self.isGlobal( args[ s ] ) ) + { + isGlobal = true; + result[ s ] = self.parseConsecutive( args[ s ] ); + } + else + { + isGlobal = args[ s ] !== null; + result[ s ] = { longPath : args[ s ] }; + } + } + + return result; + } + + /* */ + + function resultMapMake( srcs ) + { + let result = Object.create( null ); + result.resourcePath = undefined; + + for( let s = srcs.length - 1 ; s >= 0 ; s-- ) + { + let src = srcs[ s ]; + + if( !result.protocol && src.protocol !== undefined ) + result.protocol = src.protocol; + + if( result.longPath === undefined && src.longPath !== undefined ) + result.longPath = src.longPath; + else if( src.longPath ) + result.longPath = parent[ o.routineName ]( src.longPath, result.longPath ); + + if( src.longPath === null ) + break; + + if( src.query !== undefined ) + if( result.query ) + result.query = src.query + '&' + result.query; + else + result.query = src.query; + + if( !result.hash && src.hash !== undefined ) + result.hash = src.hash; + + if( !result.tag && src.tag !== undefined ) + result.tag = src.tag; + } + + return result; + } +} + +join_body.defaults = +{ + routineName : 'join', + args : null, +}; + +// + +let join_ = _.routine.uniteCloning_replaceByUnite( join_head, join_body ); + +// + +let joinRaw_ = _.routine.uniteCloning_replaceByUnite( join_head, join_body ); +joinRaw_.defaults.routineName = 'joinRaw'; + +// + +let reroot_ = _.routine.uniteCloning_replaceByUnite( join_head, join_body ); +reroot_.defaults.routineName = 'reroot'; + +// + +function resolve() +{ + let parent = this.path; + let args = [] + let hasNull; + + for( let i = arguments.length - 1 ; i >= 0 ; i-- ) + { + let arg = arguments[ i ]; + if( arg === null ) + { + hasNull = true; + break; + } + else + { + args.unshift( arg ); + } + } + + if( args.length === 0 ) + { + if( hasNull ) + return null; + else + return parent.resolve.call( this ); + } + + let result = this.join.apply( this, args ); + if( hasNull || this.isAbsolute( result ) ) + return result; + + let parsed = this.parseConsecutive( result ); + parsed.longPath = parent.join.call( this, parent.resolve.call( this, '.' ), parsed.longPath ); + return this.str( parsed ); +} + +// { +// let parent = this.path; +// return this.join( parent.resolve.call( this, '.' ), ... arguments ); +// } + +// { +// let parent = this.path; +// let joined = this.join.apply( this, arguments ); +// if( joined === null ) +// return joined; +// let parsed = this.parseConsecutive( joined ); +// parsed.longPath = parent.resolve.call( this, parsed.longPath ); /* xxx yyy */ +// // parsed.longPath = parent.resolve( parsed.longPath ); +// return this.str( parsed ); +// } + +// + +function relative_body( o ) +{ + let parent = this.path; + + _.routine.assertOptions( relative_body, arguments ); + + if( !this.isGlobal( o.basePath ) && !this.isGlobal( o.filePath ) ) + { + let o2 = _.props.extend( null, o ); + delete o2.global; + return this._relative( o2 ); + } + + let basePath = this.parseConsecutive( o.basePath ); + let filePath = this.parseConsecutive( o.filePath ); + + let o2 = _.props.extend( null, o ); + delete o2.global; + o2.basePath = basePath.longPath; + o2.filePath = filePath.longPath; + let longPath = parent._relative( o2 ); + + if( o.global ) + { + _.props.extend( filePath, basePath ); + // _.props.supplement( basePath, filePath ); + // return this.str( basePath ); + } + else + { + for( let c in filePath ) + { + if( c === 'longPath' ) + continue; + if( filePath[ c ] === basePath[ c ] ) + delete filePath[ c ]; + } + } + + filePath.longPath = longPath; + + return this.str( filePath ); +} + +var defaults = relative_body.defaults = Object.create( Parent.relative.defaults ); +defaults.global = 1; /* qqq : why is this option here? */ + +let relative = _.routine.uniteCloning_replaceByUnite( Parent.relative.head, relative_body ); + +// + +/* +qqq : teach common to work with path maps and cover it by tests | Dmytro : new task was to teach common work with uri maps, done +*/ + +function common() +{ + let parent = this.path; + let self = this; + let uris = _.arrayFlatten( null, arguments ); + + for( let s = uris.length-1 ; s >= 0 ; s-- ) + { + // _.assert( !_.mapIs( uris[ s ] ), 'not tested' ); + + /* Dmytro : added for : + _.uriNew.common( path1, path2 ); + _.uriNew.common( _.uriNew.parse( path1 ), _.uriNew.parse( path2 ) ); + має давати однаковий результат */ + + if( _.mapIs( uris[ s ] ) ) + uris[ s ] = self.str( uris[ s ] ); + } + + _.assert( _.strsAreAll( uris ), 'Expects only strings as arguments' ); + + /* */ + + if( !uris.length ) + return null; + + /* */ + + let isRelative = null; + for( let i = 0, len = uris.length ; i < len ; i++ ) + { + uris[ i ] = parse( uris[ i ] ); + let isThisRelative = parent.isRelative.call( this, uris[ i ].longPath ); + _.assert( isRelative === isThisRelative || isRelative === null, 'Attempt to combine relative with absolutue paths' ); + isRelative = isThisRelative; + } + + /* */ + + let result = _.props.extend( null, uris[ 0 ] ); + let protocol = null; + let withoutProtocol = 0; + + for( let i = 1, len = uris.length ; i < len ; i++ ) + { + + for( let c in result ) + if( uris[ i ][ c ] !== result[ c ] ) + delete result[ c ]; + + } + + /* */ + + for( let i = 0, len = uris.length; i < len; i++ ) + { + let uri = uris[ i ]; + + let protocol2 = uri.protocol || ''; + + if( protocol === null ) + { + protocol = uri.protocol; + continue; + } + + if( uri.protocol === protocol ) + continue; + + if( uri.protocol && protocol ) + return ''; + + withoutProtocol = 1; + + } + + if( withoutProtocol ) + protocol = ''; + + result.protocol = protocol; + result.longPath = result.longPath || uris[ 0 ].longPath; + + /* */ + + for( let i = 1, len = uris.length; i < len; i++ ) + { + let uri = uris[ i ]; + result.longPath = parent._commonPair.call( this, uri.longPath, result.longPath ); + } + + /* */ + + return this.str( result ); + + /* */ + + function parse( uri ) + { + let result; + + if( _.strIs( uri ) ) + if( self.isGlobal( uri ) ) + { + result = self.parseConsecutive( uri ); + } + else + { + result = { longPath : uri }; + } + + return result; + } + +} + +// + +function rebase( srcPath, oldPath, newPath ) +{ + let parent = this.path; + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + + srcPath = this.parseConsecutive( srcPath ); + oldPath = this.parseConsecutive( oldPath ); + newPath = this.parseConsecutive( newPath ); + + let dstPath = _.props.extend( null, srcPath, _.mapValsWithKeys( newPath, _.props.keys( srcPath ) ) ); + + // if( srcPath.protocol !== undefined && oldPath.protocol !== undefined ) + // { + // if( srcPath.protocol === oldPath.protocol && newPath.protocol === undefined ) + // delete dstPath.protocol; + // } + // + // if( srcPath.host !== undefined && oldPath.host !== undefined ) + // { + // if( srcPath.host === oldPath.host && newPath.host === undefined ) + // delete dstPath.host; + // } + + // dstPath.resourcePath = null; xxx + dstPath.longPath = parent.rebase.call( this, srcPath.longPath, oldPath.longPath, newPath.longPath ); + + return this.str( dstPath ); +} + +// + + +function dir_body( o ) +{ + let parent = this.path; + + if( !this.isGlobal( o.filePath ) ) + return parent.dir.body.call( this, o ); + + let o2 = _.props.extend( null, o ); + let filePath = this.parseConsecutive( o.filePath ); + o2.filePath = filePath.longPath + filePath.longPath = parent.dir.body.call( this, o2 ) + + return this.str( filePath ); +} + +_.assert( _.aux.is( Parent.dir.body.defaults ) ); +_.routineExtend( dir_body, Parent.dir.body ); + +let dir = _.routine.uniteCloning_replaceByUnite( Parent.dir.head, dir_body ); +_.props.extend( dir.defaults, Parent.dir.defaults ); + +let dirFirst = _.routine.uniteCloning_replaceByUnite( Parent.dirFirst.head, dir_body ); +_.props.extend( dirFirst.defaults, Parent.dirFirst.defaults ); + +// + +function groupTextualReport_head( routine, args ) +{ + let self = this; + let parent = this.path; + + let o = args[ 0 ]; + + _.assert( _.object.isBasic( o ), 'Expects object' ); + + let basePathParsed; + + if( !o.onRelative ) + o.onRelative = function onRelative( basePath, filePath ) + { + if( !basePathParsed ) + basePathParsed = self.parseConsecutive( basePath ); + + let filePathParsed = self.parseConsecutive( filePath ); + filePathParsed.longPath = self.relative( basePathParsed.longPath, filePathParsed.longPath ); + + let strOptions = { longPath : filePathParsed.longPath } + + if( !basePathParsed.hash ) + strOptions.hash = filePathParsed.hash; + if( !basePathParsed.tag ) + strOptions.tag = filePathParsed.tag; + if( !basePathParsed.protocol ) + strOptions.protocol = filePathParsed.protocol; + if( !basePathParsed.query ) + strOptions.query = filePathParsed.query; + + return self.str( strOptions ); + } + + return parent.groupTextualReport.head.call( self, routine, [ o ] ); +} + +let groupTextualReport = _.routine.uniteCloning_replaceByUnite( groupTextualReport_head, Parent.groupTextualReport.body ); + +// + +function commonTextualReport( filePath ) +{ + let self = this; + let parent = this.path; + + _.assert( arguments.length === 1 ); + + let basePathParsed; + let o = + { + filePath, + onRelative + } + return parent._commonTextualReport.call( self, o ); + + /* */ + + function onRelative( basePath, filePath ) + { + if( !basePathParsed ) + basePathParsed = self.parseConsecutive( basePath ); + + let filePathParsed = self.parseConsecutive( filePath ); + filePathParsed.longPath = self.relative( basePathParsed.longPath, filePathParsed.longPath ); + + let strOptions = { longPath : filePathParsed.longPath } + + if( !basePathParsed.hash ) + strOptions.hash = filePathParsed.hash; + if( !basePathParsed.tag ) + strOptions.tag = filePathParsed.tag; + if( !basePathParsed.protocol ) + strOptions.protocol = filePathParsed.protocol; + if( !basePathParsed.query ) + strOptions.query = filePathParsed.query; + + return self.str( strOptions ); + } +} + +// + +function moveTextualReport_head( routine, args ) +{ + let self = this; + let parent = this.path; + + let o = args[ 0 ]; + if( args[ 1 ] !== undefined ) + o = { dstPath : args[ 0 ], srcPath : args[ 1 ] } + + _.assert( _.object.isBasic( o ), 'Expects object' ); + + let basePathParsed; + + if( !o.onRelative ) + o.onRelative = function onRelative( basePath, filePath ) + { + if( !basePathParsed ) + basePathParsed = self.parseConsecutive( basePath ); + + let filePathParsed = self.parseConsecutive( filePath ); + filePathParsed.longPath = self.relative( basePathParsed.longPath, filePathParsed.longPath ); + + let strOptions = { longPath : filePathParsed.longPath } + + if( !basePathParsed.hash ) + strOptions.hash = filePathParsed.hash; + if( !basePathParsed.tag ) + strOptions.tag = filePathParsed.tag; + if( !basePathParsed.protocol ) + strOptions.protocol = filePathParsed.protocol; + if( !basePathParsed.query ) + strOptions.query = filePathParsed.query; + + return self.str( strOptions ); + } + + return parent.moveTextualReport.head.call( self, routine, [ o ] ); +} + +let moveTextualReport = _.routine.uniteCloning_replaceByUnite( moveTextualReport_head, Parent.moveTextualReport.body ); + +// + +/** + * Returns origin plus path without query part of uri string. + * @example + * + let path = 'https://www.site.com:13/path/name?query=here&and=here#anchor'; + wTools.uri.uri.documentGet( path, { withoutProtocol : 1 } ); + // 'www.site.com:13/path/name' + * @param {string} path uri string + * @param {Object} [o] o - options + * @param {boolean} o.withoutServer if true rejects origin part from result + * @param {boolean} o.withoutProtocol if true rejects protocol part from result uri + * @returns {string} Return document uri. + * @function documentGet + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function documentGet( path, o ) +{ + let self = this; + + o = o || Object.create( null ); + + if( path === undefined ) + path = _realGlobal_.location.href; + + if( path.indexOf( '//' ) === -1 ) + { + path = 'http:/' + ( path[ 0 ] === '/' ? '' : '/' ) + path; + } + + let a = path.split( '//' ); + let b = a[ 1 ].split( self.queryToken ); + + /* */ + + if( o.withoutServer ) + { + let i = b[ 0 ].indexOf( '/' ); + if( i === -1 ) i = 0; + return b[ 0 ].substr( i ); + } + else + { + if( o.withoutProtocol )return b[ 0 ]; + else return a[ 0 ] + '//' + b[ 0 ]; + } + +} + +documentGet.defaults = +{ + path : null, + withoutServer : null, + withoutProtocol : null, +} + +// + +/** + * Return origin (protocol + host + port) part of passed `path` string. If missed arguments, returns origin of + * current document. + * @example + * + let path = 'http://www.site.com:13/path/name?query=here' + wTools.uri.server( path ); + // 'http://www.site.com:13/' + * @param {string} [path] uri + * @returns {string} Origin part of uri. + * @function server + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function server( path ) +{ + let a, b; + + if( path === undefined ) + path = _realGlobal_.location.origin; + + if( path.indexOf( '//' ) === -1 ) + { + if( path[ 0 ] === '/' )return '/'; + a = [ '', path ] + } + else + { + a = path.split( '//' ); + a[ 0 ] += '//'; + } + + b = a[ 1 ].split( '/' ); + + return a[ 0 ] + b[ 0 ] + '/'; +} + +// + +/** + * Returns query part of uri. If method is called without arguments, it returns current query of current document uri. + * @example + let uri = 'http://www.site.com:13/path/name?query=here&and=here#anchor', + wTools.uri.query( uri ); // 'query=here&and=here#anchor' + * @param {string } [path] uri + * @returns {string} + * @function query + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function query( path ) +{ + let self = this; + if( path === undefined ) + path = _realGlobal_.location.href; + if( path.indexOf( self.queryToken ) === -1 ) + return ''; + return path.split( self.queryToken )[ 1 ]; +} + +// + +/** + * Parse a query string passed as a 'query' argument. Result is returned as a dictionary. + * The dictionary keys are the unique query variable names and the values are decoded from uri query variable values. + * @example + * + let query = 'k1=&k2=v2%20v3&k3=v4_v4'; + + let res = wTools.uri.dequery( query ); + // { + // k1 : '', + // k2 : 'v2 v3', + // k3 : 'v4_v4' + // }, + + * @param {string} query query string + * @returns {Object} + * @function dequery + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function dequery( query ) +{ + + let result = Object.create( null ); + query = query || _global.location.search.split( self.queryToken )[ 1 ]; + if( !query || !query.length ) + return result; + let vars = query.split( '&' ); + + for( let i = 0 ; i < vars.length ; i++ ) + { + + let w = vars[ i ].split( '=' ); + w[ 0 ] = decodeURIComponent( w[ 0 ] ); + if( w[ 1 ] === undefined ) w[ 1 ] = ''; + else w[ 1 ] = decodeURIComponent( w[ 1 ] ); + + if( ( w[ 1 ][ 0 ] === w[ 1 ][ w[ 1 ].length-1 ] ) && ( w[ 1 ][ 0 ] === '"' ) ) + w[ 1 ] = w[ 1 ].substr( 1, w[ 1 ].length-1 ); + + if( result[ w[ 0 ] ] === undefined ) + { + result[ w[ 0 ] ] = w[ 1 ]; + } + else if( _.strIs( result[ w[ 0 ] ] ) ) + { + result[ w[ 0 ] ] = result[ w[ 1 ] ] + } + else + { + result[ w[ 0 ] ].push( w[ 1 ] ); + } + + } + + return result; +} + +// -- +// relations +// -- + +let Parameters = +{ + + protocolToken : '://', + portToken : ':', + userToken : '@', + tagToken : '!', /* xxx : enable */ + // tagToken : '@', + hashToken : '#', + queryToken : '?', + +} + +// + +let Extension = +{ + + // internal + + _filterOnlyUrl, + _filterNoInnerArray, + + // dichotomy + + is, + isSafe, + isRefined, + isNormalized, + isAbsolute, + isRelative, + isRoot, + isDotted, + isTrailed, + isGlob, + + // transformer + + _parseOrigin, + _parseLongPath, + _parseHostFull, + + parse, + parseFull, + parseAtomic, + parseConsecutive, + localFromGlobal, + + str, + full, + + refine, + normalize, + canonize, + normalizeTolerant, + + dot, + + trail, + detrail, + + name, + ext, + exts, + changeExt, + + // joiner + + join_functor, + + join, + join_, /* !!! use instead of join */ /* Dmytro : routine contains no redundant 'if' statements for WebUri */ + joinRaw, + joinRaw_, /* !!! use instead of joinRaw */ /* Dmytro : routine contains no redundant 'if' statements for WebUri */ + reroot, + reroot_, /* !!! use instead of reroot */ /* Dmytro : routine contains no redundant 'if' statements for WebUri */ + resolve, + + relative, + common, + rebase, + + dir, + dirFirst, + + groupTextualReport, + commonTextualReport, + moveTextualReport, + + documentGet, + server, + query, + dequery, + + // fields + + single : Self, + + Uri, + UriFull, + UriAtomic, + UriConsequtive, + /* qqq : use this blueprints with help of method Blueprint.Rconstruct() */ + +} + +_.mapExtendDstNotOwn( Self, Extension ); +_.mapExtendDstNotOwn( Self, Parameters ); +_.mapExtendDstNotOwn( Self.Parameters, Parameters ); + +Self.Init(); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +if( typeof module !== 'undefined' ) +require( '../l4/UriOld.s' ); +if( typeof module !== 'undefined' ) +require( '../l5/Uris.s' ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wuribasic/proto/wtools/abase/l4/Uri.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wuribasic/proto/wtools/abase/l4' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Uri_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Uri_s */ })(); + +/* */ /* begin of file UriOld_s */ ( function UriOld_s() { function UriOld_s_naked() { ( function _UriOld_s_() +{ + +'use strict'; + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + + _.include( 'wPathBasic' ); + _.include( 'wBlueprint' ); + +} + +// + +const _global = _global_; +const _ = _global_.wTools; +const Parent = _.path; +const Self = _.uriOld = _.uriOld || Object.create( Parent ); +// _.uri = _.uriOld; + +// -- +// internal +// -- + +function _filterOnlyUrl( e, k, c ) +{ + if( _.strIs( k ) ) + { + if( _.strEnds( k, 'Url' ) ) + return true; + else + return false + } + return this.is( e ); +} + +// + +function _filterNoInnerArray( arr ) +{ + return arr.every( ( e ) => !_.arrayIs( e ) ); +} + +// -- +// dichotomy +// -- + +// '^(https?:\\/\\/)?' // protocol +// + '(\\/)?' // relative +// + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' // domain +// + '((\\d{1,3}\\.){3}\\d{1,3}))' // ip +// + '(\\:\\d+)?' // port +// + '(\\/[-a-z\\d%_.~+]*)*' // path +// + '(\\?[;&a-z\\d%_.~+=-]*)?' // query +// + '(\\#[-a-z\\d_]*)?$'; // anchor + +let isRegExpString = + '^([\w\d]*:\\/\\/)?' // protocol + + '(\\/)?' // relative + + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' // domain + + '((\\d{1,3}\\.){3}\\d{1,3}))' // ip + + '(\\:\\d+)?' // port + + '(\\/[-a-z\\d%_.~+]*)*' // path + + '(\\?[;&a-z\\d%_.~+=-]*)?' // query + + '(\\#[-a-z\\d_]*)?$'; // anchor + +let isRegExp = new RegExp( isRegExpString, 'i' ); +function is( path ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + return _.strIs( path ); +} + +// + +/** + * @summary Checks if provided uri is safe. + * @param {String} filePath Source uri + * @param {Number} level Level of check + * + * @example + * _.ur2.isSafe( 'https:///web.archive.org' )// false + * + * @example + * _.ur2.isSafe( 'https:///web.archive.org/root' )// true + * + * @returns {Boolean} Returns result of check for safetiness. + * @function isSafe + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isSafe( path, level ) +{ + let parent = this.path; + + _.assert( arguments.length === 1 || arguments.length === 2, 'Expects single argument' ); + _.assert( _.strDefined( path ) ); + + if( this.isGlobal( path ) ) + path = this.parseConsecutive( path ).longPath; + + return parent.isSafe.call( this, path, level ); +} + +/* +qqq : module:Tools? | Dmytro : changed similar to module wPathBasic +*/ + +// + +/** + * @summary Checks if provided uri is refined. + * @param {String} filePath Source uri + * + * @returns {Boolean} Returns true if {filePath} is refined, otherwise false. + * @function isRefined + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isRefined( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ).longPath; + + return parent.isRefined.call( this, filePath ); +} + +// // +// +// /** +// * @summary Checks if provided uri is refined. +// * @param {String} filePath Source uri +// * +// * @returns {Boolean} Returns true if {filePath} is refined, otherwise false. +// * @function isRefined +// * @module Tools/UriBasic +// * @namespace Tools.uri +// */ +// +// function isRefined( filePath ) +// { +// let parent = this.path; +// +// _.assert( arguments.length === 1, 'Expects single argument' ); +// _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); +// +// if( this.isGlobal( filePath ) ) +// filePath = this.parseConsecutive( filePath ).longPath; +// +// return parent.isRefined.call( this, filePath ); +// } + +// + +/** + * @summary Checks if provided uri is normalized. + * @param {String} filePath Source uri + * + * @returns {Boolean} Returns true if {filePath} is normalized, otherwise false. + * @function isNormalized + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isNormalized( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ).longPath; + + return parent.isNormalized.call( this, filePath ); +} + +// // +// +// /** +// * @summary Checks if provided uri is normalized. +// * @param {String} filePath Source uri +// * +// * @example +// * _.ur2.isNormalized( 'https:///web.archive.org' ); // returns true +// * +// * @example +// * _.ur2.isNormalized( 'https:/\\\\web.archive.org' ); // returns false +// * +// * @returns {Boolean} Returns true if {filePath} is normalized, otherwise false. +// * @function isNormalized +// * @module Tools/UriBasic +// * @namespace Tools.uri +// */ +// +// function isNormalized( path ) +// { +// _.assert( arguments.length === 1, 'Expects single argument' ); +// _.assert( _.strIs( path ), 'Expects string' ); +// return this.normalize( path ) === path; +// } + +// + +/** + * @summary Checks if provided uri is absolute. + * @param {String} filePath Source uri + * + * @example + * _.ur2.isAbsolute( 'https:/web.archive.org' )// false + * + * @example + * _.ur2.isAbsolute( 'https:///web.archive.org' )// true + * + * @returns {Boolean} Returns true if {filePath} is absolute, otherwise false. + * @function isAbsolute + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isAbsolute( path ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( path ), () => 'Expects string {-path-}, but got ' + _.entity.strType( path ) ); + + if( this.isGlobal( path ) ) + path = this.parseConsecutive( path ).longPath; + + return parent.isAbsolute.call( this, path ); +} + +// + +/** + * @summary Checks if provided uri is relative. + * @param {String} filePath Source uri + * + * @returns {Boolean} Returns true if {filePath} is relative, otherwise false. + * @function isRelative + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isRelative( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ).longPath; + + return parent.isRelative.call( this, filePath ); +} + +// + +/** + * @summary Checks if provided uri is root. + * @param {String} filePath Source uri + * + * @example + * _.ur2.isRoot( 'https:/web.archive.org' )// false + * + * @example + * _.ur2.isRoot( 'https:///' )// true + * + * @returns {Boolean} Returns true if {filePath} is root, otherwise false. + * @function isRoot + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isRoot( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ).longPath; + + return parent.isRoot.call( this, filePath ); +} + +// + +/** + * @summary Checks if provided uri begins with dot. + * @param {String} filePath Source uri + * + * @returns {Boolean} Returns true if path begins with dot, otherwise false. + * @function isDotted + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isDotted( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ).longPath; + + return parent.isDotted.call( this, filePath ); +} + +// + +/** + * @summary Checks if provided uri ends with slash. + * @param {String} filePath Source uri + * + * @returns {Boolean} Returns true if path ends with slash, otherwise false. + * @function isTrailed + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isTrailed( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ).longPath; + + return parent.isTrailed.call( this, filePath ); +} + +// + +/** + * @summary Checks if provided uri is glob. + * @param {String} filePath Source uri + * + * @returns {Boolean} Returns true if {filePath} is glob, otherwise false. + * @function isGlob + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function isGlob( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ), () => 'Expects string {-filePath-}, but got ' + _.entity.strType( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ).longPath; + + return parent.isGlob.call( this, filePath ); +} + +// -- +// transformer +// -- + +/** + * + * The URI component object. + * @typedef {Object} UrlComponents + * @property {string} protocol the URI's protocol scheme.; + * @property {string} host host portion of the URI; + * @property {string} port property is the numeric port portion of the URI + * @property {string} resourcePath the entire path section of the URI. + * @property {string} query the entire "query string" portion of the URI, not including '?' character. + * @property {string} hash property consists of the "fragment identifier" portion of the URI. + + * @property {string} uri the whole URI + * @property {string} hostFull host portion of the URI, including the port if specified. + * @property {string} origin protocol + host + port + * @private + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +let UriComponents = +{ + + /* atomic */ + + protocol : null, /* 'svn+http' */ + host : null, /* 'www.site.com' */ + port : null, /* '13' */ + resourcePath : null, /* '/path/name' */ + query : null, /* 'query=here&and=here' */ + hash : null, /* 'anchor' */ + tag : null, /* tag */ + + /* composite */ + + // qqq !!! : implement queries + // queries : null, /* { query : here, and : here } */ + longPath : null, /* www.site.com:13/path/name */ + postfixedPath : null, /* www.site.com:13/path/name?query=here#anchor@tag */ + protocols : null, /* [ 'svn','http' ] */ + hostFull : null, /* 'www.site.com:13' */ + origin : null, /* 'svn+http://www.site.com:13' */ + full : null, /* 'svn+http://www.site.com:13/path/name?query=here&and=here#anchor' */ + +} + +// + +/* +http://www.site.com:13/path/name?query=here&and=here#anchor +2 - protocol +3 - hostFull( host + port ) +5 - resourcePath +6 - query +8 - hash +*/ + +/*{ + 'protocol' : 'complex+protocol', + 'host' : 'www.site.com', + 'port' : '13', + 'query' : 'query=here&and=here', + 'hash' : 'anchor', + 'resourcePath' : '/!a.js?', + 'longPath' : 'www.site.com:13/!a.js?', +}*/ + +// let _uriParseRegexpStr = '^'; +// _uriParseRegexpStr += '(?:([^:/\\?#]*):)?'; /* protocol */ +// _uriParseRegexpStr += '(?:\/\/(([^:/\\?#]*)(?::([^/\\?#]*))?))?'; /* host and port */ +// _uriParseRegexpStr += '([^\\?#]*)'; /* local path */ +// _uriParseRegexpStr += '(?:\\?([^#]*))?'; /* query */ +// _uriParseRegexpStr += '(?:#(.*))?'; /* hash */ +// _uriParseRegexpStr += '$'; + +let _uriParseRegexpStr = '^'; /* begin */ + +let _uriParseRegexpProtocolStr = '([^:/\\?#]*)'; /* protocol */ +let _uriParseRegexpHostAndPortStr = ':\/\/(([^:/\\?#]*)(?::([^/\\?#]*))?)'; /* host and port */ +// let _uriParseRegexpHostAndPortStr = ':\/\/((\/?[^:/\\?#]*)(?::([^/\\?#]*))?)'; /* host and port */ + +_uriParseRegexpStr += '(?:' + _uriParseRegexpProtocolStr + _uriParseRegexpHostAndPortStr + ')?'; + +// _uriParseRegexpStr += '(.*?)'; /* rest yyy */ + +_uriParseRegexpStr += '([^?]*\\?[^:=#]*|[^?#]*)'; /* local path */ /* yyy */ +_uriParseRegexpStr += '(?:\\?([^#]*))?'; /* query */ +_uriParseRegexpStr += '(?:#([^]*))?'; /* hash */ +// _uriParseRegexpStr += '(?:@([^#]*))?'; /* tag */ + +_uriParseRegexpStr += '$'; /* end */ + +let _uriParseRegexp = new RegExp( _uriParseRegexpStr ); + +function parse_head( routine, args ) +{ + _.assert( args.length === 1, 'Expects single argument' ); + + let o = { srcPath : args[ 0 ] }; + + _.routine.options_( routine, o ); + _.assert( _.strIs( o.srcPath ) || _.mapIs( o.srcPath ) ); + _.assert( _.longHas( routine.Kind, o.kind ), () => 'Unknown kind of parsing ' + o.kind ); + + return o; +} + +function parse_body( o ) +{ + let self = this; + let result = Object.create( null ); + + if( _.mapIs( o.srcPath ) ) + { + _.map.assertHasOnly( o.srcPath, this.UriComponents ); + if( o.srcPath.protocols ) + return o.srcPath; + else if( o.srcPath.full ) + o.srcPath = o.srcPath.full; + else + o.srcPath = this.str( o.srcPath ); + } + + let splits = this._uriParseRegexp.exec( o.srcPath ); + _.sure( !!splits, 'Cant parse :', o.srcPath ); + + let params = ''; + + if( _.strIs( splits[ 1 ] ) ) + result.protocol = splits[ 1 ]; + if( _.strIs( splits[ 3 ] ) ) + result.host = splits[ 3 ]; + if( _.strIs( splits[ 4 ] ) ) + result.port = _.numberFromStrMaybe( splits[ 4 ] ); + + // _.assert( splits.length <= 6 ); /* yyy */ + // if( _.strIs( splits[ 5 ] ) ) + // { + // let delimeter = [ '@', '#', '?' ]; + // result.resourcePath = splits[ 5 ]; + // if( _.strHasAny( result.resourcePath, delimeter ) ) + // postfixesParse( delimeter ); + // } + + if( _.strIs( splits[ 5 ] ) ) /* yyy */ + { + result.resourcePath = splits[ 5 ]; + let isolatedSlash = _.strIsolateRightOrNone( result.resourcePath, '/' ); + if( isolatedSlash[ 2 ] ) + { + let isolated = _.strIsolateRightOrNone( isolatedSlash[ 2 ], '@' ); + if( isolated[ 2 ] ) + { + result.tag = isolated[ 2 ]; + result.resourcePath = isolatedSlash[ 0 ] + isolatedSlash[ 1 ] + isolated[ 0 ] + params += '@' + result.tag; + } + } + } + if( _.strIs( splits[ 6 ] ) ) + { + result.query = splits[ 6 ]; + params += '?' + result.query; + let isolated = _.strIsolateRightOrNone( result.query, '@' ); + if( isolated[ 2 ] ) + { + result.tag = isolated[ 2 ]; + result.query = isolated[ 0 ] + } + } + if( _.strIs( splits[ 7 ] ) ) + { + result.hash = splits[ 7 ]; + params += '#' + result.hash; + let isolated = _.strIsolateRightOrNone( result.hash, '@' ); + if( isolated[ 2 ] ) + { + result.tag = isolated[ 2 ]; + result.hash = isolated[ 0 ] + } + } + + /* */ + + if( o.kind === 'full' ) + { + let hostFull = splits[ 2 ] || ''; + result.longPath = hostFull + result.resourcePath; + result.postfixedPath = result.longPath + params; + if( result.protocol ) + result.protocols = result.protocol.split( '+' ); + else + result.protocols = []; + if( _.strIs( splits[ 2 ] ) ) + result.hostFull = splits[ 2 ]; + if( _.strIs( result.protocol ) || _.strIs( result.hostFull ) ) + result.origin = ( _.strIs( result.protocol ) ? result.protocol + '://' : '//' ) + result.hostFull; + result.full = o.srcPath; + } + else if( o.kind === 'consecutive' ) + { + let hostFull = splits[ 2 ] || ''; + result.longPath = hostFull + result.resourcePath; + result.postfixedPath = result.longPath + params; /* xxx : redundat! */ + delete result.host; + delete result.port; + delete result.resourcePath; + } + + return result; + + /* */ + + // function longPathWithParamsForm() + // { + // let postfixedPath = result.longPath; + // if( result.query ) + // postfixedPath += '?' + result.query; + // if( result.hash ) + // postfixedPath += '#' + result.hash; + // if( result.tag ) + // postfixedPath += '@' + result.tag; + // return postfixedPath; + // } + + // function isolateTagFrom( src ) + // { + // let result = _.strIsolateRightOrNone( src, '@' ); + // if( result[ 2 ] ) + // result.tag = result[ 2 ]; + // return result[ 0 ]; + // } + + /* */ + + function postfixesParse( delimeter ) + { + + let rest = ''; + let splits2 = _.path.split( result.resourcePath ); + let left, s; + for( s = 0 ; s < splits2.length ; s++ ) + { + let split = splits2[ s ]; + if( _.path._unescape( split ).wasEscaped ) + continue; + left = _.strLeft_( split, delimeter ); + if( left.entry ) + { + if( s > 0 ) + { + result.resourcePath = splits2.slice( 0, s ).join( self.upToken ); + result.resourcePath += self.upToken + split.slice( 0, left.index ); + } + else + { + result.resourcePath = split.slice( 0, left.index ); + } + split = split.slice( left.index + 1 ); + splits2[ s ] = split + rest = splits2.slice( s ).join( self.upToken ); + break; + } + } + + if( left && left.entry ) + restParse( rest, left.entry, delimeter ); + + } + + /* */ + + function restParse( rest, entry, delimeter ) + { + + _.arrayRemoveOnceStrictly( delimeter, entry ); + + let isolates = _.strIsolateRightOrNone( rest, delimeter ); + + rest = isolates[ 0 ]; + + if( isolates[ 1 ] ) + { + restParse( isolates[ 2 ], isolates[ 1 ], delimeter ); + } + + if( entry === '?' ) + result.query = rest; + else if( entry === '#' ) + result.hash = rest; + else if( entry === '@' ) + result.tag = rest; + + } + +} + +parse_body.defaults = +{ + srcPath : null, + kind : 'full', +} + +parse_body.components = UriComponents; + +parse_body.Kind = [ 'full', 'atomic', 'consecutive' ]; + +// + +/** + * Method parses URI string, and returns a UrlComponents object. + * @example + * + let uri = 'http://www.site.com:13/path/name?query=here&and=here#anchor' + + wTools.uri.parse( uri ); + + // { + // protocol : 'http', + // hostFull : 'www.site.com:13', + // resourcePath : /path/name, + // query : 'query=here&and=here', + // hash : 'anchor', + // host : 'www.site.com', + // port : '13', + // origin : 'http://www.site.com:13' + // } + + * @param {string} path Url to parse + * @param {Object} o - parse parameters + included into result + * @returns {UrlComponents} Result object with parsed uri components + * @throws {Error} If passed `path` parameter is not string + * @function parse + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +let parse = _.routine.uniteCloning_replaceByUnite( parse_head, parse_body ); + +parse.components = UriComponents; + +// + +let parseFull = _.routine.uniteCloning_replaceByUnite( parse_head, parse_body ); +parseFull.defaults.kind = 'full'; +parseFull.components = UriComponents; + +// + +let parseAtomic = _.routine.uniteCloning_replaceByUnite( parse_head, parse_body ); +parseAtomic.defaults.kind = 'atomic'; + +parseAtomic.components = UriComponents; + +// + +let parseConsecutive = _.routine.uniteCloning_replaceByUnite( parse_head, parse_body ); +parseConsecutive.defaults.kind = 'consecutive'; + +// + +function localFromGlobal( globalPath ) +{ + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.boolLike( globalPath ) ) + return globalPath; + + if( _.strIs( globalPath ) ) + { + if( !this.isGlobal( globalPath ) ) + return globalPath; + + globalPath = this.parseConsecutive( globalPath ); + } + + _.assert( _.mapIs( globalPath ) ) ; + _.assert( _.strIs( globalPath.longPath ) ); + + return globalPath.longPath; +} + +// + +/** + * Assembles uri string from components + * + * @example + * + let components = + { + protocol : 'http', + host : 'www.site.com', + port : '13', + resourcePath : '/path/name', + query : 'query=here&and=here', + hash : 'anchor', + }; + wTools.uri.str( UrlComponents ); + // 'http://www.site.com:13/path/name?query=here&and=here#anchor' + * @param {UrlComponents} components Components for uri + * @returns {string} Complete uri string + * @throws {Error} If `components` is not UrlComponents map + * @see {@link UrlComponents} + * @function str + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function str( c ) +{ + let self = this; + let result = ''; + + _.assert( c.longPath === undefined || c.longPath === null || longPathHas( c ), 'Codependent components of URI map are not consistent', 'something wrong with {-longPath-}' ); + _.assert( c.protocols === undefined || c.protocols === null || protocolsHas( c ), 'Codependent components of URI map are not consistent', 'something wrong with {-protocols-}' ); + _.assert( c.hostFull === undefined || c.hostFull === null || hostFullHas( c ), 'Codependent components of URI map are not consistent', 'something wrong with {-hostFull-}' ); + _.assert( c.origin === undefined || c.origin === null || originHas( c ), 'Codependent components of URI map are not consistent', 'something wrong with {-origin-}' ); + _.assert( c.full === undefined || c.full === null || fullHas( c ), 'Codependent components of URI map are not consistent', 'something wrong with {-full-}' ); + + _.assert( _.strIs( c ) || _.mapIs( c ) ); + _.assert( arguments.length === 1, 'Expects single argument' ); + + if( _.strIs( c ) ) + return c; + + _.map.assertHasOnly( c, this.UriComponents ); + + if( c.full ) + { + _.assert( _.strDefined( c.full ) ); + return c.full; + } + + var protocol = c.protocol; + var host = c.host; + var port = c.port; + + if( c.origin && ( protocol === null || protocol === undefined ) ) + if( _.strHas( c.origin, '://' ) ) + { + protocol = _.strIsolateLeftOrNone( c.origin, '://' )[ 0 ]; + } + + if( ( protocol === null || protocol === undefined ) && c.protocols && c.protocols.length ) + protocol = c.protocols.join( '+' ); + + if( c.origin && ( host === null || host === undefined ) ) + { + host = c.origin; + host = _.strIsolateRightOrAll( host, '://' )[ 2 ]; + host = _.strIsolateLeftOrAll( host, ':' )[ 0 ]; + // host = _.strIsolateInside( c.origin, '://', ':' )[ 2 ]; + } + + if( c.origin && ( port === null || port === undefined ) ) + if( _.strHas( c.origin, ':' ) ) + { + port = _.strIsolateRightOrNone( c.origin, ':' )[ 2 ]; + } + + // /* atomic */ + // + // protocol : null, /* 'svn+http' */ + // host : null, /* 'www.site.com' */ + // port : null, /* '13' */ + // resourcePath : null, /* '/path/name' */ + // query : null, /* 'query=here&and=here' */ + // hash : null, /* 'anchor' */ + // + // /* composite */ + // + // longPath : null, /* www.site.com:13/path/name */ + // protocols : null, /* [ 'svn','http' ] */ + // hostFull : null, /* 'www.site.com:13' */ + // origin : null, /* 'svn+http://www.site.com:13' */ + // full : null, /* 'svn+http://www.site.com:13/path/name?query=here&and=here#anchor' */ + + return fullFrom( c ); + + /* */ + + return result; + + /**/ + + function longPathFrom( c ) + { + + let hostFull = c.hostFull; + if( !_.strIs( hostFull ) ) + hostFull = hostFullFrom( c ); + + if( _.strIs( c.resourcePath ) ) + { + if( c.resourcePath && hostFull && !_.strBegins( c.resourcePath, self.upToken ) ) + return hostFull + self.upToken + c.resourcePath; + else + return hostFull + c.resourcePath; + } + else + { + _.assert( _.strBegins( c.longPath, hostFull ) ); + return c.longPath; + } + + } + + /* */ + + function longPathHas( c ) + { + + if( c.host ) + if( !_.strBegins( c.longPath, c.host ) ) + return false; + + if( c.port !== undefined && c.port !== null ) + if( !_.strHas( c.longPath, String( c.port ) ) ) + return false; + + if( c.resourcePath ) + if( !_.strEnds( c.longPath, c.resourcePath ) ) + return false; + + return true; + } + + /* */ + + function protocolsFrom( c ) + { + return protocol.split( '+' ); + } + + /* */ + + function protocolsHas( c ) + { + if( c.protocol !== null && c.protocol !== undefined ) + if( c.protocols.join( '+' ) !== c.protocol ) + return false; + return true; + } + + /* */ + + function hostFullFrom( c ) + { + + // if( host === undefined || host === null ) + // return c.hostFull; + + let hostFull = ''; + if( _.strIs( host ) ) + hostFull = host; + if( port !== undefined && port !== null ) + if( hostFull ) + hostFull += ':' + port; + else + hostFull = ':' + port; + return hostFull; + } + + /* */ + + function hostFullHas( c ) + { + + if( c.host ) + if( !_.strBegins( c.hostFull, c.host ) ) + return false; + + if( c.port !== null && c.port !== undefined ) + if( !_.strHas( c.hostFull, String( c.port ) ) ) + return false; + + return true; + } + + /* */ + + function originFrom( c ) + { + let result = ''; + let hostFull; + + if( c.hostFull ) + { + hostFull = c.hostFull; + } + else + { + hostFull = hostFullFrom( c ); + } + + if( _.strIs( protocol ) && !hostFull ) + hostFull = ''; + + if( _.strIs( protocol ) || _.strIs( hostFull ) ) + result += ( _.strIs( protocol ) ? protocol + '://' : '//' ) + hostFull; + + return result; + } + + /* */ + + function originHas( c ) + { + + if( c.protocol ) + if( !_.strBegins( c.origin, c.protocol ) ) + return false; + + if( c.host ) + if( !_.strHas( c.origin, c.host ) ) + return false; + + if( c.port !== null && c.port !== undefined ) + if( !_.strHas( c.origin, String( c.port ) ) ) + return false; + + return true; + } + + /* */ + + function fullFrom( c ) + { + + if( _.strIs( protocol ) || _.strIs( c.hostFull ) || _.strIs( host ) ) + result += _.strIs( protocol ) ? protocol + '://' : '//'; + + if( c.longPath ) + { + result += c.longPath; + } + else + { + result += longPathFrom( c ); + } + + /**/ + + if( _.mapIs( c.query ) ) + c.query = _.strWebQueryStr({ src : c.query }); + + _.assert( !c.query || _.strIs( c.query ) ); + + if( c.query !== undefined && c.query !== undefined ) + result += '?' + c.query; + + if( c.hash !== undefined && c.hash !== null ) + result += '#' + c.hash; + + if( c.tag !== undefined && c.tag !== null ) + result += '@' + c.tag; + + return result; + } + + /* */ + + function fullHas( c ) + { + if( c.protocol ) + if( !_.strBegins( c.full, c.protocol ) ) + return false; + + if( c.host ) + if( !_.strHas( c.full, c.host ) ) + return false; + + if( c.port !== null && c.port !== undefined ) + if( !_.strHas( c.full, String( c.host ) ) ) + return false; + + if( c.resourcePath ) + if( !_.strHas( c.full, String( c.resourcePath ) ) ) + return false; + + if( c.query ) + if( !_.strHas( c.full, String( c.query ) ) ) + return false; + + if( c.hash ) + if( !_.strHas( c.full, String( c.hash ) ) ) + return false; + + if( c.tag ) + if( !_.strHas( c.full, String( c.tag ) ) ) + return false; + + if( c.longPath ) + if( !_.strHas( c.full, String( c.longPath ) ) ) + return false; + + return true; + } + +} + +str.components = UriComponents; + +// + +/** + * Complements current window uri origin by components passed in o. + * All components of current origin is replaced by appropriates components from o if they exist. + * If { o.full } exists and valid, method returns it. + * @example + * // current uri http://www.site.com:13/foo/baz + let components = + { + resourcePath : '/path/name', + query : 'query=here&and=here', + hash : 'anchor', + }; + let res = wTools.uri.full( o ); + // 'http://www.site.com:13/path/name?query=here&and=here#anchor' + * + * @returns {string} composed uri + * @function full + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function full( o ) +{ + + _.assert( arguments.length === 1 ); + _.assert( this.is( o ) || _.mapIs( o ) ); + + if( _.strIs( o ) ) + o = this.parseAtomic( o ) + + _.map.assertHasOnly( o, this.UriComponents ); + + // if( o.full ) + // return this.str( o ); + + if( !_realGlobal_.location ) + return this.str( o ); + + let serverUri = this.server(); + let serverParsed = this.parseAtomic( serverUri ); + + _.props.extend( serverParsed, o ); + + return this.str( serverParsed ); +} + +// + +function refine( filePath ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( filePath ) ); + + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ); + else + return parent.refine.call( this, filePath ); + + if( _.strDefined( filePath.longPath ) ) + filePath.longPath = parent.refine.call( this, filePath.longPath ); + + if( filePath.hash || filePath.tag ) + filePath.longPath = parent.detrail( filePath.longPath ); + + return this.str( filePath ); +} + +function normalize( filePath ) +{ + let parent = this.path; + _.assert( _.strIs( filePath ), 'Expects string {-filePath-}' ); + if( _.strIs( filePath ) ) + { + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ); + else + return parent.normalize.call( this, filePath ); + } + _.assert( !!filePath ); + filePath.longPath = parent.normalize.call( this, filePath.longPath ); + return this.str( filePath ); +} + +// + +function canonize( filePath ) +{ + let parent = this.path; + if( _.strIs( filePath ) ) + { + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ); + else + return parent.canonize.call( this, filePath ); + } + _.assert( !!filePath ); + filePath.longPath = parent.canonize.call( this, filePath.longPath ); + return this.str( filePath ); +} + +// + +function normalizeTolerant( filePath ) +{ + let parent = this.path; + if( _.strIs( filePath ) ) + { + if( this.isGlobal( filePath ) ) + filePath = this.parseConsecutive( filePath ); + else + return parent.normalizeTolerant.call( this, filePath ); + } + _.assert( !!filePath ); + filePath.longPath = parent.normalizeTolerant.call( this, filePath.longPath ); + return this.str( filePath ); +} + +// + +function dot( path ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strDefined( path ) ); + + if( !this.isGlobal( path ) ) + return parent.dot.call( this, path ); + + path = this.parseConsecutive( path ); + path.longPath = parent.dot( path.longPath ); + + return this.str( path ); +} + +// + +function trail( srcPath ) +{ + _.assert( arguments.length === 1 ); + return this.path.trail( srcPath ); +} + +// + +function detrail( srcPath ) +{ + _.assert( this.is( srcPath ) ); + _.assert( arguments.length === 1 ); + + // debugger; + if( _.strIs( srcPath ) ) + srcPath = this.parseConsecutive( srcPath ); + + srcPath.longPath = this.path.detrail( srcPath.longPath ); + + return this.str( srcPath ); +} + +// + +function name( o ) +{ + let parent = this.path; + if( _.strIs( o ) ) + o = { path : o } + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.mapIs( o ) ); + _.assert( _.strIs( o.path ) ); + _.routine.options_( name, o ); + + if( !this.isGlobal( o.path ) ) + return parent.name.call( this, o ); + + let path = this.parseConsecutive( o.path ); + + let o2 = _.props.extend( null, o ); + o2.path = path.longPath; + return parent.name.call( this, o2 ); +} + +name.defaults = Object.create( Parent.name.defaults ); + +// + +function ext( path ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strIs( path ), 'Expects string' ); + + if( this.isGlobal( path ) ) + path = this.parseConsecutive( path ).longPath; + + return parent.ext.call( this, path ); +} + +// + +function exts( path ) +{ + let parent = this.path; + + _.assert( arguments.length === 1, 'Expects single argument' ); + _.assert( _.strDefined( path ) ); + + if( this.isGlobal( path ) ) + path = this.parseConsecutive( path ).longPath; + + return parent.exts.call( this, path ); +} + +// + +function changeExt( path, ext ) +{ + let parent = this.path; + + _.assert( arguments.length === 2, 'Expects exactly two arguments' ); + _.assert( _.strDefined( path ) ); + _.assert( _.strIs( ext ) ); + + if( !this.isGlobal( path ) ) + return parent.changeExt.call( this, path, ext ); + + path = this.parseConsecutive( path ); + + path.longPath = parent.changeExt( path.longPath, ext ); + + return this.str( path ); +} + +// -- +// joiner +// -- + +function join_functor( gen ) +{ + + if( arguments.length === 2 ) + gen = { routineName : arguments[ 0 ], web : arguments[ 1 ] } + + _.assert( arguments.length === 1 || arguments.length === 2 ); + _.routine.assertOptions( join_functor, gen ); + + let routineName = gen.routineName; + let web = gen.web; + + return function joining() + { + + let parent = this.path; + let result = Object.create( null ); + let srcs = []; + let isGlobal = false; + + /* */ + + if( web ) + { + + for( let s = 0 ; s < arguments.length ; s++ ) + { + if( arguments[ s ] !== null && this.isGlobal( arguments[ s ] ) ) + { + isGlobal = true; + srcs[ s ] = this.parseAtomic( arguments[ s ] ); + } + else + { + isGlobal = arguments[ s ] !== null; + srcs[ s ] = { resourcePath : arguments[ s ] }; + } + } + + } + else + { + + for( let s = 0 ; s < arguments.length ; s++ ) + { + if( arguments[ s ] !== null && this.isGlobal( arguments[ s ] ) ) + { + isGlobal = true; + srcs[ s ] = this.parseConsecutive( arguments[ s ] ); + } + else + { + isGlobal = arguments[ s ] !== null; + srcs[ s ] = { longPath : arguments[ s ] }; + } + } + + } + + /* */ + + if( web ) + { + result.resourcePath = undefined; + } + else + { + result.longPath = undefined; + } + + /* */ + + for( let s = srcs.length-1 ; s >= 0 ; s-- ) + { + let src = srcs[ s ]; + + if( web ) + if( result.protocol && src.protocol ) + if( result.protocol !== src.protocol ) + continue; + + if( !result.protocol && src.protocol !== undefined ) + result.protocol = src.protocol; + + if( web ) + { + + let hostWas = result.host; + if( !result.host && src.host !== undefined ) + result.host = src.host; + + if( !result.port && src.port !== undefined ) + if( !hostWas || !src.host || hostWas === src.host ) + result.port = src.port; + + if( !result.resourcePath && src.resourcePath !== undefined ) + result.resourcePath = src.resourcePath; + else if( src.resourcePath ) + result.resourcePath = parent[ routineName ]( src.resourcePath, result.resourcePath ); + + if( src.resourcePath === null ) + break; + + } + else + { + + if( result.longPath === undefined && src.longPath !== undefined ) + result.longPath = src.longPath; + else if( src.longPath ) + result.longPath = parent[ routineName ]( src.longPath, result.longPath ); + + if( src.longPath === null ) + break; + + } + + if( src.query !== undefined ) + if( result.query ) + result.query = src.query + '&' + result.query; + else + result.query = src.query; + + if( !result.hash && src.hash !==undefined ) + result.hash = src.hash; + + if( !result.tag && src.tag !==undefined ) + result.tag = src.tag; + } + + /* */ + + if( !isGlobal ) + { + if( web ) + return result.resourcePath; + else + return result.longPath; + } + + if( ( result.hash || result.tag ) && result.longPath ) + result.longPath = parent.detrail( result.longPath ); + + return this.str( result ); + } + +} + +join_functor.defaults = +{ + routineName : null, + web : 0, +} + +// + +let join = join_functor({ routineName : 'join', web : 0 }); +let joinRaw = join_functor({ routineName : 'joinRaw', web : 0 }); +let reroot = join_functor({ routineName : 'reroot', web : 0 }); + +// + +function resolve() +{ + let parent = this.path; + let joined = this.join.apply( this, arguments ); + if( joined === null ) + return joined; + let parsed = this.parseConsecutive( joined ); + parsed.longPath = parent.resolve.call( this, parsed.longPath ); + return this.str( parsed ); +} + +// + +function relative_body( o ) +{ + let parent = this.path; + + _.routine.assertOptions( relative_body, arguments ); + + if( !this.isGlobal( o.basePath ) && !this.isGlobal( o.filePath ) ) + { + let o2 = _.props.extend( null, o ); + delete o2.global; + return this._relative( o2 ); + } + + let basePath = this.parseConsecutive( o.basePath ); + let filePath = this.parseConsecutive( o.filePath ); + + let o2 = _.props.extend( null, o ); + delete o2.global; + o2.basePath = basePath.longPath; + o2.filePath = filePath.longPath; + let longPath = parent._relative( o2 ); + + if( o.global ) + { + _.props.extend( filePath, basePath ); + // _.props.supplement( basePath, filePath ); + // return this.str( basePath ); + } + else + { + for( let c in filePath ) + { + if( c === 'longPath' ) + continue; + if( filePath[ c ] === basePath[ c ] ) + delete filePath[ c ]; + } + } + + filePath.longPath = longPath; + + return this.str( filePath ); +} + +var defaults = relative_body.defaults = Object.create( Parent.relative.defaults ); +defaults.global = 1; /* qqq : why is this option here? */ + +let relative = _.routine.uniteCloning_replaceByUnite( Parent.relative.head, relative_body ); + +// + +/* +qqq : teach common to work with path maps and cover it by tests | Dmytro : new task was to teach common work with uri maps, done +*/ + +function common() +{ + let parent = this.path; + let self = this; + let uris = _.arrayFlatten( null, arguments ); + + for( let s = uris.length-1 ; s >= 0 ; s-- ) + { + // _.assert( !_.mapIs( uris[ s ] ), 'not tested' ); + + /* Dmytro : added for : + _.ur2.common( path1, path2 ); + _.ur2.common( _.ur2.parse( path1 ), _.ur2.parse( path2 ) ); + має давати однаковий результат */ + + if( _.mapIs( uris[ s ] ) ) + uris[ s ] = self.str( uris[ s ] ); + } + + _.assert( _.strsAreAll( uris ), 'Expects only strings as arguments' ); + + /* */ + + if( !uris.length ) + return null; + + /* */ + + let isRelative = null; + for( let i = 0, len = uris.length ; i < len ; i++ ) + { + uris[ i ] = parse( uris[ i ] ); + let isThisRelative = parent.isRelative.call( this, uris[ i ].longPath ); + _.assert( isRelative === isThisRelative || isRelative === null, 'Attempt to combine relative with absolutue paths' ); + isRelative = isThisRelative; + } + + /* */ + + let result = _.props.extend( null, uris[ 0 ] ); + let protocol = null; + let withoutProtocol = 0; + + for( let i = 1, len = uris.length ; i < len ; i++ ) + { + + for( let c in result ) + if( uris[ i ][ c ] !== result[ c ] ) + delete result[ c ]; + + } + + /* */ + + for( let i = 0, len = uris.length; i < len; i++ ) + { + let uri = uris[ i ]; + + let protocol2 = uri.protocol || ''; + + if( protocol === null ) + { + protocol = uri.protocol; + continue; + } + + if( uri.protocol === protocol ) + continue; + + if( uri.protocol && protocol ) + return ''; + + withoutProtocol = 1; + + } + + if( withoutProtocol ) + protocol = ''; + + result.protocol = protocol; + result.longPath = result.longPath || uris[ 0 ].longPath; + + /* */ + + for( let i = 1, len = uris.length; i < len; i++ ) + { + let uri = uris[ i ]; + result.longPath = parent._commonPair.call( this, uri.longPath, result.longPath ); + } + + /* */ + + return this.str( result ); + + /* */ + + function parse( uri ) + { + let result; + + if( _.strIs( uri ) ) + if( self.isGlobal( uri ) ) + { + result = self.parseConsecutive( uri ); + } + else + { + result = { longPath : uri }; + } + + return result; + } + +} + +// + +function rebase( srcPath, oldPath, newPath ) +{ + let parent = this.path; + _.assert( arguments.length === 3, 'Expects exactly three arguments' ); + + srcPath = this.parseConsecutive( srcPath ); + oldPath = this.parseConsecutive( oldPath ); + newPath = this.parseConsecutive( newPath ); + + let dstPath = _.props.extend( null, srcPath, _.mapValsWithKeys( newPath, _.props.keys( srcPath ) ) ); + + // if( srcPath.protocol !== undefined && oldPath.protocol !== undefined ) + // { + // if( srcPath.protocol === oldPath.protocol && newPath.protocol === undefined ) + // delete dstPath.protocol; + // } + // + // if( srcPath.host !== undefined && oldPath.host !== undefined ) + // { + // if( srcPath.host === oldPath.host && newPath.host === undefined ) + // delete dstPath.host; + // } + + // dstPath.resourcePath = null; xxx + dstPath.longPath = parent.rebase.call( this, srcPath.longPath, oldPath.longPath, newPath.longPath ); + + return this.str( dstPath ); +} + +// + + +function dir_body( o ) +{ + let parent = this.path; + + if( !this.isGlobal( o.filePath ) ) + return parent.dir.body.call( this, o ); + + let o2 = _.props.extend( null, o ); + let filePath = this.parseConsecutive( o.filePath ); + o2.filePath = filePath.longPath + filePath.longPath = parent.dir.body.call( this, o2 ) + + return this.str( filePath ); +} + +// _.routineExtend( dir_body, Parent.dir ); +_.assert( _.aux.is( Parent.dir.body.defaults ) ); +_.routineExtend( dir_body, Parent.dir.body ); + +let dir = _.routine.uniteCloning_replaceByUnite( Parent.dir.head, dir_body ); +_.props.extend( dir.defaults, Parent.dir.defaults ); + +let dirFirst = _.routine.uniteCloning_replaceByUnite( Parent.dirFirst.head, dir_body ); +_.props.extend( dirFirst.defaults, Parent.dirFirst.defaults ); + +// + +function groupTextualReport_head( routine, args ) +{ + let self = this; + let parent = this.path; + + let o = args[ 0 ]; + + _.assert( _.object.isBasic( o ), 'Expects object' ); + + let basePathParsed; + + if( !o.onRelative ) + o.onRelative = function onRelative( basePath, filePath ) + { + if( !basePathParsed ) + basePathParsed = self.parseConsecutive( basePath ); + + let filePathParsed = self.parseConsecutive( filePath ); + filePathParsed.longPath = self.relative( basePathParsed.longPath, filePathParsed.longPath ); + + let strOptions = { longPath : filePathParsed.longPath } + + if( !basePathParsed.hash ) + strOptions.hash = filePathParsed.hash; + if( !basePathParsed.tag ) + strOptions.tag = filePathParsed.tag; + if( !basePathParsed.protocol ) + strOptions.protocol = filePathParsed.protocol; + if( !basePathParsed.query ) + strOptions.query = filePathParsed.query; + + return self.str( strOptions ); + } + + return parent.groupTextualReport.head.call( self, routine, [ o ] ); +} + +let groupTextualReport = _.routine.uniteCloning_replaceByUnite( groupTextualReport_head, Parent.groupTextualReport.body ); + +// + +function commonTextualReport( filePath ) +{ + let self = this; + let parent = this.path; + + _.assert( arguments.length === 1 ); + + let basePathParsed; + let o = + { + filePath, + onRelative + } + return parent._commonTextualReport.call( self, o ); + + /* */ + + function onRelative( basePath, filePath ) + { + if( !basePathParsed ) + basePathParsed = self.parseConsecutive( basePath ); + + let filePathParsed = self.parseConsecutive( filePath ); + filePathParsed.longPath = self.relative( basePathParsed.longPath, filePathParsed.longPath ); + + let strOptions = { longPath : filePathParsed.longPath } + + if( !basePathParsed.hash ) + strOptions.hash = filePathParsed.hash; + if( !basePathParsed.tag ) + strOptions.tag = filePathParsed.tag; + if( !basePathParsed.protocol ) + strOptions.protocol = filePathParsed.protocol; + if( !basePathParsed.query ) + strOptions.query = filePathParsed.query; + + return self.str( strOptions ); + } +} + +// + +function moveTextualReport_head( routine, args ) +{ + let self = this; + let parent = this.path; + + let o = args[ 0 ]; + if( args[ 1 ] !== undefined ) + o = { dstPath : args[ 0 ], srcPath : args[ 1 ] } + + _.assert( _.object.isBasic( o ), 'Expects object' ); + + let basePathParsed; + + if( !o.onRelative ) + o.onRelative = function onRelative( basePath, filePath ) + { + if( !basePathParsed ) + basePathParsed = self.parseConsecutive( basePath ); + + let filePathParsed = self.parseConsecutive( filePath ); + filePathParsed.longPath = self.relative( basePathParsed.longPath, filePathParsed.longPath ); + + let strOptions = { longPath : filePathParsed.longPath } + + if( !basePathParsed.hash ) + strOptions.hash = filePathParsed.hash; + if( !basePathParsed.tag ) + strOptions.tag = filePathParsed.tag; + if( !basePathParsed.protocol ) + strOptions.protocol = filePathParsed.protocol; + if( !basePathParsed.query ) + strOptions.query = filePathParsed.query; + + return self.str( strOptions ); + } + + return parent.moveTextualReport.head.call( self, routine, [ o ] ); +} + +let moveTextualReport = _.routine.uniteCloning_replaceByUnite( moveTextualReport_head, Parent.moveTextualReport.body ); + +// + +/** + * Returns origin plus path without query part of uri string. + * @example + * + let path = 'https://www.site.com:13/path/name?query=here&and=here#anchor'; + wTools.uri.uri.documentGet( path, { withoutProtocol : 1 } ); + // 'www.site.com:13/path/name' + * @param {string} path uri string + * @param {Object} [o] o - options + * @param {boolean} o.withoutServer if true rejects origin part from result + * @param {boolean} o.withoutProtocol if true rejects protocol part from result uri + * @returns {string} Return document uri. + * @function documentGet + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function documentGet( path, o ) +{ + o = o || Object.create( null ); + + if( path === undefined ) + path = _realGlobal_.location.href; + + if( path.indexOf( '//' ) === -1 ) + { + path = 'http:/' + ( path[ 0 ] === '/' ? '' : '/' ) + path; + } + + let a = path.split( '//' ); + let b = a[ 1 ].split( '?' ); + + /* */ + + if( o.withoutServer ) + { + let i = b[ 0 ].indexOf( '/' ); + if( i === -1 ) i = 0; + return b[ 0 ].substr( i ); + } + else + { + if( o.withoutProtocol )return b[ 0 ]; + else return a[ 0 ] + '//' + b[ 0 ]; + } + +} + +documentGet.defaults = +{ + path : null, + withoutServer : null, + withoutProtocol : null, +} + +// + +/** + * Return origin (protocol + host + port) part of passed `path` string. If missed arguments, returns origin of + * current document. + * @example + * + let path = 'http://www.site.com:13/path/name?query=here' + wTools.uri.server( path ); + // 'http://www.site.com:13/' + * @param {string} [path] uri + * @returns {string} Origin part of uri. + * @function server + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function server( path ) +{ + let a, b; + + if( path === undefined ) + path = _realGlobal_.location.origin; + + if( path.indexOf( '//' ) === -1 ) + { + if( path[ 0 ] === '/' )return '/'; + a = [ '', path ] + } + else + { + a = path.split( '//' ); + a[ 0 ] += '//'; + } + + b = a[ 1 ].split( '/' ); + + return a[ 0 ] + b[ 0 ] + '/'; +} + +// + +/** + * Returns query part of uri. If method is called without arguments, it returns current query of current document uri. + * @example + let uri = 'http://www.site.com:13/path/name?query=here&and=here#anchor', + wTools.uri.query( uri ); // 'query=here&and=here#anchor' + * @param {string } [path] uri + * @returns {string} + * @function query + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function query( path ) +{ + if( path === undefined ) + path = _realGlobal_.location.href; + if( path.indexOf( '?' ) === -1 )return ''; + return path.split( '?' )[ 1 ]; +} + +// + +/** + * Parse a query string passed as a 'query' argument. Result is returned as a dictionary. + * The dictionary keys are the unique query variable names and the values are decoded from uri query variable values. + * @example + * + let query = 'k1=&k2=v2%20v3&k3=v4_v4'; + + let res = wTools.uri.dequery( query ); + // { + // k1 : '', + // k2 : 'v2 v3', + // k3 : 'v4_v4' + // }, + + * @param {string} query query string + * @returns {Object} + * @function dequery + * @module Tools/UriBasic + * @namespace Tools.uri + */ + +function dequery( query ) +{ + + let result = Object.create( null ); + query = query || _global.location.search.split('?')[ 1 ]; + if( !query || !query.length ) + return result; + let vars = query.split( '&' ); + + for( let i = 0 ; i < vars.length ; i++ ) + { + + let w = vars[ i ].split( '=' ); + w[ 0 ] = decodeURIComponent( w[ 0 ] ); + if( w[ 1 ] === undefined ) w[ 1 ] = ''; + else w[ 1 ] = decodeURIComponent( w[ 1 ] ); + + if( (w[ 1 ][ 0 ] === w[ 1 ][ w[ 1 ].length-1 ] ) && ( w[ 1 ][ 0 ] === '"') ) + w[ 1 ] = w[ 1 ].substr( 1, w[ 1 ].length-1 ); + + if( result[ w[ 0 ] ] === undefined ) + { + result[ w[ 0 ] ] = w[ 1 ]; + } + else if( _.strIs( result[ w[ 0 ] ] ) ) + { + result[ w[ 0 ] ] = result[ w[ 1 ] ] + } + else + { + result[ w[ 0 ] ].push( w[ 1 ] ); + } + + } + + return result; +} + +// -- +// Uri constructors +// -- + +let Uri = _.blueprint.defineConstructor +({ + protocol : null, + query : null, + hash : null, + typed : _.trait.typed(), + extendable : _.trait.extendable(), +}); + +// + +// let UriFull = +// ({ +// resourcePath : null, +// host : null, +// port : null, +// longPath : null, +// protocols : null, +// hostFull : null, +// origin : null, +// full : null, +// extension : _.define.extension( Uri ), +// }); +// +// // +// +// let UriAtomic = +// ({ +// resourcePath : null, +// host : null, +// extension : _.define.extension( Uri ), +// }); +// +// // +// +// let UriConsequtive = +// ({ +// longPath : null, +// extension : _.define.extension( Uri ), +// }); + +let Constructors = +{ + + // Uri map constructors + + Uri, + // UriFull, + // UriAtomic, + // UriConsequtive, +} + +_.props.extend( _, Constructors ); + +// -- +// declare routines +// -- + +let Parameters = +{ + _uriParseRegexpStr, + _uriParseRegexp +} + +let Extension = +{ + // internal + + _filterOnlyUrl, + _filterNoInnerArray, + + // dichotomy + + is, + isSafe, + isRefined, + isNormalized, + isAbsolute, + isRelative, + isRoot, + isDotted, + isTrailed, + isGlob, + + // transformer + + parse, + parseFull, + parseAtomic, + parseConsecutive, + localFromGlobal, + + str, + full, + + refine, + normalize, + canonize, + normalizeTolerant, + + dot, + + trail, + detrail, + + name, + ext, + exts, + changeExt, + + // joiner + + join_functor, + + join, + joinRaw, + reroot, + resolve, + + relative, + common, + rebase, + + dir, + dirFirst, + + groupTextualReport, + commonTextualReport, + moveTextualReport, + + documentGet, + server, + query, + dequery, + + // fields + + single : Self, + UriComponents, + Parameters + +} + +_.mapExtendDstNotOwn( Self, Parameters ); +_.mapExtendDstNotOwn( Self, Extension ); + +Self.Init(); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +if( typeof module !== 'undefined' ) +require( '../l5/Uris.s' ); + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wuribasic/proto/wtools/abase/l4/UriOld.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wuribasic/proto/wtools/abase/l4' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, UriOld_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file UriOld_s */ })(); + +/* */ /* begin of file Uris_s */ ( function Uris_s() { function Uris_s_naked() { ( function _Uris_s_() +{ + +'use strict'; + +/** + * */ + +/** + * Collection of cross-platform routines to operate multiple uris in the reliable and consistent way. + * @namespace wTools.uri.s + * @extends Tools.uri + * @module Tools/base/Uri + */ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + + require( '../l4/Uri.s' ); + +} + +// + +const _ = _global_.wTools; +const Parent = _.uri; +// const Self = _.uri.s = _.uri.s || Object.create( Parent ); +const Self = _.uris = _.uri.s = _.uris || _.uri.s || Object.create( Parent ); + +// -- +// functors +// -- + +let _vectorize = _.path.s._vectorize; +let _vectorizeOnly = _.path.s._vectorizeOnly; + +// function _keyEndsUriFilter( e,k,c ) +// { +// _.assert( 0, 'not tested' ); +// +// if( _.strIs( k ) ) +// { +// if( _.strEnds( k,'Uri' ) ) +// return true; +// else +// return false +// } +// return this.is( e ); +// } +// +// // +// +// function _isUriFilter( e ) +// { +// return this.is( e[ 0 ] ) +// } + +// // +// +// function _vectorize( routine, select ) +// { +// _.assert( arguments.length === 1 || arguments.length === 2 ); +// _.assert( _.strIs( routine ) ); +// select = select || 1; +// return _.routineVectorize_functor +// ({ +// routine : [ 'single', routine ], +// vectorizingArray : 1, +// vectorizingMapVals : 0, +// vectorizingMapKeys : 1, +// select, +// }); +// } +// +// // +// +// function _vectorizeOnly( routine ) +// { +// _.assert( arguments.length === 1 ); +// _.assert( _.strIs( routine ) ); +// return _.routineVectorize_functor +// ({ +// routine : [ 'single', routine ], +// propertyCondition : _keyEndsUriFilter, +// vectorizingArray : 1, +// vectorizingMapVals : 1, +// }); +// } + +/** + * @summary Parses uris from array `src`. Writes results into array. + * @param {Array|String} src + * @example + * _.uri.s.parse( [ '/a', 'https:///stackoverflow.com' ] ); + * @returns {Array} Returns array with results of parse operation. + * @function parse + * @module Tools/base/Uri.wTools + * @namespace uri.s + */ + +/** + * @summary Parses uris from array `src`. Looks only for atomic components of the uri. Writes results into array. + * @description Atomic components: protocol,host,port,resourcePath,query,hash. + * @param {Array|String} src + * @example + * _.uri.s.parseAtomic( [ '/a', 'https:///stackoverflow.com' ] ); + * @returns {Array} Returns array with results of parse operation. + * @function parseAtomic + * @module Tools/base/Uri.wTools + * @namespace uri.s + */ + +/** + * @summary Parses uris from array `src`. Looks only for consecutive components of the uri. Writes results into array. + * @description Consecutive components: protocol,longPath,query,hash. + * @param {Array|String} src + * @example + * _.uri.s.parseConsecutive( [ '/a', 'https:///stackoverflow.com' ] ); + * @returns {Array} Returns array with results of parse operation. + * @function parseConsecutive + * @module Tools/base/Uri.wTools + * @namespace uri.s + */ + +/** +* @summary Assembles uris from array of components( src ). +* @param {Array|Object} src +* @example +* _.uri.s.str( [ { resourcePath : '/a' }, { protocol : 'http', resourcePath : '/a' } ] ); +* //['/a', 'http:///a' ] +* @returns {Array} Returns array of strings, each element represent a uri. +* @function str +* @module Tools/base/Uri.wTools +* @namespace uri.s +*/ + +/** + * @summary Complements current window uri origin with array of components. + * @param {Array|Object} src + * @example + * _.uri.s.full( [ { resourcePath : '/a' }, { protocol : 'http', resourcePath : '/a' } ] ); + * @returns {Array} Returns array of strings, each element represent a uri. + * @function full + * @module Tools/base/Uri.wTools + * @namespace uri.s + */ + +// -- +// implementation +// -- + +let Extension = +{ + + // _keyEndsUriFilter, + // _isUriFilter, + // + // _vectorize, + // _vectorizeOnly, + + // + + parse : _vectorize( 'parse' ), + parseAtomic : _vectorize( 'parseAtomic' ), + parseConsecutive : _vectorize( 'parseConsecutive' ), + + onlyParse : _vectorizeOnly( 'parse' ), + onlyParseAtomic : _vectorizeOnly( 'parseAtomic' ), + onlyParseConsecutive : _vectorizeOnly( 'parseConsecutive' ), + + str : _vectorize( 'str' ), + full : _vectorize( 'full' ), + + normalizeTolerant : _vectorize( 'normalizeTolerant' ), + onlyNormalizeTolerant : _vectorizeOnly( 'normalizeTolerant' ), + + rebase : _vectorize( 'rebase', 3 ), + + documentGet : _vectorize( 'documentGet', 2 ), + server : _vectorize( 'server' ), + query : _vectorize( 'query' ), + dequery : _vectorize( 'dequery' ), + + // + + uri : Parent, + +} + +_.mapExtendDstNotOwn( Self, Extension ); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wuribasic/proto/wtools/abase/l5/Uris.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wuribasic/proto/wtools/abase/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Uris_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Uris_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wverbal/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wverbal/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wverbal */ ( function wverbal() { function wverbal_naked() { +module.exports = require( '../wtools/amid/amixin/Verbal.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wVerbal', 'wverbal' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wverbal/proto/node_modules/wverbal' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wverbal/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wverbal_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wverbal */ })(); + +/* */ /* begin of file Verbal_s */ ( function Verbal_s() { function Verbal_s_naked() { ( function _Verbal_s_() +{ + +'use strict'; + +/** + * Verbal is small mixin which adds verbosity control to your class. It tracks verbosity changes, reflects any change of verbosity to instance's components, and also clamp verbosity in [ 0 .. 9 ] range. Use it as a companion for a logger, mixing it into logger's carrier. + @module Tools/mid/Verbal +*/ + +/** + * */ + +/** + * @classdesc Verbal is small mixin which adds verbosity control to your class. + * @class wVerbal + * @namespace wTools + * @module Tools/mid/Verbal +*/ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + + _.include( 'wProto' ); + +} + + +// + +const _global = _global_; +const _ = _global_.wTools; +const Parent = null; +const Self = wVerbal; +function wVerbal( o ) +{ + _.assert( arguments.length === 0 || arguments.length === 1 ); + return _.workpiece.construct( Self, this, arguments ); +} + +Self.shortName = 'Verbal'; + +// -- +// implementation +// -- + +function verbal_functor( o ) +{ + if( _.routineIs( o ) ) + o = { routine : o } + _.routine.options_( verbal_functor, o ); + _.assert( _.strDefined( o.routine.name ) ); + let routine = o.routine; + let title = _.strCapitalize( _.strToTitle( o.routine.name ) ); + + return function verbal() + { + let self = this; + let logger = self.logger; + let result; + logger.rbegin({ verbosity : -1 }); + logger.log( title + ' ..' ); + logger.up(); + + try + { + result = routine.apply( this, arguments ); + } + catch( err ) + { + throw _.err( err ); + } + + _.Consequence.From( result ).split() + .finally( () => + { + logger.down(); + logger.rend({ verbosity : -1 }); + return true; + }); + + return result; + } +} + +verbal_functor.defaults = +{ + routine : null, +} + +// + +function _verbosityGet() +{ + let self = this; + if( !self.logger ) + return 0; + return self.logger.verbosity; +} + +// + +function _verbositySet( src ) +{ + let self = this; + + if( _.boolIs( src ) ) + src = src ? 1 : 0; + + src = _.numberClamp( src, 0, 9 ); + + _.assert( arguments.length === 1 ); + _.assert( _.numberIs( src ) ); + _.assert( src === 0 || !!self.logger, () => 'Verbal ' + self.qualifiedName + ' does not have logger to set verbosity to ' + src ); + + // self[ verbositySymbol ] = src; + + let change = self.logger && self.logger.verbosity !== src; + if( self.logger ) + self.logger.verbosity = src; + + if( change ) + return self._verbosityChange(); +} + +// + +function _verbosityChange() +{ + let self = this; + + _.assert( arguments.length === 0, 'Expects no arguments' ); + + // if( self.fileProvider ) + // self.fileProvider.verbosity = self._verbosityForFileProvider(); + + // if( self.logger ) + // { + // // self.logger.verbosity = self._verbosityForLogger(); + // self.logger.outputGray = self.coloring ? 0 : 1; + // return src; + // } + + return 0; +} + +// + +// function _coloringSet( src ) +// { +// let self = this; +// +// _.assert( arguments.length === 1 ); +// _.assert( _.boolLike( src ) ); +// +// if( !src ) +// debugger; +// +// if( self.logger ) +// { +// self[ coloringSymbol ] = src; +// self.logger.outputGray = src ? 0 : 1; +// } +// else +// { +// self[ coloringSymbol ] = src; +// } +// +// } + +// + +function _coloringGet() +{ + let self = this; + if( !self.logger ) + return false; + return !self.logger.outputGray; + // return self[ coloringSymbol ]; +} + +// + +// function _verbosityForFileProvider() +// { +// let self = this; +// let less = _.numberClamp( self.verbosity-2, 0, 9 ); +// _.assert( arguments.length === 0, 'Expects no arguments' ); +// return less; +// } + +// + +// function _fileProviderSet( src ) +// { +// let self = this; +// +// _.assert( arguments.length === 1 ); +// +// // if( src ) +// // src.verbosity = self._verbosityForFileProvider(); +// +// self[ fileProviderSymbol ] = src; +// +// self._verbosityChange(); +// +// } +// +// // +// +// function _verbosityForLogger() +// { +// let self = this; +// _.assert( arguments.length === 0, 'Expects no arguments' ); +// return self.verbosity; +// } + +// + +function _loggerSet( src ) +{ + let self = this; + + _.assert( arguments.length === 1 ); + + if( self[ loggerSymbol ] ) + { + self[ loggerSymbol ].off( 'verbosityChange', self ); + } + + self[ loggerSymbol ] = src; + + // if( src ) + // debugger; + if( src ) + src.on( 'verbosityChange', self, () => self._verbosityChange() ); + + // if( src ) + // { + // // src.verbosity = self._verbosityForLogger(); + // // src.outputGray = self.coloring ? 0 :1; + // } + + self._verbosityChange(); + + return src; +} + +// -- +// vars +// -- + +// let verbositySymbol = Symbol.for( 'verbosity' ); +let coloringSymbol = Symbol.for( 'coloring' ); +// let fileProviderSymbol = Symbol.for( 'fileProvider' ); +let loggerSymbol = Symbol.for( 'logger' ); + +// -- +// relations +// -- + +let Composes = +{ + // verbosity : 0, + // coloring : 1, +} + +let Aggregates = +{ +} + +let Associates = +{ +} + +let Restricts = +{ +} + +let Statics = +{ + verbal_functor, +} + +let Forbids = +{ + _verbosityForFileProvider : '_verbosityForFileProvider', + _fileProviderSet : '_fileProviderSet', + _verbosityForLogger : '_verbosityForLogger', + _coloringSet : '_coloringSet', +} + +let Accessors = +{ + verbosity : { combining : 'supplement' }, + coloring : { combining : 'supplement' }, + // fileProvider : { combining : 'supplement' }, + logger : { combining : 'supplement' }, +} + +// -- +// declare +// -- + +let Supplement = +{ + + _verbosityGet, + _verbositySet, + _verbosityChange, + // _coloringSet : _coloringSet, + _coloringGet, + + // _verbosityForFileProvider : _verbosityForFileProvider, + // _fileProviderSet : _fileProviderSet, + // _verbosityForLogger : _verbosityForLogger, + + _loggerSet, + + // + + Composes, + Aggregates, + Associates, + Restricts, + Statics, + Forbids, + Accessors, + +} + +// + +_.classDeclare +({ + cls : Self, + parent : Parent, + supplement : Supplement, + withMixin : true, + withClass : true, +}); + +// -- +// export +// -- + +_global_[ Self.name ] = _[ Self.shortName ] = Self; + + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wverbal/proto/wtools/amid/amixin/Verbal.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wverbal/proto/wtools/amid/amixin' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Verbal_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Verbal_s */ })(); + +/* */ /* begin of file Tools */ ( function Tools() { function Tools_naked() { if( typeof module !== 'undefined' ) +{ + + module[ 'exports' ] = require( 'wTools' ); + + // if + // ( + // typeof _global_ === 'undefined' || !Object.hasOwnProperty.call( _global_, 'wTools' ) || !_global_.wTools.maybe + // ) + // { + // let toolsPath = '../wtools/abase/Layer1.s'; + // let toolsExternal = 0; + // try + // { + // toolsPath = require.resolve( toolsPath ); + // } + // catch( err ) + // { + // toolsExternal = 1; + // require( 'wTools' ); + // } + // if( !toolsExternal ) + // require( toolsPath ); + // } + // + // _global_.wTools.module.predeclare + // ({ + // alias : [ 'wTools', 'wtools' ], + // entryPath : __filename, + // }); + // + // module[ 'exports' ] = _global_.wTools; +} + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wweburibasic/proto/node_modules/Tools' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wweburibasic/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, Tools_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file Tools */ })(); + +/* */ /* begin of file wweburibasic */ ( function wweburibasic() { function wweburibasic_naked() { +module.exports = require( '../wtools/abase/l5/WebUri.s' ); +const _ = _global_.wTools; +_.module.predeclare +({ + alias : [ 'wWebUriBasic', 'wweburibasic' ], + entryPath : __filename, +}); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wweburibasic/proto/node_modules/wweburibasic' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wweburibasic/proto/node_modules' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, wweburibasic_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file wweburibasic */ })(); + +/* */ /* begin of file WebUri_s */ ( function WebUri_s() { function WebUri_s_naked() { ( function _WebUri_s_() +{ + +'use strict'; + +/** + * Collection of cross-platform routines to operate web URIs ( URLs ) in the reliable and consistent way. Module WebUri extends Uri module to handle host and port parts of URI in a way appropriate for world wide web resources. This module leverages parsing, joining, extracting, normalizing, nativizing, resolving paths. Use the module to get uniform experience from playing with paths on different platforms. + @module Tools/base/WebUri +*/ + +/** + * Collection of cross-platform routines to operate web URIs ( URLs ) in the reliable and consistent way. + @namespace wTools.weburi + @extends Tools + @module Tools/base/WebUri +*/ + +if( typeof module !== 'undefined' ) +{ + + const _ = require( '../../../node_modules/Tools' ); + + _.include( 'wPathBasic' ); + _.include( 'wUriBasic' ); + +} + +// + +const _global = _global_; +const _ = _global_.wTools; +const Parent = _.uri; +const Self = _.weburi = _.weburi || Object.create( Parent ); + +// -- +// +// -- + +/** + * @summary Checks if argument `path` is a absolute path. + * @param {String} path Source path. + * @returns {Boolean} Returns true if provided path is absolute. + * @function isAbsolute + * @module Tools/base/WebUri + * @namespace Tools.weburi + */ + +function isAbsolute( path ) +{ + let parent = this.path; + _.assert( arguments.length === 1 ); + _.assert( _.strIs( path ), 'Expects string' ); + if( this.isGlobal( path ) ) + return true; + return parent.isAbsolute( path ); +} + +// + +/** + * @summary Joins a sequence of paths into single web uri. + * @param {...String} path Source paths. + * @example + * _.weburi.join( 'http://www.site.com:13','a','http:///dir','b' ); + * //'http://www.site.com:13/dir/b' + * @returns {String} Returns normalized new web uri. + * @function join + * @module Tools/base/WebUri + * @namespace Tools.weburi + */ + +let join = Parent.join_functor( 'join', 1 ); + +// + +// function join_head( routine, args ) +// { +// let o = args[ 0 ]; +// +// if( !_.mapIs( o ) ) +// o = { args }; +// else +// _.assert( args.length === 1, 'Expects single options map {-o-}' ); +// +// _.routine.options_( routine, o ); +// _.assert( _.strIs( o.routineName ) ); +// +// return o; +// } + +// + +function join_body( o ) +{ + let self = this; + let parent = self.path; + let isGlobal = false; + + /* */ + + let srcs = pathsParseAtomicAndSetIsGlobal( o.args ); + let result = resultMapMake( srcs ); + + if( !isGlobal ) + return result.resourcePath; + + if( ( result.hash || result.tag ) && result.longPath ) + result.longPath = parent.detrail( result.longPath ); + + return self.str( result ); + + /* */ + + function pathsParseAtomicAndSetIsGlobal( args ) + { + let result = _.array.make( args.length ); + + for( let s = 0 ; s < args.length ; s++ ) + { + if( args[ s ] !== null && self.isGlobal( args[ s ] ) ) + { + isGlobal = true; + result[ s ] = self.parseAtomic( args[ s ] ); + } + else + { + isGlobal = args[ s ] !== null; + result[ s ] = { resourcePath : args[ s ] }; + } + } + + return result; + } + + /* */ + + function resultMapMake( srcs ) + { + let result = Object.create( null ); + result.resourcePath = undefined; + + for( let s = srcs.length - 1 ; s >= 0 ; s-- ) + { + let src = srcs[ s ]; + let hostWas = result.host; + + if( result.protocol && src.protocol ) + if( result.protocol !== src.protocol ) + continue; + + if( !result.protocol && src.protocol !== undefined ) + result.protocol = src.protocol; + + if( !result.user && src.user !== undefined ) + result.user = src.user; + + if( !result.host && src.host !== undefined ) + result.host = src.host; + + if( !result.port && src.port !== undefined ) + if( !hostWas || !src.host || hostWas === src.host ) + result.port = src.port; + + if( !result.resourcePath && src.resourcePath !== undefined ) + result.resourcePath = src.resourcePath; + else if( src.resourcePath ) + result.resourcePath = parent[ o.routineName ]( src.resourcePath, result.resourcePath ); + + if( src.resourcePath === null ) + break; + + if( src.query !== undefined ) + if( result.query ) + result.query = src.query + '&' + result.query; + else + result.query = src.query; + + if( !result.hash && src.hash !==undefined ) + result.hash = src.hash; + + if( !result.tag && src.tag !==undefined ) + result.tag = src.tag; + } + + return result; + } +} + +join_body.defaults = +{ + routineName : 'join', + args : null, +}; + +// + +let join_ = _.routine.uniteCloning_replaceByUnite( Parent.join_.head, join_body ); + +/** + * @summary Joins a sequence of paths into single web uri. + * @param {...String} path Source paths. + * @example + * _.weburi.joinRaw( 'http://www.site.com:13','a','http:///dir///','b' ); + * //'http://www.site.com:13/dir////b' + * @returns {String} Returns new web uri withou normalization. + * @function joinRaw + * @module Tools/base/WebUri + * @namespace Tools.weburi + */ + +let joinRaw = Parent.join_functor( 'joinRaw', 1 ); + +// + +let joinRaw_ = _.routine.uniteCloning_replaceByUnite( Parent.joinRaw_.head, join_body ); +joinRaw_.defaults.routineName = 'joinRaw'; + +// + +// let urisJoin = _.path._pathMultiplicator_functor +// ({ +// routine : join, +// }); + +// + +function current() +{ + _.assert( arguments.length === 0, 'Expects no arguments.' ); + return this.upToken; +} + +// + +// +// +// function resolve() +// { +// let parent = this.path; +// let result = Object.create( null ); +// let srcs = []; +// let parsed = false; +// +// for( let s = 0 ; s < arguments.length ; s++ ) +// { +// if( this.isGlobal( arguments[ s ] ) ) +// { +// parsed = true; +// srcs[ s ] = this.parseConsecutive( arguments[ s ] ); +// } +// else +// { +// srcs[ s ] = { longPath : arguments[ s ] }; +// } +// } +// +// for( let s = 0 ; s < srcs.length ; s++ ) +// { +// let src = srcs[ s ]; +// +// if( !result.protocol && src.protocol !== undefined ) +// result.protocol = src.protocol; +// +// // if( !result.host && src.host !== undefined ) +// // result.host = src.host; +// // +// // if( !result.port && src.port !== undefined ) +// // result.port = src.port; +// +// if( !result.longPath && src.longPath !== undefined ) +// { +// if( !_.strDefined( src.longPath ) ) +// src.longPath = this.rootToken; +// +// result.longPath = src.longPath; +// } +// else +// { +// result.longPath = parent.resolve( result.longPath, src.longPath ); +// } +// +// if( src.query !== undefined ) +// if( !result.query ) +// result.query = src.query; +// else +// result.query = src.query + '&' + result.query; +// +// if( !result.hash && src.hash !==undefined ) +// result.hash = src.hash; +// +// } +// +// if( !parsed ) +// return result.longPath; +// +// return this.str( result ); +// } + +// + +/** + * @summary Resolves a sequence of paths or path segments into web uri. + * @description + * The given sequence of paths is processed from right to left,with each subsequent path prepended until an absolute + * path is constructed. If after processing all given path segments an absolute path has not yet been generated, + * the current working directory is used. + * @param {...String} path Source paths. + * @example + * _.weburi.resolve( 'http://www.site.com:13','a/../' ); + * //'http://www.site.com:13/' + * @returns {String} Returns new web uri withou normalization. + * @function resolve + * @module Tools/base/WebUri + * @namespace Tools.weburi + */ + +function resolve() +{ + let self = this; + let parent = self.path; + let joined = self.join.apply( self, arguments ); + let parsed = self.parseAtomic( joined ); + if( parsed.resourcePath ) + parsed.resourcePath = parent.resolve.call( self, parsed.resourcePath ); + // parsed.resourcePath = parent.resolve( parsed.resourcePath ); /* Dmytro : the context of resolving should be a WebUri, not Path */ + return self.str( parsed ); +} + +// + +// let urisResolve = _.path._pathMultiplicator_functor +// ({ +// routine : resolve, +// }); + +// -- +// extension +// -- + +let Extension = +{ + + isAbsolute, + + join, + join_, /* !!! : use instead of join */ /* Dmytro : separate implementation, it has less if branches */ + joinRaw, + joinRaw_, /* !!! : use instead of joinRaw */ /* Dmytro : separate implementation, it has less if branches */ + // urisJoin, + + current, + + resolve, + // urisResolve, + + // extension + + single : Self, + +} + +_.mapExtendDstNotOwn( Self, Extension ); + +Self.Init(); + +// -- +// export +// -- + +if( typeof module !== 'undefined' ) +module[ 'exports' ] = Self; + +})(); + +/* */ }; +/* */ let _filePath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wweburibasic/proto/wtools/abase/l5/WebUri.s' ); +/* */ let _dirPath_ = _starter_._pathResolveLocal( null, _libraryFilePath_, './node_modules/wweburibasic/proto/wtools/abase/l5' ); +/* */ let __filename = _filePath_; +/* */ let __dirname = _dirPath_; +/* */ let module = _starter_._sourceMake( _filePath_, _dirPath_, WebUri_s_naked ); +/* */ let exports = module.exports; +/* */ let require = module.include; +/* */ let include = module.include; + +/* */ /* end of file WebUri_s */ })(); + + +/* */ module.exports = _starter_._sourceInclude( null, _libraryFilePath_, './node_modules/wgittools/proto/wtools/amid/l3/git/entry/GitTools.ss' ); + + +/* */ /* end of library Joined_s */ })() diff --git a/node_modules/async/retry.js b/node_modules/async/retry.js new file mode 100644 index 00000000..dba30301 --- /dev/null +++ b/node_modules/async/retry.js @@ -0,0 +1,159 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = retry; + +var _wrapAsync = require('./internal/wrapAsync.js'); + +var _wrapAsync2 = _interopRequireDefault(_wrapAsync); + +var _promiseCallback = require('./internal/promiseCallback.js'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function constant(value) { + return function () { + return value; + }; +} + +/** + * Attempts to get a successful response from `task` no more than `times` times + * before returning an error. If the task is successful, the `callback` will be + * passed the result of the successful task. If all attempts fail, the callback + * will be passed the error and result (if any) of the final attempt. + * + * @name retry + * @static + * @memberOf module:ControlFlow + * @method + * @category Control Flow + * @see [async.retryable]{@link module:ControlFlow.retryable} + * @param {Object|number} [opts = {times: 5, interval: 0}| 5] - Can be either an + * object with `times` and `interval` or a number. + * * `times` - The number of attempts to make before giving up. The default + * is `5`. + * * `interval` - The time to wait between retries, in milliseconds. The + * default is `0`. The interval may also be specified as a function of the + * retry count (see example). + * * `errorFilter` - An optional synchronous function that is invoked on + * erroneous result. If it returns `true` the retry attempts will continue; + * if the function returns `false` the retry flow is aborted with the current + * attempt's error and result being returned to the final callback. + * Invoked with (err). + * * If `opts` is a number, the number specifies the number of times to retry, + * with the default interval of `0`. + * @param {AsyncFunction} task - An async function to retry. + * Invoked with (callback). + * @param {Function} [callback] - An optional callback which is called when the + * task has succeeded, or after the final failed attempt. It receives the `err` + * and `result` arguments of the last attempt at completing the `task`. Invoked + * with (err, results). + * @returns {Promise} a promise if no callback provided + * + * @example + * + * // The `retry` function can be used as a stand-alone control flow by passing + * // a callback, as shown below: + * + * // try calling apiMethod 3 times + * async.retry(3, apiMethod, function(err, result) { + * // do something with the result + * }); + * + * // try calling apiMethod 3 times, waiting 200 ms between each retry + * async.retry({times: 3, interval: 200}, apiMethod, function(err, result) { + * // do something with the result + * }); + * + * // try calling apiMethod 10 times with exponential backoff + * // (i.e. intervals of 100, 200, 400, 800, 1600, ... milliseconds) + * async.retry({ + * times: 10, + * interval: function(retryCount) { + * return 50 * Math.pow(2, retryCount); + * } + * }, apiMethod, function(err, result) { + * // do something with the result + * }); + * + * // try calling apiMethod the default 5 times no delay between each retry + * async.retry(apiMethod, function(err, result) { + * // do something with the result + * }); + * + * // try calling apiMethod only when error condition satisfies, all other + * // errors will abort the retry control flow and return to final callback + * async.retry({ + * errorFilter: function(err) { + * return err.message === 'Temporary error'; // only retry on a specific error + * } + * }, apiMethod, function(err, result) { + * // do something with the result + * }); + * + * // to retry individual methods that are not as reliable within other + * // control flow functions, use the `retryable` wrapper: + * async.auto({ + * users: api.getUsers.bind(api), + * payments: async.retryable(3, api.getPayments.bind(api)) + * }, function(err, results) { + * // do something with the results + * }); + * + */ +const DEFAULT_TIMES = 5; +const DEFAULT_INTERVAL = 0; + +function retry(opts, task, callback) { + var options = { + times: DEFAULT_TIMES, + intervalFunc: constant(DEFAULT_INTERVAL) + }; + + if (arguments.length < 3 && typeof opts === 'function') { + callback = task || (0, _promiseCallback.promiseCallback)(); + task = opts; + } else { + parseTimes(options, opts); + callback = callback || (0, _promiseCallback.promiseCallback)(); + } + + if (typeof task !== 'function') { + throw new Error("Invalid arguments for async.retry"); + } + + var _task = (0, _wrapAsync2.default)(task); + + var attempt = 1; + function retryAttempt() { + _task((err, ...args) => { + if (err === false) return; + if (err && attempt++ < options.times && (typeof options.errorFilter != 'function' || options.errorFilter(err))) { + setTimeout(retryAttempt, options.intervalFunc(attempt - 1)); + } else { + callback(err, ...args); + } + }); + } + + retryAttempt(); + return callback[_promiseCallback.PROMISE_SYMBOL]; +} + +function parseTimes(acc, t) { + if (typeof t === 'object') { + acc.times = +t.times || DEFAULT_TIMES; + + acc.intervalFunc = typeof t.interval === 'function' ? t.interval : constant(+t.interval || DEFAULT_INTERVAL); + + acc.errorFilter = t.errorFilter; + } else if (typeof t === 'number' || typeof t === 'string') { + acc.times = +t || DEFAULT_TIMES; + } else { + throw new Error("Invalid arguments for async.retry"); + } +} +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/async/retryable.js b/node_modules/async/retryable.js new file mode 100644 index 00000000..1b1147cd --- /dev/null +++ b/node_modules/async/retryable.js @@ -0,0 +1,77 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = retryable; + +var _retry = require('./retry.js'); + +var _retry2 = _interopRequireDefault(_retry); + +var _initialParams = require('./internal/initialParams.js'); + +var _initialParams2 = _interopRequireDefault(_initialParams); + +var _wrapAsync = require('./internal/wrapAsync.js'); + +var _wrapAsync2 = _interopRequireDefault(_wrapAsync); + +var _promiseCallback = require('./internal/promiseCallback.js'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * A close relative of [`retry`]{@link module:ControlFlow.retry}. This method + * wraps a task and makes it retryable, rather than immediately calling it + * with retries. + * + * @name retryable + * @static + * @memberOf module:ControlFlow + * @method + * @see [async.retry]{@link module:ControlFlow.retry} + * @category Control Flow + * @param {Object|number} [opts = {times: 5, interval: 0}| 5] - optional + * options, exactly the same as from `retry`, except for a `opts.arity` that + * is the arity of the `task` function, defaulting to `task.length` + * @param {AsyncFunction} task - the asynchronous function to wrap. + * This function will be passed any arguments passed to the returned wrapper. + * Invoked with (...args, callback). + * @returns {AsyncFunction} The wrapped function, which when invoked, will + * retry on an error, based on the parameters specified in `opts`. + * This function will accept the same parameters as `task`. + * @example + * + * async.auto({ + * dep1: async.retryable(3, getFromFlakyService), + * process: ["dep1", async.retryable(3, function (results, cb) { + * maybeProcessData(results.dep1, cb); + * })] + * }, callback); + */ +function retryable(opts, task) { + if (!task) { + task = opts; + opts = null; + } + let arity = opts && opts.arity || task.length; + if ((0, _wrapAsync.isAsync)(task)) { + arity += 1; + } + var _task = (0, _wrapAsync2.default)(task); + return (0, _initialParams2.default)((args, callback) => { + if (args.length < arity - 1 || callback == null) { + args.push(callback); + callback = (0, _promiseCallback.promiseCallback)(); + } + function taskFn(cb) { + _task(...args, cb); + } + + if (opts) (0, _retry2.default)(opts, taskFn, callback);else (0, _retry2.default)(taskFn, callback); + + return callback[_promiseCallback.PROMISE_SYMBOL]; + }); +} +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/portscanner/node_modules/async/retry.js b/node_modules/portscanner/node_modules/async/retry.js new file mode 100644 index 00000000..6a1aa1ec --- /dev/null +++ b/node_modules/portscanner/node_modules/async/retry.js @@ -0,0 +1,156 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = retry; + +var _noop = require('lodash/noop'); + +var _noop2 = _interopRequireDefault(_noop); + +var _constant = require('lodash/constant'); + +var _constant2 = _interopRequireDefault(_constant); + +var _wrapAsync = require('./internal/wrapAsync'); + +var _wrapAsync2 = _interopRequireDefault(_wrapAsync); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Attempts to get a successful response from `task` no more than `times` times + * before returning an error. If the task is successful, the `callback` will be + * passed the result of the successful task. If all attempts fail, the callback + * will be passed the error and result (if any) of the final attempt. + * + * @name retry + * @static + * @memberOf module:ControlFlow + * @method + * @category Control Flow + * @see [async.retryable]{@link module:ControlFlow.retryable} + * @param {Object|number} [opts = {times: 5, interval: 0}| 5] - Can be either an + * object with `times` and `interval` or a number. + * * `times` - The number of attempts to make before giving up. The default + * is `5`. + * * `interval` - The time to wait between retries, in milliseconds. The + * default is `0`. The interval may also be specified as a function of the + * retry count (see example). + * * `errorFilter` - An optional synchronous function that is invoked on + * erroneous result. If it returns `true` the retry attempts will continue; + * if the function returns `false` the retry flow is aborted with the current + * attempt's error and result being returned to the final callback. + * Invoked with (err). + * * If `opts` is a number, the number specifies the number of times to retry, + * with the default interval of `0`. + * @param {AsyncFunction} task - An async function to retry. + * Invoked with (callback). + * @param {Function} [callback] - An optional callback which is called when the + * task has succeeded, or after the final failed attempt. It receives the `err` + * and `result` arguments of the last attempt at completing the `task`. Invoked + * with (err, results). + * + * @example + * + * // The `retry` function can be used as a stand-alone control flow by passing + * // a callback, as shown below: + * + * // try calling apiMethod 3 times + * async.retry(3, apiMethod, function(err, result) { + * // do something with the result + * }); + * + * // try calling apiMethod 3 times, waiting 200 ms between each retry + * async.retry({times: 3, interval: 200}, apiMethod, function(err, result) { + * // do something with the result + * }); + * + * // try calling apiMethod 10 times with exponential backoff + * // (i.e. intervals of 100, 200, 400, 800, 1600, ... milliseconds) + * async.retry({ + * times: 10, + * interval: function(retryCount) { + * return 50 * Math.pow(2, retryCount); + * } + * }, apiMethod, function(err, result) { + * // do something with the result + * }); + * + * // try calling apiMethod the default 5 times no delay between each retry + * async.retry(apiMethod, function(err, result) { + * // do something with the result + * }); + * + * // try calling apiMethod only when error condition satisfies, all other + * // errors will abort the retry control flow and return to final callback + * async.retry({ + * errorFilter: function(err) { + * return err.message === 'Temporary error'; // only retry on a specific error + * } + * }, apiMethod, function(err, result) { + * // do something with the result + * }); + * + * // to retry individual methods that are not as reliable within other + * // control flow functions, use the `retryable` wrapper: + * async.auto({ + * users: api.getUsers.bind(api), + * payments: async.retryable(3, api.getPayments.bind(api)) + * }, function(err, results) { + * // do something with the results + * }); + * + */ +function retry(opts, task, callback) { + var DEFAULT_TIMES = 5; + var DEFAULT_INTERVAL = 0; + + var options = { + times: DEFAULT_TIMES, + intervalFunc: (0, _constant2.default)(DEFAULT_INTERVAL) + }; + + function parseTimes(acc, t) { + if (typeof t === 'object') { + acc.times = +t.times || DEFAULT_TIMES; + + acc.intervalFunc = typeof t.interval === 'function' ? t.interval : (0, _constant2.default)(+t.interval || DEFAULT_INTERVAL); + + acc.errorFilter = t.errorFilter; + } else if (typeof t === 'number' || typeof t === 'string') { + acc.times = +t || DEFAULT_TIMES; + } else { + throw new Error("Invalid arguments for async.retry"); + } + } + + if (arguments.length < 3 && typeof opts === 'function') { + callback = task || _noop2.default; + task = opts; + } else { + parseTimes(options, opts); + callback = callback || _noop2.default; + } + + if (typeof task !== 'function') { + throw new Error("Invalid arguments for async.retry"); + } + + var _task = (0, _wrapAsync2.default)(task); + + var attempt = 1; + function retryAttempt() { + _task(function (err) { + if (err && attempt++ < options.times && (typeof options.errorFilter != 'function' || options.errorFilter(err))) { + setTimeout(retryAttempt, options.intervalFunc(attempt)); + } else { + callback.apply(null, arguments); + } + }); + } + + retryAttempt(); +} +module.exports = exports['default']; \ No newline at end of file diff --git a/node_modules/portscanner/node_modules/async/retryable.js b/node_modules/portscanner/node_modules/async/retryable.js new file mode 100644 index 00000000..002bfb0f --- /dev/null +++ b/node_modules/portscanner/node_modules/async/retryable.js @@ -0,0 +1,65 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +exports.default = function (opts, task) { + if (!task) { + task = opts; + opts = null; + } + var _task = (0, _wrapAsync2.default)(task); + return (0, _initialParams2.default)(function (args, callback) { + function taskFn(cb) { + _task.apply(null, args.concat(cb)); + } + + if (opts) (0, _retry2.default)(opts, taskFn, callback);else (0, _retry2.default)(taskFn, callback); + }); +}; + +var _retry = require('./retry'); + +var _retry2 = _interopRequireDefault(_retry); + +var _initialParams = require('./internal/initialParams'); + +var _initialParams2 = _interopRequireDefault(_initialParams); + +var _wrapAsync = require('./internal/wrapAsync'); + +var _wrapAsync2 = _interopRequireDefault(_wrapAsync); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +module.exports = exports['default']; + +/** + * A close relative of [`retry`]{@link module:ControlFlow.retry}. This method + * wraps a task and makes it retryable, rather than immediately calling it + * with retries. + * + * @name retryable + * @static + * @memberOf module:ControlFlow + * @method + * @see [async.retry]{@link module:ControlFlow.retry} + * @category Control Flow + * @param {Object|number} [opts = {times: 5, interval: 0}| 5] - optional + * options, exactly the same as from `retry` + * @param {AsyncFunction} task - the asynchronous function to wrap. + * This function will be passed any arguments passed to the returned wrapper. + * Invoked with (...args, callback). + * @returns {AsyncFunction} The wrapped function, which when invoked, will + * retry on an error, based on the parameters specified in `opts`. + * This function will accept the same parameters as `task`. + * @example + * + * async.auto({ + * dep1: async.retryable(3, getFromFlakyService), + * process: ["dep1", async.retryable(3, function (results, cb) { + * maybeProcessData(results.dep1, cb); + * })] + * }, callback); + */ \ No newline at end of file diff --git a/node_modules/wfilesencoders/node_modules/.bin/js-yaml b/node_modules/wfilesencoders/node_modules/.bin/js-yaml new file mode 120000 index 00000000..9dbd010d --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/.bin/js-yaml @@ -0,0 +1 @@ +../js-yaml/bin/js-yaml.js \ No newline at end of file diff --git a/node_modules/wfilesencoders/node_modules/argparse/CHANGELOG.md b/node_modules/wfilesencoders/node_modules/argparse/CHANGELOG.md new file mode 100644 index 00000000..dc39ed69 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/argparse/CHANGELOG.md @@ -0,0 +1,216 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## [2.0.1] - 2020-08-29 +### Fixed +- Fix issue with `process.argv` when used with interpreters (`coffee`, `ts-node`, etc.), #150. + + +## [2.0.0] - 2020-08-14 +### Changed +- Full rewrite. Now port from python 3.9.0 & more precise following. + See [doc](./doc) for difference and migration info. +- node.js 10+ required +- Removed most of local docs in favour of original ones. + + +## [1.0.10] - 2018-02-15 +### Fixed +- Use .concat instead of + for arrays, #122. + + +## [1.0.9] - 2016-09-29 +### Changed +- Rerelease after 1.0.8 - deps cleanup. + + +## [1.0.8] - 2016-09-29 +### Changed +- Maintenance (deps bump, fix node 6.5+ tests, coverage report). + + +## [1.0.7] - 2016-03-17 +### Changed +- Teach `addArgument` to accept string arg names. #97, @tomxtobin. + + +## [1.0.6] - 2016-02-06 +### Changed +- Maintenance: moved to eslint & updated CS. + + +## [1.0.5] - 2016-02-05 +### Changed +- Removed lodash dependency to significantly reduce install size. + Thanks to @mourner. + + +## [1.0.4] - 2016-01-17 +### Changed +- Maintenance: lodash update to 4.0.0. + + +## [1.0.3] - 2015-10-27 +### Fixed +- Fix parse `=` in args: `--examplepath="C:\myfolder\env=x64"`. #84, @CatWithApple. + + +## [1.0.2] - 2015-03-22 +### Changed +- Relaxed lodash version dependency. + + +## [1.0.1] - 2015-02-20 +### Changed +- Changed dependencies to be compatible with ancient nodejs. + + +## [1.0.0] - 2015-02-19 +### Changed +- Maintenance release. +- Replaced `underscore` with `lodash`. +- Bumped version to 1.0.0 to better reflect semver meaning. +- HISTORY.md -> CHANGELOG.md + + +## [0.1.16] - 2013-12-01 +### Changed +- Maintenance release. Updated dependencies and docs. + + +## [0.1.15] - 2013-05-13 +### Fixed +- Fixed #55, @trebor89 + + +## [0.1.14] - 2013-05-12 +### Fixed +- Fixed #62, @maxtaco + + +## [0.1.13] - 2013-04-08 +### Changed +- Added `.npmignore` to reduce package size + + +## [0.1.12] - 2013-02-10 +### Fixed +- Fixed conflictHandler (#46), @hpaulj + + +## [0.1.11] - 2013-02-07 +### Added +- Added 70+ tests (ported from python), @hpaulj +- Added conflictHandler, @applepicke +- Added fromfilePrefixChar, @hpaulj + +### Fixed +- Multiple bugfixes, @hpaulj + + +## [0.1.10] - 2012-12-30 +### Added +- Added [mutual exclusion](http://docs.python.org/dev/library/argparse.html#mutual-exclusion) + support, thanks to @hpaulj + +### Fixed +- Fixed options check for `storeConst` & `appendConst` actions, thanks to @hpaulj + + +## [0.1.9] - 2012-12-27 +### Fixed +- Fixed option dest interferens with other options (issue #23), thanks to @hpaulj +- Fixed default value behavior with `*` positionals, thanks to @hpaulj +- Improve `getDefault()` behavior, thanks to @hpaulj +- Improve negative argument parsing, thanks to @hpaulj + + +## [0.1.8] - 2012-12-01 +### Fixed +- Fixed parser parents (issue #19), thanks to @hpaulj +- Fixed negative argument parse (issue #20), thanks to @hpaulj + + +## [0.1.7] - 2012-10-14 +### Fixed +- Fixed 'choices' argument parse (issue #16) +- Fixed stderr output (issue #15) + + +## [0.1.6] - 2012-09-09 +### Fixed +- Fixed check for conflict of options (thanks to @tomxtobin) + + +## [0.1.5] - 2012-09-03 +### Fixed +- Fix parser #setDefaults method (thanks to @tomxtobin) + + +## [0.1.4] - 2012-07-30 +### Fixed +- Fixed pseudo-argument support (thanks to @CGamesPlay) +- Fixed addHelp default (should be true), if not set (thanks to @benblank) + + +## [0.1.3] - 2012-06-27 +### Fixed +- Fixed formatter api name: Formatter -> HelpFormatter + + +## [0.1.2] - 2012-05-29 +### Fixed +- Removed excess whitespace in help +- Fixed error reporting, when parcer with subcommands + called with empty arguments + +### Added +- Added basic tests + + +## [0.1.1] - 2012-05-23 +### Fixed +- Fixed line wrapping in help formatter +- Added better error reporting on invalid arguments + + +## [0.1.0] - 2012-05-16 +### Added +- First release. + + +[2.0.1]: https://github.com/nodeca/argparse/compare/2.0.0...2.0.1 +[2.0.0]: https://github.com/nodeca/argparse/compare/1.0.10...2.0.0 +[1.0.10]: https://github.com/nodeca/argparse/compare/1.0.9...1.0.10 +[1.0.9]: https://github.com/nodeca/argparse/compare/1.0.8...1.0.9 +[1.0.8]: https://github.com/nodeca/argparse/compare/1.0.7...1.0.8 +[1.0.7]: https://github.com/nodeca/argparse/compare/1.0.6...1.0.7 +[1.0.6]: https://github.com/nodeca/argparse/compare/1.0.5...1.0.6 +[1.0.5]: https://github.com/nodeca/argparse/compare/1.0.4...1.0.5 +[1.0.4]: https://github.com/nodeca/argparse/compare/1.0.3...1.0.4 +[1.0.3]: https://github.com/nodeca/argparse/compare/1.0.2...1.0.3 +[1.0.2]: https://github.com/nodeca/argparse/compare/1.0.1...1.0.2 +[1.0.1]: https://github.com/nodeca/argparse/compare/1.0.0...1.0.1 +[1.0.0]: https://github.com/nodeca/argparse/compare/0.1.16...1.0.0 +[0.1.16]: https://github.com/nodeca/argparse/compare/0.1.15...0.1.16 +[0.1.15]: https://github.com/nodeca/argparse/compare/0.1.14...0.1.15 +[0.1.14]: https://github.com/nodeca/argparse/compare/0.1.13...0.1.14 +[0.1.13]: https://github.com/nodeca/argparse/compare/0.1.12...0.1.13 +[0.1.12]: https://github.com/nodeca/argparse/compare/0.1.11...0.1.12 +[0.1.11]: https://github.com/nodeca/argparse/compare/0.1.10...0.1.11 +[0.1.10]: https://github.com/nodeca/argparse/compare/0.1.9...0.1.10 +[0.1.9]: https://github.com/nodeca/argparse/compare/0.1.8...0.1.9 +[0.1.8]: https://github.com/nodeca/argparse/compare/0.1.7...0.1.8 +[0.1.7]: https://github.com/nodeca/argparse/compare/0.1.6...0.1.7 +[0.1.6]: https://github.com/nodeca/argparse/compare/0.1.5...0.1.6 +[0.1.5]: https://github.com/nodeca/argparse/compare/0.1.4...0.1.5 +[0.1.4]: https://github.com/nodeca/argparse/compare/0.1.3...0.1.4 +[0.1.3]: https://github.com/nodeca/argparse/compare/0.1.2...0.1.3 +[0.1.2]: https://github.com/nodeca/argparse/compare/0.1.1...0.1.2 +[0.1.1]: https://github.com/nodeca/argparse/compare/0.1.0...0.1.1 +[0.1.0]: https://github.com/nodeca/argparse/releases/tag/0.1.0 diff --git a/node_modules/wfilesencoders/node_modules/argparse/LICENSE b/node_modules/wfilesencoders/node_modules/argparse/LICENSE new file mode 100644 index 00000000..66a3ac80 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/argparse/LICENSE @@ -0,0 +1,254 @@ +A. HISTORY OF THE SOFTWARE +========================== + +Python was created in the early 1990s by Guido van Rossum at Stichting +Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands +as a successor of a language called ABC. Guido remains Python's +principal author, although it includes many contributions from others. + +In 1995, Guido continued his work on Python at the Corporation for +National Research Initiatives (CNRI, see http://www.cnri.reston.va.us) +in Reston, Virginia where he released several versions of the +software. + +In May 2000, Guido and the Python core development team moved to +BeOpen.com to form the BeOpen PythonLabs team. In October of the same +year, the PythonLabs team moved to Digital Creations, which became +Zope Corporation. In 2001, the Python Software Foundation (PSF, see +https://www.python.org/psf/) was formed, a non-profit organization +created specifically to own Python-related Intellectual Property. +Zope Corporation was a sponsoring member of the PSF. + +All Python releases are Open Source (see http://www.opensource.org for +the Open Source Definition). Historically, most, but not all, Python +releases have also been GPL-compatible; the table below summarizes +the various releases. + + Release Derived Year Owner GPL- + from compatible? (1) + + 0.9.0 thru 1.2 1991-1995 CWI yes + 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes + 1.6 1.5.2 2000 CNRI no + 2.0 1.6 2000 BeOpen.com no + 1.6.1 1.6 2001 CNRI yes (2) + 2.1 2.0+1.6.1 2001 PSF no + 2.0.1 2.0+1.6.1 2001 PSF yes + 2.1.1 2.1+2.0.1 2001 PSF yes + 2.1.2 2.1.1 2002 PSF yes + 2.1.3 2.1.2 2002 PSF yes + 2.2 and above 2.1.1 2001-now PSF yes + +Footnotes: + +(1) GPL-compatible doesn't mean that we're distributing Python under + the GPL. All Python licenses, unlike the GPL, let you distribute + a modified version without making your changes open source. The + GPL-compatible licenses make it possible to combine Python with + other software that is released under the GPL; the others don't. + +(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, + because its license has a choice of law clause. According to + CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 + is "not incompatible" with the GPL. + +Thanks to the many outside volunteers who have worked under Guido's +direction to make these releases possible. + + +B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON +=============================================================== + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative version +prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 +------------------------------------------- + +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 + +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the +Individual or Organization ("Licensee") accessing and otherwise using +this software in source or binary form and its associated +documentation ("the Software"). + +2. Subject to the terms and conditions of this BeOpen Python License +Agreement, BeOpen hereby grants Licensee a non-exclusive, +royalty-free, world-wide license to reproduce, analyze, test, perform +and/or display publicly, prepare derivative works, distribute, and +otherwise use the Software alone or in any derivative version, +provided, however, that the BeOpen Python License is retained in the +Software, alone or in any derivative version prepared by Licensee. + +3. BeOpen is making the Software available to Licensee on an "AS IS" +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +5. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +6. This License Agreement shall be governed by and interpreted in all +respects by the law of the State of California, excluding conflict of +law provisions. Nothing in this License Agreement shall be deemed to +create any relationship of agency, partnership, or joint venture +between BeOpen and Licensee. This License Agreement does not grant +permission to use BeOpen trademarks or trade names in a trademark +sense to endorse or promote products or services of Licensee, or any +third party. As an exception, the "BeOpen Python" logos available at +http://www.pythonlabs.com/logos.html may be used according to the +permissions granted on that web page. + +7. By copying, installing or otherwise using the software, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 +--------------------------------------- + +1. This LICENSE AGREEMENT is between the Corporation for National +Research Initiatives, having an office at 1895 Preston White Drive, +Reston, VA 20191 ("CNRI"), and the Individual or Organization +("Licensee") accessing and otherwise using Python 1.6.1 software in +source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, CNRI +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python 1.6.1 +alone or in any derivative version, provided, however, that CNRI's +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) +1995-2001 Corporation for National Research Initiatives; All Rights +Reserved" are retained in Python 1.6.1 alone or in any derivative +version prepared by Licensee. Alternately, in lieu of CNRI's License +Agreement, Licensee may substitute the following text (omitting the +quotes): "Python 1.6.1 is made available subject to the terms and +conditions in CNRI's License Agreement. This Agreement together with +Python 1.6.1 may be located on the Internet using the following +unique, persistent identifier (known as a handle): 1895.22/1013. This +Agreement may also be obtained from a proxy server on the Internet +using the following URL: http://hdl.handle.net/1895.22/1013". + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 1.6.1 or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python 1.6.1. + +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. This License Agreement shall be governed by the federal +intellectual property law of the United States, including without +limitation the federal copyright law, and, to the extent such +U.S. federal law does not apply, by the law of the Commonwealth of +Virginia, excluding Virginia's conflict of law provisions. +Notwithstanding the foregoing, with regard to derivative works based +on Python 1.6.1 that incorporate non-separable material that was +previously distributed under the GNU General Public License (GPL), the +law of the Commonwealth of Virginia shall govern this License +Agreement only as to issues arising under or with respect to +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this +License Agreement shall be deemed to create any relationship of +agency, partnership, or joint venture between CNRI and Licensee. This +License Agreement does not grant permission to use CNRI trademarks or +trade name in a trademark sense to endorse or promote products or +services of Licensee, or any third party. + +8. By clicking on the "ACCEPT" button where indicated, or by copying, +installing or otherwise using Python 1.6.1, Licensee agrees to be +bound by the terms and conditions of this License Agreement. + + ACCEPT + + +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 +-------------------------------------------------- + +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, +The Netherlands. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/wfilesencoders/node_modules/argparse/README.md b/node_modules/wfilesencoders/node_modules/argparse/README.md new file mode 100644 index 00000000..550b5c9b --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/argparse/README.md @@ -0,0 +1,84 @@ +argparse +======== + +[![Build Status](https://secure.travis-ci.org/nodeca/argparse.svg?branch=master)](http://travis-ci.org/nodeca/argparse) +[![NPM version](https://img.shields.io/npm/v/argparse.svg)](https://www.npmjs.org/package/argparse) + +CLI arguments parser for node.js, with [sub-commands](https://docs.python.org/3.9/library/argparse.html#sub-commands) support. Port of python's [argparse](http://docs.python.org/dev/library/argparse.html) (version [3.9.0](https://github.com/python/cpython/blob/v3.9.0rc1/Lib/argparse.py)). + +**Difference with original.** + +- JS has no keyword arguments support. + - Pass options instead: `new ArgumentParser({ description: 'example', add_help: true })`. +- JS has no python's types `int`, `float`, ... + - Use string-typed names: `.add_argument('-b', { type: 'int', help: 'help' })`. +- `%r` format specifier uses `require('util').inspect()`. + +More details in [doc](./doc). + + +Example +------- + +`test.js` file: + +```javascript +#!/usr/bin/env node +'use strict'; + +const { ArgumentParser } = require('argparse'); +const { version } = require('./package.json'); + +const parser = new ArgumentParser({ + description: 'Argparse example' +}); + +parser.add_argument('-v', '--version', { action: 'version', version }); +parser.add_argument('-f', '--foo', { help: 'foo bar' }); +parser.add_argument('-b', '--bar', { help: 'bar foo' }); +parser.add_argument('--baz', { help: 'baz bar' }); + +console.dir(parser.parse_args()); +``` + +Display help: + +``` +$ ./test.js -h +usage: test.js [-h] [-v] [-f FOO] [-b BAR] [--baz BAZ] + +Argparse example + +optional arguments: + -h, --help show this help message and exit + -v, --version show program's version number and exit + -f FOO, --foo FOO foo bar + -b BAR, --bar BAR bar foo + --baz BAZ baz bar +``` + +Parse arguments: + +``` +$ ./test.js -f=3 --bar=4 --baz 5 +{ foo: '3', bar: '4', baz: '5' } +``` + + +API docs +-------- + +Since this is a port with minimal divergence, there's no separate documentation. +Use original one instead, with notes about difference. + +1. [Original doc](https://docs.python.org/3.9/library/argparse.html). +2. [Original tutorial](https://docs.python.org/3.9/howto/argparse.html). +3. [Difference with python](./doc). + + +argparse for enterprise +----------------------- + +Available as part of the Tidelift Subscription + +The maintainers of argparse and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-argparse?utm_source=npm-argparse&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) diff --git a/node_modules/wfilesencoders/node_modules/argparse/argparse.js b/node_modules/wfilesencoders/node_modules/argparse/argparse.js new file mode 100644 index 00000000..2b8c8c63 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/argparse/argparse.js @@ -0,0 +1,3707 @@ +// Port of python's argparse module, version 3.9.0: +// https://github.com/python/cpython/blob/v3.9.0rc1/Lib/argparse.py + +'use strict' + +// Copyright (C) 2010-2020 Python Software Foundation. +// Copyright (C) 2020 argparse.js authors + +/* + * Command-line parsing library + * + * This module is an optparse-inspired command-line parsing library that: + * + * - handles both optional and positional arguments + * - produces highly informative usage messages + * - supports parsers that dispatch to sub-parsers + * + * The following is a simple usage example that sums integers from the + * command-line and writes the result to a file:: + * + * parser = argparse.ArgumentParser( + * description='sum the integers at the command line') + * parser.add_argument( + * 'integers', metavar='int', nargs='+', type=int, + * help='an integer to be summed') + * parser.add_argument( + * '--log', default=sys.stdout, type=argparse.FileType('w'), + * help='the file where the sum should be written') + * args = parser.parse_args() + * args.log.write('%s' % sum(args.integers)) + * args.log.close() + * + * The module contains the following public classes: + * + * - ArgumentParser -- The main entry point for command-line parsing. As the + * example above shows, the add_argument() method is used to populate + * the parser with actions for optional and positional arguments. Then + * the parse_args() method is invoked to convert the args at the + * command-line into an object with attributes. + * + * - ArgumentError -- The exception raised by ArgumentParser objects when + * there are errors with the parser's actions. Errors raised while + * parsing the command-line are caught by ArgumentParser and emitted + * as command-line messages. + * + * - FileType -- A factory for defining types of files to be created. As the + * example above shows, instances of FileType are typically passed as + * the type= argument of add_argument() calls. + * + * - Action -- The base class for parser actions. Typically actions are + * selected by passing strings like 'store_true' or 'append_const' to + * the action= argument of add_argument(). However, for greater + * customization of ArgumentParser actions, subclasses of Action may + * be defined and passed as the action= argument. + * + * - HelpFormatter, RawDescriptionHelpFormatter, RawTextHelpFormatter, + * ArgumentDefaultsHelpFormatter -- Formatter classes which + * may be passed as the formatter_class= argument to the + * ArgumentParser constructor. HelpFormatter is the default, + * RawDescriptionHelpFormatter and RawTextHelpFormatter tell the parser + * not to change the formatting for help text, and + * ArgumentDefaultsHelpFormatter adds information about argument defaults + * to the help. + * + * All other classes in this module are considered implementation details. + * (Also note that HelpFormatter and RawDescriptionHelpFormatter are only + * considered public as object names -- the API of the formatter objects is + * still considered an implementation detail.) + */ + +const SUPPRESS = '==SUPPRESS==' + +const OPTIONAL = '?' +const ZERO_OR_MORE = '*' +const ONE_OR_MORE = '+' +const PARSER = 'A...' +const REMAINDER = '...' +const _UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args' + + +// ================================== +// Utility functions used for porting +// ================================== +const assert = require('assert') +const util = require('util') +const fs = require('fs') +const sub = require('./lib/sub') +const path = require('path') +const repr = util.inspect + +function get_argv() { + // omit first argument (which is assumed to be interpreter - `node`, `coffee`, `ts-node`, etc.) + return process.argv.slice(1) +} + +function get_terminal_size() { + return { + columns: +process.env.COLUMNS || process.stdout.columns || 80 + } +} + +function hasattr(object, name) { + return Object.prototype.hasOwnProperty.call(object, name) +} + +function getattr(object, name, value) { + return hasattr(object, name) ? object[name] : value +} + +function setattr(object, name, value) { + object[name] = value +} + +function setdefault(object, name, value) { + if (!hasattr(object, name)) object[name] = value + return object[name] +} + +function delattr(object, name) { + delete object[name] +} + +function range(from, to, step=1) { + // range(10) is equivalent to range(0, 10) + if (arguments.length === 1) [ to, from ] = [ from, 0 ] + if (typeof from !== 'number' || typeof to !== 'number' || typeof step !== 'number') { + throw new TypeError('argument cannot be interpreted as an integer') + } + if (step === 0) throw new TypeError('range() arg 3 must not be zero') + + let result = [] + if (step > 0) { + for (let i = from; i < to; i += step) result.push(i) + } else { + for (let i = from; i > to; i += step) result.push(i) + } + return result +} + +function splitlines(str, keepends = false) { + let result + if (!keepends) { + result = str.split(/\r\n|[\n\r\v\f\x1c\x1d\x1e\x85\u2028\u2029]/) + } else { + result = [] + let parts = str.split(/(\r\n|[\n\r\v\f\x1c\x1d\x1e\x85\u2028\u2029])/) + for (let i = 0; i < parts.length; i += 2) { + result.push(parts[i] + (i + 1 < parts.length ? parts[i + 1] : '')) + } + } + if (!result[result.length - 1]) result.pop() + return result +} + +function _string_lstrip(string, prefix_chars) { + let idx = 0 + while (idx < string.length && prefix_chars.includes(string[idx])) idx++ + return idx ? string.slice(idx) : string +} + +function _string_split(string, sep, maxsplit) { + let result = string.split(sep) + if (result.length > maxsplit) { + result = result.slice(0, maxsplit).concat([ result.slice(maxsplit).join(sep) ]) + } + return result +} + +function _array_equal(array1, array2) { + if (array1.length !== array2.length) return false + for (let i = 0; i < array1.length; i++) { + if (array1[i] !== array2[i]) return false + } + return true +} + +function _array_remove(array, item) { + let idx = array.indexOf(item) + if (idx === -1) throw new TypeError(sub('%r not in list', item)) + array.splice(idx, 1) +} + +// normalize choices to array; +// this isn't required in python because `in` and `map` operators work with anything, +// but in js dealing with multiple types here is too clunky +function _choices_to_array(choices) { + if (choices === undefined) { + return [] + } else if (Array.isArray(choices)) { + return choices + } else if (choices !== null && typeof choices[Symbol.iterator] === 'function') { + return Array.from(choices) + } else if (typeof choices === 'object' && choices !== null) { + return Object.keys(choices) + } else { + throw new Error(sub('invalid choices value: %r', choices)) + } +} + +// decorator that allows a class to be called without new +function _callable(cls) { + let result = { // object is needed for inferred class name + [cls.name]: function (...args) { + let this_class = new.target === result || !new.target + return Reflect.construct(cls, args, this_class ? cls : new.target) + } + } + result[cls.name].prototype = cls.prototype + // fix default tag for toString, e.g. [object Action] instead of [object Object] + cls.prototype[Symbol.toStringTag] = cls.name + return result[cls.name] +} + +function _alias(object, from, to) { + try { + let name = object.constructor.name + Object.defineProperty(object, from, { + value: util.deprecate(object[to], sub('%s.%s() is renamed to %s.%s()', + name, from, name, to)), + enumerable: false + }) + } catch {} +} + +// decorator that allows snake_case class methods to be called with camelCase and vice versa +function _camelcase_alias(_class) { + for (let name of Object.getOwnPropertyNames(_class.prototype)) { + let camelcase = name.replace(/\w_[a-z]/g, s => s[0] + s[2].toUpperCase()) + if (camelcase !== name) _alias(_class.prototype, camelcase, name) + } + return _class +} + +function _to_legacy_name(key) { + key = key.replace(/\w_[a-z]/g, s => s[0] + s[2].toUpperCase()) + if (key === 'default') key = 'defaultValue' + if (key === 'const') key = 'constant' + return key +} + +function _to_new_name(key) { + if (key === 'defaultValue') key = 'default' + if (key === 'constant') key = 'const' + key = key.replace(/[A-Z]/g, c => '_' + c.toLowerCase()) + return key +} + +// parse options +let no_default = Symbol('no_default_value') +function _parse_opts(args, descriptor) { + function get_name() { + let stack = new Error().stack.split('\n') + .map(x => x.match(/^ at (.*) \(.*\)$/)) + .filter(Boolean) + .map(m => m[1]) + .map(fn => fn.match(/[^ .]*$/)[0]) + + if (stack.length && stack[0] === get_name.name) stack.shift() + if (stack.length && stack[0] === _parse_opts.name) stack.shift() + return stack.length ? stack[0] : '' + } + + args = Array.from(args) + let kwargs = {} + let result = [] + let last_opt = args.length && args[args.length - 1] + + if (typeof last_opt === 'object' && last_opt !== null && !Array.isArray(last_opt) && + (!last_opt.constructor || last_opt.constructor.name === 'Object')) { + kwargs = Object.assign({}, args.pop()) + } + + // LEGACY (v1 compatibility): camelcase + let renames = [] + for (let key of Object.keys(descriptor)) { + let old_name = _to_legacy_name(key) + if (old_name !== key && (old_name in kwargs)) { + if (key in kwargs) { + // default and defaultValue specified at the same time, happens often in old tests + //throw new TypeError(sub('%s() got multiple values for argument %r', get_name(), key)) + } else { + kwargs[key] = kwargs[old_name] + } + renames.push([ old_name, key ]) + delete kwargs[old_name] + } + } + if (renames.length) { + let name = get_name() + deprecate('camelcase_' + name, sub('%s(): following options are renamed: %s', + name, renames.map(([ a, b ]) => sub('%r -> %r', a, b)))) + } + // end + + let missing_positionals = [] + let positional_count = args.length + + for (let [ key, def ] of Object.entries(descriptor)) { + if (key[0] === '*') { + if (key.length > 0 && key[1] === '*') { + // LEGACY (v1 compatibility): camelcase + let renames = [] + for (let key of Object.keys(kwargs)) { + let new_name = _to_new_name(key) + if (new_name !== key && (key in kwargs)) { + if (new_name in kwargs) { + // default and defaultValue specified at the same time, happens often in old tests + //throw new TypeError(sub('%s() got multiple values for argument %r', get_name(), new_name)) + } else { + kwargs[new_name] = kwargs[key] + } + renames.push([ key, new_name ]) + delete kwargs[key] + } + } + if (renames.length) { + let name = get_name() + deprecate('camelcase_' + name, sub('%s(): following options are renamed: %s', + name, renames.map(([ a, b ]) => sub('%r -> %r', a, b)))) + } + // end + result.push(kwargs) + kwargs = {} + } else { + result.push(args) + args = [] + } + } else if (key in kwargs && args.length > 0) { + throw new TypeError(sub('%s() got multiple values for argument %r', get_name(), key)) + } else if (key in kwargs) { + result.push(kwargs[key]) + delete kwargs[key] + } else if (args.length > 0) { + result.push(args.shift()) + } else if (def !== no_default) { + result.push(def) + } else { + missing_positionals.push(key) + } + } + + if (Object.keys(kwargs).length) { + throw new TypeError(sub('%s() got an unexpected keyword argument %r', + get_name(), Object.keys(kwargs)[0])) + } + + if (args.length) { + let from = Object.entries(descriptor).filter(([ k, v ]) => k[0] !== '*' && v !== no_default).length + let to = Object.entries(descriptor).filter(([ k ]) => k[0] !== '*').length + throw new TypeError(sub('%s() takes %s positional argument%s but %s %s given', + get_name(), + from === to ? sub('from %s to %s', from, to) : to, + from === to && to === 1 ? '' : 's', + positional_count, + positional_count === 1 ? 'was' : 'were')) + } + + if (missing_positionals.length) { + let strs = missing_positionals.map(repr) + if (strs.length > 1) strs[strs.length - 1] = 'and ' + strs[strs.length - 1] + let str_joined = strs.join(strs.length === 2 ? '' : ', ') + throw new TypeError(sub('%s() missing %i required positional argument%s: %s', + get_name(), strs.length, strs.length === 1 ? '' : 's', str_joined)) + } + + return result +} + +let _deprecations = {} +function deprecate(id, string) { + _deprecations[id] = _deprecations[id] || util.deprecate(() => {}, string) + _deprecations[id]() +} + + +// ============================= +// Utility functions and classes +// ============================= +function _AttributeHolder(cls = Object) { + /* + * Abstract base class that provides __repr__. + * + * The __repr__ method returns a string in the format:: + * ClassName(attr=name, attr=name, ...) + * The attributes are determined either by a class-level attribute, + * '_kwarg_names', or by inspecting the instance __dict__. + */ + + return class _AttributeHolder extends cls { + [util.inspect.custom]() { + let type_name = this.constructor.name + let arg_strings = [] + let star_args = {} + for (let arg of this._get_args()) { + arg_strings.push(repr(arg)) + } + for (let [ name, value ] of this._get_kwargs()) { + if (/^[a-z_][a-z0-9_$]*$/i.test(name)) { + arg_strings.push(sub('%s=%r', name, value)) + } else { + star_args[name] = value + } + } + if (Object.keys(star_args).length) { + arg_strings.push(sub('**%s', repr(star_args))) + } + return sub('%s(%s)', type_name, arg_strings.join(', ')) + } + + toString() { + return this[util.inspect.custom]() + } + + _get_kwargs() { + return Object.entries(this) + } + + _get_args() { + return [] + } + } +} + + +function _copy_items(items) { + if (items === undefined) { + return [] + } + return items.slice(0) +} + + +// =============== +// Formatting Help +// =============== +const HelpFormatter = _camelcase_alias(_callable(class HelpFormatter { + /* + * Formatter for generating usage messages and argument help strings. + * + * Only the name of this class is considered a public API. All the methods + * provided by the class are considered an implementation detail. + */ + + constructor() { + let [ + prog, + indent_increment, + max_help_position, + width + ] = _parse_opts(arguments, { + prog: no_default, + indent_increment: 2, + max_help_position: 24, + width: undefined + }) + + // default setting for width + if (width === undefined) { + width = get_terminal_size().columns + width -= 2 + } + + this._prog = prog + this._indent_increment = indent_increment + this._max_help_position = Math.min(max_help_position, + Math.max(width - 20, indent_increment * 2)) + this._width = width + + this._current_indent = 0 + this._level = 0 + this._action_max_length = 0 + + this._root_section = this._Section(this, undefined) + this._current_section = this._root_section + + this._whitespace_matcher = /[ \t\n\r\f\v]+/g // equivalent to python /\s+/ with ASCII flag + this._long_break_matcher = /\n\n\n+/g + } + + // =============================== + // Section and indentation methods + // =============================== + _indent() { + this._current_indent += this._indent_increment + this._level += 1 + } + + _dedent() { + this._current_indent -= this._indent_increment + assert(this._current_indent >= 0, 'Indent decreased below 0.') + this._level -= 1 + } + + _add_item(func, args) { + this._current_section.items.push([ func, args ]) + } + + // ======================== + // Message building methods + // ======================== + start_section(heading) { + this._indent() + let section = this._Section(this, this._current_section, heading) + this._add_item(section.format_help.bind(section), []) + this._current_section = section + } + + end_section() { + this._current_section = this._current_section.parent + this._dedent() + } + + add_text(text) { + if (text !== SUPPRESS && text !== undefined) { + this._add_item(this._format_text.bind(this), [text]) + } + } + + add_usage(usage, actions, groups, prefix = undefined) { + if (usage !== SUPPRESS) { + let args = [ usage, actions, groups, prefix ] + this._add_item(this._format_usage.bind(this), args) + } + } + + add_argument(action) { + if (action.help !== SUPPRESS) { + + // find all invocations + let invocations = [this._format_action_invocation(action)] + for (let subaction of this._iter_indented_subactions(action)) { + invocations.push(this._format_action_invocation(subaction)) + } + + // update the maximum item length + let invocation_length = Math.max(...invocations.map(invocation => invocation.length)) + let action_length = invocation_length + this._current_indent + this._action_max_length = Math.max(this._action_max_length, + action_length) + + // add the item to the list + this._add_item(this._format_action.bind(this), [action]) + } + } + + add_arguments(actions) { + for (let action of actions) { + this.add_argument(action) + } + } + + // ======================= + // Help-formatting methods + // ======================= + format_help() { + let help = this._root_section.format_help() + if (help) { + help = help.replace(this._long_break_matcher, '\n\n') + help = help.replace(/^\n+|\n+$/g, '') + '\n' + } + return help + } + + _join_parts(part_strings) { + return part_strings.filter(part => part && part !== SUPPRESS).join('') + } + + _format_usage(usage, actions, groups, prefix) { + if (prefix === undefined) { + prefix = 'usage: ' + } + + // if usage is specified, use that + if (usage !== undefined) { + usage = sub(usage, { prog: this._prog }) + + // if no optionals or positionals are available, usage is just prog + } else if (usage === undefined && !actions.length) { + usage = sub('%(prog)s', { prog: this._prog }) + + // if optionals and positionals are available, calculate usage + } else if (usage === undefined) { + let prog = sub('%(prog)s', { prog: this._prog }) + + // split optionals from positionals + let optionals = [] + let positionals = [] + for (let action of actions) { + if (action.option_strings.length) { + optionals.push(action) + } else { + positionals.push(action) + } + } + + // build full usage string + let action_usage = this._format_actions_usage([].concat(optionals).concat(positionals), groups) + usage = [ prog, action_usage ].map(String).join(' ') + + // wrap the usage parts if it's too long + let text_width = this._width - this._current_indent + if (prefix.length + usage.length > text_width) { + + // break usage into wrappable parts + let part_regexp = /\(.*?\)+(?=\s|$)|\[.*?\]+(?=\s|$)|\S+/g + let opt_usage = this._format_actions_usage(optionals, groups) + let pos_usage = this._format_actions_usage(positionals, groups) + let opt_parts = opt_usage.match(part_regexp) || [] + let pos_parts = pos_usage.match(part_regexp) || [] + assert(opt_parts.join(' ') === opt_usage) + assert(pos_parts.join(' ') === pos_usage) + + // helper for wrapping lines + let get_lines = (parts, indent, prefix = undefined) => { + let lines = [] + let line = [] + let line_len + if (prefix !== undefined) { + line_len = prefix.length - 1 + } else { + line_len = indent.length - 1 + } + for (let part of parts) { + if (line_len + 1 + part.length > text_width && line) { + lines.push(indent + line.join(' ')) + line = [] + line_len = indent.length - 1 + } + line.push(part) + line_len += part.length + 1 + } + if (line.length) { + lines.push(indent + line.join(' ')) + } + if (prefix !== undefined) { + lines[0] = lines[0].slice(indent.length) + } + return lines + } + + let lines + + // if prog is short, follow it with optionals or positionals + if (prefix.length + prog.length <= 0.75 * text_width) { + let indent = ' '.repeat(prefix.length + prog.length + 1) + if (opt_parts.length) { + lines = get_lines([prog].concat(opt_parts), indent, prefix) + lines = lines.concat(get_lines(pos_parts, indent)) + } else if (pos_parts.length) { + lines = get_lines([prog].concat(pos_parts), indent, prefix) + } else { + lines = [prog] + } + + // if prog is long, put it on its own line + } else { + let indent = ' '.repeat(prefix.length) + let parts = [].concat(opt_parts).concat(pos_parts) + lines = get_lines(parts, indent) + if (lines.length > 1) { + lines = [] + lines = lines.concat(get_lines(opt_parts, indent)) + lines = lines.concat(get_lines(pos_parts, indent)) + } + lines = [prog].concat(lines) + } + + // join lines into usage + usage = lines.join('\n') + } + } + + // prefix with 'usage:' + return sub('%s%s\n\n', prefix, usage) + } + + _format_actions_usage(actions, groups) { + // find group indices and identify actions in groups + let group_actions = new Set() + let inserts = {} + for (let group of groups) { + let start = actions.indexOf(group._group_actions[0]) + if (start === -1) { + continue + } else { + let end = start + group._group_actions.length + if (_array_equal(actions.slice(start, end), group._group_actions)) { + for (let action of group._group_actions) { + group_actions.add(action) + } + if (!group.required) { + if (start in inserts) { + inserts[start] += ' [' + } else { + inserts[start] = '[' + } + if (end in inserts) { + inserts[end] += ']' + } else { + inserts[end] = ']' + } + } else { + if (start in inserts) { + inserts[start] += ' (' + } else { + inserts[start] = '(' + } + if (end in inserts) { + inserts[end] += ')' + } else { + inserts[end] = ')' + } + } + for (let i of range(start + 1, end)) { + inserts[i] = '|' + } + } + } + } + + // collect all actions format strings + let parts = [] + for (let [ i, action ] of Object.entries(actions)) { + + // suppressed arguments are marked with None + // remove | separators for suppressed arguments + if (action.help === SUPPRESS) { + parts.push(undefined) + if (inserts[+i] === '|') { + delete inserts[+i] + } else if (inserts[+i + 1] === '|') { + delete inserts[+i + 1] + } + + // produce all arg strings + } else if (!action.option_strings.length) { + let default_value = this._get_default_metavar_for_positional(action) + let part = this._format_args(action, default_value) + + // if it's in a group, strip the outer [] + if (group_actions.has(action)) { + if (part[0] === '[' && part[part.length - 1] === ']') { + part = part.slice(1, -1) + } + } + + // add the action string to the list + parts.push(part) + + // produce the first way to invoke the option in brackets + } else { + let option_string = action.option_strings[0] + let part + + // if the Optional doesn't take a value, format is: + // -s or --long + if (action.nargs === 0) { + part = action.format_usage() + + // if the Optional takes a value, format is: + // -s ARGS or --long ARGS + } else { + let default_value = this._get_default_metavar_for_optional(action) + let args_string = this._format_args(action, default_value) + part = sub('%s %s', option_string, args_string) + } + + // make it look optional if it's not required or in a group + if (!action.required && !group_actions.has(action)) { + part = sub('[%s]', part) + } + + // add the action string to the list + parts.push(part) + } + } + + // insert things at the necessary indices + for (let i of Object.keys(inserts).map(Number).sort((a, b) => b - a)) { + parts.splice(+i, 0, inserts[+i]) + } + + // join all the action items with spaces + let text = parts.filter(Boolean).join(' ') + + // clean up separators for mutually exclusive groups + text = text.replace(/([\[(]) /g, '$1') + text = text.replace(/ ([\])])/g, '$1') + text = text.replace(/[\[(] *[\])]/g, '') + text = text.replace(/\(([^|]*)\)/g, '$1', text) + text = text.trim() + + // return the text + return text + } + + _format_text(text) { + if (text.includes('%(prog)')) { + text = sub(text, { prog: this._prog }) + } + let text_width = Math.max(this._width - this._current_indent, 11) + let indent = ' '.repeat(this._current_indent) + return this._fill_text(text, text_width, indent) + '\n\n' + } + + _format_action(action) { + // determine the required width and the entry label + let help_position = Math.min(this._action_max_length + 2, + this._max_help_position) + let help_width = Math.max(this._width - help_position, 11) + let action_width = help_position - this._current_indent - 2 + let action_header = this._format_action_invocation(action) + let indent_first + + // no help; start on same line and add a final newline + if (!action.help) { + let tup = [ this._current_indent, '', action_header ] + action_header = sub('%*s%s\n', ...tup) + + // short action name; start on the same line and pad two spaces + } else if (action_header.length <= action_width) { + let tup = [ this._current_indent, '', action_width, action_header ] + action_header = sub('%*s%-*s ', ...tup) + indent_first = 0 + + // long action name; start on the next line + } else { + let tup = [ this._current_indent, '', action_header ] + action_header = sub('%*s%s\n', ...tup) + indent_first = help_position + } + + // collect the pieces of the action help + let parts = [action_header] + + // if there was help for the action, add lines of help text + if (action.help) { + let help_text = this._expand_help(action) + let help_lines = this._split_lines(help_text, help_width) + parts.push(sub('%*s%s\n', indent_first, '', help_lines[0])) + for (let line of help_lines.slice(1)) { + parts.push(sub('%*s%s\n', help_position, '', line)) + } + + // or add a newline if the description doesn't end with one + } else if (!action_header.endsWith('\n')) { + parts.push('\n') + } + + // if there are any sub-actions, add their help as well + for (let subaction of this._iter_indented_subactions(action)) { + parts.push(this._format_action(subaction)) + } + + // return a single string + return this._join_parts(parts) + } + + _format_action_invocation(action) { + if (!action.option_strings.length) { + let default_value = this._get_default_metavar_for_positional(action) + let metavar = this._metavar_formatter(action, default_value)(1)[0] + return metavar + + } else { + let parts = [] + + // if the Optional doesn't take a value, format is: + // -s, --long + if (action.nargs === 0) { + parts = parts.concat(action.option_strings) + + // if the Optional takes a value, format is: + // -s ARGS, --long ARGS + } else { + let default_value = this._get_default_metavar_for_optional(action) + let args_string = this._format_args(action, default_value) + for (let option_string of action.option_strings) { + parts.push(sub('%s %s', option_string, args_string)) + } + } + + return parts.join(', ') + } + } + + _metavar_formatter(action, default_metavar) { + let result + if (action.metavar !== undefined) { + result = action.metavar + } else if (action.choices !== undefined) { + let choice_strs = _choices_to_array(action.choices).map(String) + result = sub('{%s}', choice_strs.join(',')) + } else { + result = default_metavar + } + + function format(tuple_size) { + if (Array.isArray(result)) { + return result + } else { + return Array(tuple_size).fill(result) + } + } + return format + } + + _format_args(action, default_metavar) { + let get_metavar = this._metavar_formatter(action, default_metavar) + let result + if (action.nargs === undefined) { + result = sub('%s', ...get_metavar(1)) + } else if (action.nargs === OPTIONAL) { + result = sub('[%s]', ...get_metavar(1)) + } else if (action.nargs === ZERO_OR_MORE) { + let metavar = get_metavar(1) + if (metavar.length === 2) { + result = sub('[%s [%s ...]]', ...metavar) + } else { + result = sub('[%s ...]', ...metavar) + } + } else if (action.nargs === ONE_OR_MORE) { + result = sub('%s [%s ...]', ...get_metavar(2)) + } else if (action.nargs === REMAINDER) { + result = '...' + } else if (action.nargs === PARSER) { + result = sub('%s ...', ...get_metavar(1)) + } else if (action.nargs === SUPPRESS) { + result = '' + } else { + let formats + try { + formats = range(action.nargs).map(() => '%s') + } catch (err) { + throw new TypeError('invalid nargs value') + } + result = sub(formats.join(' '), ...get_metavar(action.nargs)) + } + return result + } + + _expand_help(action) { + let params = Object.assign({ prog: this._prog }, action) + for (let name of Object.keys(params)) { + if (params[name] === SUPPRESS) { + delete params[name] + } + } + for (let name of Object.keys(params)) { + if (params[name] && params[name].name) { + params[name] = params[name].name + } + } + if (params.choices !== undefined) { + let choices_str = _choices_to_array(params.choices).map(String).join(', ') + params.choices = choices_str + } + // LEGACY (v1 compatibility): camelcase + for (let key of Object.keys(params)) { + let old_name = _to_legacy_name(key) + if (old_name !== key) { + params[old_name] = params[key] + } + } + // end + return sub(this._get_help_string(action), params) + } + + * _iter_indented_subactions(action) { + if (typeof action._get_subactions === 'function') { + this._indent() + yield* action._get_subactions() + this._dedent() + } + } + + _split_lines(text, width) { + text = text.replace(this._whitespace_matcher, ' ').trim() + // The textwrap module is used only for formatting help. + // Delay its import for speeding up the common usage of argparse. + let textwrap = require('./lib/textwrap') + return textwrap.wrap(text, { width }) + } + + _fill_text(text, width, indent) { + text = text.replace(this._whitespace_matcher, ' ').trim() + let textwrap = require('./lib/textwrap') + return textwrap.fill(text, { width, + initial_indent: indent, + subsequent_indent: indent }) + } + + _get_help_string(action) { + return action.help + } + + _get_default_metavar_for_optional(action) { + return action.dest.toUpperCase() + } + + _get_default_metavar_for_positional(action) { + return action.dest + } +})) + +HelpFormatter.prototype._Section = _callable(class _Section { + + constructor(formatter, parent, heading = undefined) { + this.formatter = formatter + this.parent = parent + this.heading = heading + this.items = [] + } + + format_help() { + // format the indented section + if (this.parent !== undefined) { + this.formatter._indent() + } + let item_help = this.formatter._join_parts(this.items.map(([ func, args ]) => func.apply(null, args))) + if (this.parent !== undefined) { + this.formatter._dedent() + } + + // return nothing if the section was empty + if (!item_help) { + return '' + } + + // add the heading if the section was non-empty + let heading + if (this.heading !== SUPPRESS && this.heading !== undefined) { + let current_indent = this.formatter._current_indent + heading = sub('%*s%s:\n', current_indent, '', this.heading) + } else { + heading = '' + } + + // join the section-initial newline, the heading and the help + return this.formatter._join_parts(['\n', heading, item_help, '\n']) + } +}) + + +const RawDescriptionHelpFormatter = _camelcase_alias(_callable(class RawDescriptionHelpFormatter extends HelpFormatter { + /* + * Help message formatter which retains any formatting in descriptions. + * + * Only the name of this class is considered a public API. All the methods + * provided by the class are considered an implementation detail. + */ + + _fill_text(text, width, indent) { + return splitlines(text, true).map(line => indent + line).join('') + } +})) + + +const RawTextHelpFormatter = _camelcase_alias(_callable(class RawTextHelpFormatter extends RawDescriptionHelpFormatter { + /* + * Help message formatter which retains formatting of all help text. + * + * Only the name of this class is considered a public API. All the methods + * provided by the class are considered an implementation detail. + */ + + _split_lines(text/*, width*/) { + return splitlines(text) + } +})) + + +const ArgumentDefaultsHelpFormatter = _camelcase_alias(_callable(class ArgumentDefaultsHelpFormatter extends HelpFormatter { + /* + * Help message formatter which adds default values to argument help. + * + * Only the name of this class is considered a public API. All the methods + * provided by the class are considered an implementation detail. + */ + + _get_help_string(action) { + let help = action.help + // LEGACY (v1 compatibility): additional check for defaultValue needed + if (!action.help.includes('%(default)') && !action.help.includes('%(defaultValue)')) { + if (action.default !== SUPPRESS) { + let defaulting_nargs = [OPTIONAL, ZERO_OR_MORE] + if (action.option_strings.length || defaulting_nargs.includes(action.nargs)) { + help += ' (default: %(default)s)' + } + } + } + return help + } +})) + + +const MetavarTypeHelpFormatter = _camelcase_alias(_callable(class MetavarTypeHelpFormatter extends HelpFormatter { + /* + * Help message formatter which uses the argument 'type' as the default + * metavar value (instead of the argument 'dest') + * + * Only the name of this class is considered a public API. All the methods + * provided by the class are considered an implementation detail. + */ + + _get_default_metavar_for_optional(action) { + return typeof action.type === 'function' ? action.type.name : action.type + } + + _get_default_metavar_for_positional(action) { + return typeof action.type === 'function' ? action.type.name : action.type + } +})) + + +// ===================== +// Options and Arguments +// ===================== +function _get_action_name(argument) { + if (argument === undefined) { + return undefined + } else if (argument.option_strings.length) { + return argument.option_strings.join('/') + } else if (![ undefined, SUPPRESS ].includes(argument.metavar)) { + return argument.metavar + } else if (![ undefined, SUPPRESS ].includes(argument.dest)) { + return argument.dest + } else { + return undefined + } +} + + +const ArgumentError = _callable(class ArgumentError extends Error { + /* + * An error from creating or using an argument (optional or positional). + * + * The string value of this exception is the message, augmented with + * information about the argument that caused it. + */ + + constructor(argument, message) { + super() + this.name = 'ArgumentError' + this._argument_name = _get_action_name(argument) + this._message = message + this.message = this.str() + } + + str() { + let format + if (this._argument_name === undefined) { + format = '%(message)s' + } else { + format = 'argument %(argument_name)s: %(message)s' + } + return sub(format, { message: this._message, + argument_name: this._argument_name }) + } +}) + + +const ArgumentTypeError = _callable(class ArgumentTypeError extends Error { + /* + * An error from trying to convert a command line string to a type. + */ + + constructor(message) { + super(message) + this.name = 'ArgumentTypeError' + } +}) + + +// ============== +// Action classes +// ============== +const Action = _camelcase_alias(_callable(class Action extends _AttributeHolder(Function) { + /* + * Information about how to convert command line strings to Python objects. + * + * Action objects are used by an ArgumentParser to represent the information + * needed to parse a single argument from one or more strings from the + * command line. The keyword arguments to the Action constructor are also + * all attributes of Action instances. + * + * Keyword Arguments: + * + * - option_strings -- A list of command-line option strings which + * should be associated with this action. + * + * - dest -- The name of the attribute to hold the created object(s) + * + * - nargs -- The number of command-line arguments that should be + * consumed. By default, one argument will be consumed and a single + * value will be produced. Other values include: + * - N (an integer) consumes N arguments (and produces a list) + * - '?' consumes zero or one arguments + * - '*' consumes zero or more arguments (and produces a list) + * - '+' consumes one or more arguments (and produces a list) + * Note that the difference between the default and nargs=1 is that + * with the default, a single value will be produced, while with + * nargs=1, a list containing a single value will be produced. + * + * - const -- The value to be produced if the option is specified and the + * option uses an action that takes no values. + * + * - default -- The value to be produced if the option is not specified. + * + * - type -- A callable that accepts a single string argument, and + * returns the converted value. The standard Python types str, int, + * float, and complex are useful examples of such callables. If None, + * str is used. + * + * - choices -- A container of values that should be allowed. If not None, + * after a command-line argument has been converted to the appropriate + * type, an exception will be raised if it is not a member of this + * collection. + * + * - required -- True if the action must always be specified at the + * command line. This is only meaningful for optional command-line + * arguments. + * + * - help -- The help string describing the argument. + * + * - metavar -- The name to be used for the option's argument with the + * help string. If None, the 'dest' value will be used as the name. + */ + + constructor() { + let [ + option_strings, + dest, + nargs, + const_value, + default_value, + type, + choices, + required, + help, + metavar + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + nargs: undefined, + const: undefined, + default: undefined, + type: undefined, + choices: undefined, + required: false, + help: undefined, + metavar: undefined + }) + + // when this class is called as a function, redirect it to .call() method of itself + super('return arguments.callee.call.apply(arguments.callee, arguments)') + + this.option_strings = option_strings + this.dest = dest + this.nargs = nargs + this.const = const_value + this.default = default_value + this.type = type + this.choices = choices + this.required = required + this.help = help + this.metavar = metavar + } + + _get_kwargs() { + let names = [ + 'option_strings', + 'dest', + 'nargs', + 'const', + 'default', + 'type', + 'choices', + 'help', + 'metavar' + ] + return names.map(name => [ name, getattr(this, name) ]) + } + + format_usage() { + return this.option_strings[0] + } + + call(/*parser, namespace, values, option_string = undefined*/) { + throw new Error('.call() not defined') + } +})) + + +const BooleanOptionalAction = _camelcase_alias(_callable(class BooleanOptionalAction extends Action { + + constructor() { + let [ + option_strings, + dest, + default_value, + type, + choices, + required, + help, + metavar + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + default: undefined, + type: undefined, + choices: undefined, + required: false, + help: undefined, + metavar: undefined + }) + + let _option_strings = [] + for (let option_string of option_strings) { + _option_strings.push(option_string) + + if (option_string.startsWith('--')) { + option_string = '--no-' + option_string.slice(2) + _option_strings.push(option_string) + } + } + + if (help !== undefined && default_value !== undefined) { + help += ` (default: ${default_value})` + } + + super({ + option_strings: _option_strings, + dest, + nargs: 0, + default: default_value, + type, + choices, + required, + help, + metavar + }) + } + + call(parser, namespace, values, option_string = undefined) { + if (this.option_strings.includes(option_string)) { + setattr(namespace, this.dest, !option_string.startsWith('--no-')) + } + } + + format_usage() { + return this.option_strings.join(' | ') + } +})) + + +const _StoreAction = _callable(class _StoreAction extends Action { + + constructor() { + let [ + option_strings, + dest, + nargs, + const_value, + default_value, + type, + choices, + required, + help, + metavar + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + nargs: undefined, + const: undefined, + default: undefined, + type: undefined, + choices: undefined, + required: false, + help: undefined, + metavar: undefined + }) + + if (nargs === 0) { + throw new TypeError('nargs for store actions must be != 0; if you ' + + 'have nothing to store, actions such as store ' + + 'true or store const may be more appropriate') + } + if (const_value !== undefined && nargs !== OPTIONAL) { + throw new TypeError(sub('nargs must be %r to supply const', OPTIONAL)) + } + super({ + option_strings, + dest, + nargs, + const: const_value, + default: default_value, + type, + choices, + required, + help, + metavar + }) + } + + call(parser, namespace, values/*, option_string = undefined*/) { + setattr(namespace, this.dest, values) + } +}) + + +const _StoreConstAction = _callable(class _StoreConstAction extends Action { + + constructor() { + let [ + option_strings, + dest, + const_value, + default_value, + required, + help + //, metavar + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + const: no_default, + default: undefined, + required: false, + help: undefined, + metavar: undefined + }) + + super({ + option_strings, + dest, + nargs: 0, + const: const_value, + default: default_value, + required, + help + }) + } + + call(parser, namespace/*, values, option_string = undefined*/) { + setattr(namespace, this.dest, this.const) + } +}) + + +const _StoreTrueAction = _callable(class _StoreTrueAction extends _StoreConstAction { + + constructor() { + let [ + option_strings, + dest, + default_value, + required, + help + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + default: false, + required: false, + help: undefined + }) + + super({ + option_strings, + dest, + const: true, + default: default_value, + required, + help + }) + } +}) + + +const _StoreFalseAction = _callable(class _StoreFalseAction extends _StoreConstAction { + + constructor() { + let [ + option_strings, + dest, + default_value, + required, + help + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + default: true, + required: false, + help: undefined + }) + + super({ + option_strings, + dest, + const: false, + default: default_value, + required, + help + }) + } +}) + + +const _AppendAction = _callable(class _AppendAction extends Action { + + constructor() { + let [ + option_strings, + dest, + nargs, + const_value, + default_value, + type, + choices, + required, + help, + metavar + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + nargs: undefined, + const: undefined, + default: undefined, + type: undefined, + choices: undefined, + required: false, + help: undefined, + metavar: undefined + }) + + if (nargs === 0) { + throw new TypeError('nargs for append actions must be != 0; if arg ' + + 'strings are not supplying the value to append, ' + + 'the append const action may be more appropriate') + } + if (const_value !== undefined && nargs !== OPTIONAL) { + throw new TypeError(sub('nargs must be %r to supply const', OPTIONAL)) + } + super({ + option_strings, + dest, + nargs, + const: const_value, + default: default_value, + type, + choices, + required, + help, + metavar + }) + } + + call(parser, namespace, values/*, option_string = undefined*/) { + let items = getattr(namespace, this.dest, undefined) + items = _copy_items(items) + items.push(values) + setattr(namespace, this.dest, items) + } +}) + + +const _AppendConstAction = _callable(class _AppendConstAction extends Action { + + constructor() { + let [ + option_strings, + dest, + const_value, + default_value, + required, + help, + metavar + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + const: no_default, + default: undefined, + required: false, + help: undefined, + metavar: undefined + }) + + super({ + option_strings, + dest, + nargs: 0, + const: const_value, + default: default_value, + required, + help, + metavar + }) + } + + call(parser, namespace/*, values, option_string = undefined*/) { + let items = getattr(namespace, this.dest, undefined) + items = _copy_items(items) + items.push(this.const) + setattr(namespace, this.dest, items) + } +}) + + +const _CountAction = _callable(class _CountAction extends Action { + + constructor() { + let [ + option_strings, + dest, + default_value, + required, + help + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: no_default, + default: undefined, + required: false, + help: undefined + }) + + super({ + option_strings, + dest, + nargs: 0, + default: default_value, + required, + help + }) + } + + call(parser, namespace/*, values, option_string = undefined*/) { + let count = getattr(namespace, this.dest, undefined) + if (count === undefined) { + count = 0 + } + setattr(namespace, this.dest, count + 1) + } +}) + + +const _HelpAction = _callable(class _HelpAction extends Action { + + constructor() { + let [ + option_strings, + dest, + default_value, + help + ] = _parse_opts(arguments, { + option_strings: no_default, + dest: SUPPRESS, + default: SUPPRESS, + help: undefined + }) + + super({ + option_strings, + dest, + default: default_value, + nargs: 0, + help + }) + } + + call(parser/*, namespace, values, option_string = undefined*/) { + parser.print_help() + parser.exit() + } +}) + + +const _VersionAction = _callable(class _VersionAction extends Action { + + constructor() { + let [ + option_strings, + version, + dest, + default_value, + help + ] = _parse_opts(arguments, { + option_strings: no_default, + version: undefined, + dest: SUPPRESS, + default: SUPPRESS, + help: "show program's version number and exit" + }) + + super({ + option_strings, + dest, + default: default_value, + nargs: 0, + help + }) + this.version = version + } + + call(parser/*, namespace, values, option_string = undefined*/) { + let version = this.version + if (version === undefined) { + version = parser.version + } + let formatter = parser._get_formatter() + formatter.add_text(version) + parser._print_message(formatter.format_help(), process.stdout) + parser.exit() + } +}) + + +const _SubParsersAction = _camelcase_alias(_callable(class _SubParsersAction extends Action { + + constructor() { + let [ + option_strings, + prog, + parser_class, + dest, + required, + help, + metavar + ] = _parse_opts(arguments, { + option_strings: no_default, + prog: no_default, + parser_class: no_default, + dest: SUPPRESS, + required: false, + help: undefined, + metavar: undefined + }) + + let name_parser_map = {} + + super({ + option_strings, + dest, + nargs: PARSER, + choices: name_parser_map, + required, + help, + metavar + }) + + this._prog_prefix = prog + this._parser_class = parser_class + this._name_parser_map = name_parser_map + this._choices_actions = [] + } + + add_parser() { + let [ + name, + kwargs + ] = _parse_opts(arguments, { + name: no_default, + '**kwargs': no_default + }) + + // set prog from the existing prefix + if (kwargs.prog === undefined) { + kwargs.prog = sub('%s %s', this._prog_prefix, name) + } + + let aliases = getattr(kwargs, 'aliases', []) + delete kwargs.aliases + + // create a pseudo-action to hold the choice help + if ('help' in kwargs) { + let help = kwargs.help + delete kwargs.help + let choice_action = this._ChoicesPseudoAction(name, aliases, help) + this._choices_actions.push(choice_action) + } + + // create the parser and add it to the map + let parser = new this._parser_class(kwargs) + this._name_parser_map[name] = parser + + // make parser available under aliases also + for (let alias of aliases) { + this._name_parser_map[alias] = parser + } + + return parser + } + + _get_subactions() { + return this._choices_actions + } + + call(parser, namespace, values/*, option_string = undefined*/) { + let parser_name = values[0] + let arg_strings = values.slice(1) + + // set the parser name if requested + if (this.dest !== SUPPRESS) { + setattr(namespace, this.dest, parser_name) + } + + // select the parser + if (hasattr(this._name_parser_map, parser_name)) { + parser = this._name_parser_map[parser_name] + } else { + let args = {parser_name, + choices: this._name_parser_map.join(', ')} + let msg = sub('unknown parser %(parser_name)r (choices: %(choices)s)', args) + throw new ArgumentError(this, msg) + } + + // parse all the remaining options into the namespace + // store any unrecognized options on the object, so that the top + // level parser can decide what to do with them + + // In case this subparser defines new defaults, we parse them + // in a new namespace object and then update the original + // namespace for the relevant parts. + let subnamespace + [ subnamespace, arg_strings ] = parser.parse_known_args(arg_strings, undefined) + for (let [ key, value ] of Object.entries(subnamespace)) { + setattr(namespace, key, value) + } + + if (arg_strings.length) { + setdefault(namespace, _UNRECOGNIZED_ARGS_ATTR, []) + getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).push(...arg_strings) + } + } +})) + + +_SubParsersAction.prototype._ChoicesPseudoAction = _callable(class _ChoicesPseudoAction extends Action { + constructor(name, aliases, help) { + let metavar = name, dest = name + if (aliases.length) { + metavar += sub(' (%s)', aliases.join(', ')) + } + super({ option_strings: [], dest, help, metavar }) + } +}) + + +const _ExtendAction = _callable(class _ExtendAction extends _AppendAction { + call(parser, namespace, values/*, option_string = undefined*/) { + let items = getattr(namespace, this.dest, undefined) + items = _copy_items(items) + items = items.concat(values) + setattr(namespace, this.dest, items) + } +}) + + +// ============== +// Type classes +// ============== +const FileType = _callable(class FileType extends Function { + /* + * Factory for creating file object types + * + * Instances of FileType are typically passed as type= arguments to the + * ArgumentParser add_argument() method. + * + * Keyword Arguments: + * - mode -- A string indicating how the file is to be opened. Accepts the + * same values as the builtin open() function. + * - bufsize -- The file's desired buffer size. Accepts the same values as + * the builtin open() function. + * - encoding -- The file's encoding. Accepts the same values as the + * builtin open() function. + * - errors -- A string indicating how encoding and decoding errors are to + * be handled. Accepts the same value as the builtin open() function. + */ + + constructor() { + let [ + flags, + encoding, + mode, + autoClose, + emitClose, + start, + end, + highWaterMark, + fs + ] = _parse_opts(arguments, { + flags: 'r', + encoding: undefined, + mode: undefined, // 0o666 + autoClose: undefined, // true + emitClose: undefined, // false + start: undefined, // 0 + end: undefined, // Infinity + highWaterMark: undefined, // 64 * 1024 + fs: undefined + }) + + // when this class is called as a function, redirect it to .call() method of itself + super('return arguments.callee.call.apply(arguments.callee, arguments)') + + Object.defineProperty(this, 'name', { + get() { + return sub('FileType(%r)', flags) + } + }) + this._flags = flags + this._options = {} + if (encoding !== undefined) this._options.encoding = encoding + if (mode !== undefined) this._options.mode = mode + if (autoClose !== undefined) this._options.autoClose = autoClose + if (emitClose !== undefined) this._options.emitClose = emitClose + if (start !== undefined) this._options.start = start + if (end !== undefined) this._options.end = end + if (highWaterMark !== undefined) this._options.highWaterMark = highWaterMark + if (fs !== undefined) this._options.fs = fs + } + + call(string) { + // the special argument "-" means sys.std{in,out} + if (string === '-') { + if (this._flags.includes('r')) { + return process.stdin + } else if (this._flags.includes('w')) { + return process.stdout + } else { + let msg = sub('argument "-" with mode %r', this._flags) + throw new TypeError(msg) + } + } + + // all other arguments are used as file names + let fd + try { + fd = fs.openSync(string, this._flags, this._options.mode) + } catch (e) { + let args = { filename: string, error: e.message } + let message = "can't open '%(filename)s': %(error)s" + throw new ArgumentTypeError(sub(message, args)) + } + + let options = Object.assign({ fd, flags: this._flags }, this._options) + if (this._flags.includes('r')) { + return fs.createReadStream(undefined, options) + } else if (this._flags.includes('w')) { + return fs.createWriteStream(undefined, options) + } else { + let msg = sub('argument "%s" with mode %r', string, this._flags) + throw new TypeError(msg) + } + } + + [util.inspect.custom]() { + let args = [ this._flags ] + let kwargs = Object.entries(this._options).map(([ k, v ]) => { + if (k === 'mode') v = { value: v, [util.inspect.custom]() { return '0o' + this.value.toString(8) } } + return [ k, v ] + }) + let args_str = [] + .concat(args.filter(arg => arg !== -1).map(repr)) + .concat(kwargs.filter(([/*kw*/, arg]) => arg !== undefined) + .map(([kw, arg]) => sub('%s=%r', kw, arg))) + .join(', ') + return sub('%s(%s)', this.constructor.name, args_str) + } + + toString() { + return this[util.inspect.custom]() + } +}) + +// =========================== +// Optional and Positional Parsing +// =========================== +const Namespace = _callable(class Namespace extends _AttributeHolder() { + /* + * Simple object for storing attributes. + * + * Implements equality by attribute names and values, and provides a simple + * string representation. + */ + + constructor(options = {}) { + super() + Object.assign(this, options) + } +}) + +// unset string tag to mimic plain object +Namespace.prototype[Symbol.toStringTag] = undefined + + +const _ActionsContainer = _camelcase_alias(_callable(class _ActionsContainer { + + constructor() { + let [ + description, + prefix_chars, + argument_default, + conflict_handler + ] = _parse_opts(arguments, { + description: no_default, + prefix_chars: no_default, + argument_default: no_default, + conflict_handler: no_default + }) + + this.description = description + this.argument_default = argument_default + this.prefix_chars = prefix_chars + this.conflict_handler = conflict_handler + + // set up registries + this._registries = {} + + // register actions + this.register('action', undefined, _StoreAction) + this.register('action', 'store', _StoreAction) + this.register('action', 'store_const', _StoreConstAction) + this.register('action', 'store_true', _StoreTrueAction) + this.register('action', 'store_false', _StoreFalseAction) + this.register('action', 'append', _AppendAction) + this.register('action', 'append_const', _AppendConstAction) + this.register('action', 'count', _CountAction) + this.register('action', 'help', _HelpAction) + this.register('action', 'version', _VersionAction) + this.register('action', 'parsers', _SubParsersAction) + this.register('action', 'extend', _ExtendAction) + // LEGACY (v1 compatibility): camelcase variants + ;[ 'storeConst', 'storeTrue', 'storeFalse', 'appendConst' ].forEach(old_name => { + let new_name = _to_new_name(old_name) + this.register('action', old_name, util.deprecate(this._registry_get('action', new_name), + sub('{action: "%s"} is renamed to {action: "%s"}', old_name, new_name))) + }) + // end + + // raise an exception if the conflict handler is invalid + this._get_handler() + + // action storage + this._actions = [] + this._option_string_actions = {} + + // groups + this._action_groups = [] + this._mutually_exclusive_groups = [] + + // defaults storage + this._defaults = {} + + // determines whether an "option" looks like a negative number + this._negative_number_matcher = /^-\d+$|^-\d*\.\d+$/ + + // whether or not there are any optionals that look like negative + // numbers -- uses a list so it can be shared and edited + this._has_negative_number_optionals = [] + } + + // ==================== + // Registration methods + // ==================== + register(registry_name, value, object) { + let registry = setdefault(this._registries, registry_name, {}) + registry[value] = object + } + + _registry_get(registry_name, value, default_value = undefined) { + return getattr(this._registries[registry_name], value, default_value) + } + + // ================================== + // Namespace default accessor methods + // ================================== + set_defaults(kwargs) { + Object.assign(this._defaults, kwargs) + + // if these defaults match any existing arguments, replace + // the previous default on the object with the new one + for (let action of this._actions) { + if (action.dest in kwargs) { + action.default = kwargs[action.dest] + } + } + } + + get_default(dest) { + for (let action of this._actions) { + if (action.dest === dest && action.default !== undefined) { + return action.default + } + } + return this._defaults[dest] + } + + + // ======================= + // Adding argument actions + // ======================= + add_argument() { + /* + * add_argument(dest, ..., name=value, ...) + * add_argument(option_string, option_string, ..., name=value, ...) + */ + let [ + args, + kwargs + ] = _parse_opts(arguments, { + '*args': no_default, + '**kwargs': no_default + }) + // LEGACY (v1 compatibility), old-style add_argument([ args ], { options }) + if (args.length === 1 && Array.isArray(args[0])) { + args = args[0] + deprecate('argument-array', + sub('use add_argument(%(args)s, {...}) instead of add_argument([ %(args)s ], { ... })', { + args: args.map(repr).join(', ') + })) + } + // end + + // if no positional args are supplied or only one is supplied and + // it doesn't look like an option string, parse a positional + // argument + let chars = this.prefix_chars + if (!args.length || args.length === 1 && !chars.includes(args[0][0])) { + if (args.length && 'dest' in kwargs) { + throw new TypeError('dest supplied twice for positional argument') + } + kwargs = this._get_positional_kwargs(...args, kwargs) + + // otherwise, we're adding an optional argument + } else { + kwargs = this._get_optional_kwargs(...args, kwargs) + } + + // if no default was supplied, use the parser-level default + if (!('default' in kwargs)) { + let dest = kwargs.dest + if (dest in this._defaults) { + kwargs.default = this._defaults[dest] + } else if (this.argument_default !== undefined) { + kwargs.default = this.argument_default + } + } + + // create the action object, and add it to the parser + let action_class = this._pop_action_class(kwargs) + if (typeof action_class !== 'function') { + throw new TypeError(sub('unknown action "%s"', action_class)) + } + // eslint-disable-next-line new-cap + let action = new action_class(kwargs) + + // raise an error if the action type is not callable + let type_func = this._registry_get('type', action.type, action.type) + if (typeof type_func !== 'function') { + throw new TypeError(sub('%r is not callable', type_func)) + } + + if (type_func === FileType) { + throw new TypeError(sub('%r is a FileType class object, instance of it' + + ' must be passed', type_func)) + } + + // raise an error if the metavar does not match the type + if ('_get_formatter' in this) { + try { + this._get_formatter()._format_args(action, undefined) + } catch (err) { + // check for 'invalid nargs value' is an artifact of TypeError and ValueError in js being the same + if (err instanceof TypeError && err.message !== 'invalid nargs value') { + throw new TypeError('length of metavar tuple does not match nargs') + } else { + throw err + } + } + } + + return this._add_action(action) + } + + add_argument_group() { + let group = _ArgumentGroup(this, ...arguments) + this._action_groups.push(group) + return group + } + + add_mutually_exclusive_group() { + // eslint-disable-next-line no-use-before-define + let group = _MutuallyExclusiveGroup(this, ...arguments) + this._mutually_exclusive_groups.push(group) + return group + } + + _add_action(action) { + // resolve any conflicts + this._check_conflict(action) + + // add to actions list + this._actions.push(action) + action.container = this + + // index the action by any option strings it has + for (let option_string of action.option_strings) { + this._option_string_actions[option_string] = action + } + + // set the flag if any option strings look like negative numbers + for (let option_string of action.option_strings) { + if (this._negative_number_matcher.test(option_string)) { + if (!this._has_negative_number_optionals.length) { + this._has_negative_number_optionals.push(true) + } + } + } + + // return the created action + return action + } + + _remove_action(action) { + _array_remove(this._actions, action) + } + + _add_container_actions(container) { + // collect groups by titles + let title_group_map = {} + for (let group of this._action_groups) { + if (group.title in title_group_map) { + let msg = 'cannot merge actions - two groups are named %r' + throw new TypeError(sub(msg, group.title)) + } + title_group_map[group.title] = group + } + + // map each action to its group + let group_map = new Map() + for (let group of container._action_groups) { + + // if a group with the title exists, use that, otherwise + // create a new group matching the container's group + if (!(group.title in title_group_map)) { + title_group_map[group.title] = this.add_argument_group({ + title: group.title, + description: group.description, + conflict_handler: group.conflict_handler + }) + } + + // map the actions to their new group + for (let action of group._group_actions) { + group_map.set(action, title_group_map[group.title]) + } + } + + // add container's mutually exclusive groups + // NOTE: if add_mutually_exclusive_group ever gains title= and + // description= then this code will need to be expanded as above + for (let group of container._mutually_exclusive_groups) { + let mutex_group = this.add_mutually_exclusive_group({ + required: group.required + }) + + // map the actions to their new mutex group + for (let action of group._group_actions) { + group_map.set(action, mutex_group) + } + } + + // add all actions to this container or their group + for (let action of container._actions) { + group_map.get(action)._add_action(action) + } + } + + _get_positional_kwargs() { + let [ + dest, + kwargs + ] = _parse_opts(arguments, { + dest: no_default, + '**kwargs': no_default + }) + + // make sure required is not specified + if ('required' in kwargs) { + let msg = "'required' is an invalid argument for positionals" + throw new TypeError(msg) + } + + // mark positional arguments as required if at least one is + // always required + if (![OPTIONAL, ZERO_OR_MORE].includes(kwargs.nargs)) { + kwargs.required = true + } + if (kwargs.nargs === ZERO_OR_MORE && !('default' in kwargs)) { + kwargs.required = true + } + + // return the keyword arguments with no option strings + return Object.assign(kwargs, { dest, option_strings: [] }) + } + + _get_optional_kwargs() { + let [ + args, + kwargs + ] = _parse_opts(arguments, { + '*args': no_default, + '**kwargs': no_default + }) + + // determine short and long option strings + let option_strings = [] + let long_option_strings = [] + let option_string + for (option_string of args) { + // error on strings that don't start with an appropriate prefix + if (!this.prefix_chars.includes(option_string[0])) { + let args = {option: option_string, + prefix_chars: this.prefix_chars} + let msg = 'invalid option string %(option)r: ' + + 'must start with a character %(prefix_chars)r' + throw new TypeError(sub(msg, args)) + } + + // strings starting with two prefix characters are long options + option_strings.push(option_string) + if (option_string.length > 1 && this.prefix_chars.includes(option_string[1])) { + long_option_strings.push(option_string) + } + } + + // infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x' + let dest = kwargs.dest + delete kwargs.dest + if (dest === undefined) { + let dest_option_string + if (long_option_strings.length) { + dest_option_string = long_option_strings[0] + } else { + dest_option_string = option_strings[0] + } + dest = _string_lstrip(dest_option_string, this.prefix_chars) + if (!dest) { + let msg = 'dest= is required for options like %r' + throw new TypeError(sub(msg, option_string)) + } + dest = dest.replace(/-/g, '_') + } + + // return the updated keyword arguments + return Object.assign(kwargs, { dest, option_strings }) + } + + _pop_action_class(kwargs, default_value = undefined) { + let action = getattr(kwargs, 'action', default_value) + delete kwargs.action + return this._registry_get('action', action, action) + } + + _get_handler() { + // determine function from conflict handler string + let handler_func_name = sub('_handle_conflict_%s', this.conflict_handler) + if (typeof this[handler_func_name] === 'function') { + return this[handler_func_name] + } else { + let msg = 'invalid conflict_resolution value: %r' + throw new TypeError(sub(msg, this.conflict_handler)) + } + } + + _check_conflict(action) { + + // find all options that conflict with this option + let confl_optionals = [] + for (let option_string of action.option_strings) { + if (hasattr(this._option_string_actions, option_string)) { + let confl_optional = this._option_string_actions[option_string] + confl_optionals.push([ option_string, confl_optional ]) + } + } + + // resolve any conflicts + if (confl_optionals.length) { + let conflict_handler = this._get_handler() + conflict_handler.call(this, action, confl_optionals) + } + } + + _handle_conflict_error(action, conflicting_actions) { + let message = conflicting_actions.length === 1 ? + 'conflicting option string: %s' : + 'conflicting option strings: %s' + let conflict_string = conflicting_actions.map(([ option_string/*, action*/ ]) => option_string).join(', ') + throw new ArgumentError(action, sub(message, conflict_string)) + } + + _handle_conflict_resolve(action, conflicting_actions) { + + // remove all conflicting options + for (let [ option_string, action ] of conflicting_actions) { + + // remove the conflicting option + _array_remove(action.option_strings, option_string) + delete this._option_string_actions[option_string] + + // if the option now has no option string, remove it from the + // container holding it + if (!action.option_strings.length) { + action.container._remove_action(action) + } + } + } +})) + + +const _ArgumentGroup = _callable(class _ArgumentGroup extends _ActionsContainer { + + constructor() { + let [ + container, + title, + description, + kwargs + ] = _parse_opts(arguments, { + container: no_default, + title: undefined, + description: undefined, + '**kwargs': no_default + }) + + // add any missing keyword arguments by checking the container + setdefault(kwargs, 'conflict_handler', container.conflict_handler) + setdefault(kwargs, 'prefix_chars', container.prefix_chars) + setdefault(kwargs, 'argument_default', container.argument_default) + super(Object.assign({ description }, kwargs)) + + // group attributes + this.title = title + this._group_actions = [] + + // share most attributes with the container + this._registries = container._registries + this._actions = container._actions + this._option_string_actions = container._option_string_actions + this._defaults = container._defaults + this._has_negative_number_optionals = + container._has_negative_number_optionals + this._mutually_exclusive_groups = container._mutually_exclusive_groups + } + + _add_action(action) { + action = super._add_action(action) + this._group_actions.push(action) + return action + } + + _remove_action(action) { + super._remove_action(action) + _array_remove(this._group_actions, action) + } +}) + + +const _MutuallyExclusiveGroup = _callable(class _MutuallyExclusiveGroup extends _ArgumentGroup { + + constructor() { + let [ + container, + required + ] = _parse_opts(arguments, { + container: no_default, + required: false + }) + + super(container) + this.required = required + this._container = container + } + + _add_action(action) { + if (action.required) { + let msg = 'mutually exclusive arguments must be optional' + throw new TypeError(msg) + } + action = this._container._add_action(action) + this._group_actions.push(action) + return action + } + + _remove_action(action) { + this._container._remove_action(action) + _array_remove(this._group_actions, action) + } +}) + + +const ArgumentParser = _camelcase_alias(_callable(class ArgumentParser extends _AttributeHolder(_ActionsContainer) { + /* + * Object for parsing command line strings into Python objects. + * + * Keyword Arguments: + * - prog -- The name of the program (default: sys.argv[0]) + * - usage -- A usage message (default: auto-generated from arguments) + * - description -- A description of what the program does + * - epilog -- Text following the argument descriptions + * - parents -- Parsers whose arguments should be copied into this one + * - formatter_class -- HelpFormatter class for printing help messages + * - prefix_chars -- Characters that prefix optional arguments + * - fromfile_prefix_chars -- Characters that prefix files containing + * additional arguments + * - argument_default -- The default value for all arguments + * - conflict_handler -- String indicating how to handle conflicts + * - add_help -- Add a -h/-help option + * - allow_abbrev -- Allow long options to be abbreviated unambiguously + * - exit_on_error -- Determines whether or not ArgumentParser exits with + * error info when an error occurs + */ + + constructor() { + let [ + prog, + usage, + description, + epilog, + parents, + formatter_class, + prefix_chars, + fromfile_prefix_chars, + argument_default, + conflict_handler, + add_help, + allow_abbrev, + exit_on_error, + debug, // LEGACY (v1 compatibility), debug mode + version // LEGACY (v1 compatibility), version + ] = _parse_opts(arguments, { + prog: undefined, + usage: undefined, + description: undefined, + epilog: undefined, + parents: [], + formatter_class: HelpFormatter, + prefix_chars: '-', + fromfile_prefix_chars: undefined, + argument_default: undefined, + conflict_handler: 'error', + add_help: true, + allow_abbrev: true, + exit_on_error: true, + debug: undefined, // LEGACY (v1 compatibility), debug mode + version: undefined // LEGACY (v1 compatibility), version + }) + + // LEGACY (v1 compatibility) + if (debug !== undefined) { + deprecate('debug', + 'The "debug" argument to ArgumentParser is deprecated. Please ' + + 'override ArgumentParser.exit function instead.' + ) + } + + if (version !== undefined) { + deprecate('version', + 'The "version" argument to ArgumentParser is deprecated. Please use ' + + "add_argument(..., { action: 'version', version: 'N', ... }) instead." + ) + } + // end + + super({ + description, + prefix_chars, + argument_default, + conflict_handler + }) + + // default setting for prog + if (prog === undefined) { + prog = path.basename(get_argv()[0] || '') + } + + this.prog = prog + this.usage = usage + this.epilog = epilog + this.formatter_class = formatter_class + this.fromfile_prefix_chars = fromfile_prefix_chars + this.add_help = add_help + this.allow_abbrev = allow_abbrev + this.exit_on_error = exit_on_error + // LEGACY (v1 compatibility), debug mode + this.debug = debug + // end + + this._positionals = this.add_argument_group('positional arguments') + this._optionals = this.add_argument_group('optional arguments') + this._subparsers = undefined + + // register types + function identity(string) { + return string + } + this.register('type', undefined, identity) + this.register('type', null, identity) + this.register('type', 'auto', identity) + this.register('type', 'int', function (x) { + let result = Number(x) + if (!Number.isInteger(result)) { + throw new TypeError(sub('could not convert string to int: %r', x)) + } + return result + }) + this.register('type', 'float', function (x) { + let result = Number(x) + if (isNaN(result)) { + throw new TypeError(sub('could not convert string to float: %r', x)) + } + return result + }) + this.register('type', 'str', String) + // LEGACY (v1 compatibility): custom types + this.register('type', 'string', + util.deprecate(String, 'use {type:"str"} or {type:String} instead of {type:"string"}')) + // end + + // add help argument if necessary + // (using explicit default to override global argument_default) + let default_prefix = prefix_chars.includes('-') ? '-' : prefix_chars[0] + if (this.add_help) { + this.add_argument( + default_prefix + 'h', + default_prefix.repeat(2) + 'help', + { + action: 'help', + default: SUPPRESS, + help: 'show this help message and exit' + } + ) + } + // LEGACY (v1 compatibility), version + if (version) { + this.add_argument( + default_prefix + 'v', + default_prefix.repeat(2) + 'version', + { + action: 'version', + default: SUPPRESS, + version: this.version, + help: "show program's version number and exit" + } + ) + } + // end + + // add parent arguments and defaults + for (let parent of parents) { + this._add_container_actions(parent) + Object.assign(this._defaults, parent._defaults) + } + } + + // ======================= + // Pretty __repr__ methods + // ======================= + _get_kwargs() { + let names = [ + 'prog', + 'usage', + 'description', + 'formatter_class', + 'conflict_handler', + 'add_help' + ] + return names.map(name => [ name, getattr(this, name) ]) + } + + // ================================== + // Optional/Positional adding methods + // ================================== + add_subparsers() { + let [ + kwargs + ] = _parse_opts(arguments, { + '**kwargs': no_default + }) + + if (this._subparsers !== undefined) { + this.error('cannot have multiple subparser arguments') + } + + // add the parser class to the arguments if it's not present + setdefault(kwargs, 'parser_class', this.constructor) + + if ('title' in kwargs || 'description' in kwargs) { + let title = getattr(kwargs, 'title', 'subcommands') + let description = getattr(kwargs, 'description', undefined) + delete kwargs.title + delete kwargs.description + this._subparsers = this.add_argument_group(title, description) + } else { + this._subparsers = this._positionals + } + + // prog defaults to the usage message of this parser, skipping + // optional arguments and with no "usage:" prefix + if (kwargs.prog === undefined) { + let formatter = this._get_formatter() + let positionals = this._get_positional_actions() + let groups = this._mutually_exclusive_groups + formatter.add_usage(this.usage, positionals, groups, '') + kwargs.prog = formatter.format_help().trim() + } + + // create the parsers action and add it to the positionals list + let parsers_class = this._pop_action_class(kwargs, 'parsers') + // eslint-disable-next-line new-cap + let action = new parsers_class(Object.assign({ option_strings: [] }, kwargs)) + this._subparsers._add_action(action) + + // return the created parsers action + return action + } + + _add_action(action) { + if (action.option_strings.length) { + this._optionals._add_action(action) + } else { + this._positionals._add_action(action) + } + return action + } + + _get_optional_actions() { + return this._actions.filter(action => action.option_strings.length) + } + + _get_positional_actions() { + return this._actions.filter(action => !action.option_strings.length) + } + + // ===================================== + // Command line argument parsing methods + // ===================================== + parse_args(args = undefined, namespace = undefined) { + let argv + [ args, argv ] = this.parse_known_args(args, namespace) + if (argv && argv.length > 0) { + let msg = 'unrecognized arguments: %s' + this.error(sub(msg, argv.join(' '))) + } + return args + } + + parse_known_args(args = undefined, namespace = undefined) { + if (args === undefined) { + args = get_argv().slice(1) + } + + // default Namespace built from parser defaults + if (namespace === undefined) { + namespace = new Namespace() + } + + // add any action defaults that aren't present + for (let action of this._actions) { + if (action.dest !== SUPPRESS) { + if (!hasattr(namespace, action.dest)) { + if (action.default !== SUPPRESS) { + setattr(namespace, action.dest, action.default) + } + } + } + } + + // add any parser defaults that aren't present + for (let dest of Object.keys(this._defaults)) { + if (!hasattr(namespace, dest)) { + setattr(namespace, dest, this._defaults[dest]) + } + } + + // parse the arguments and exit if there are any errors + if (this.exit_on_error) { + try { + [ namespace, args ] = this._parse_known_args(args, namespace) + } catch (err) { + if (err instanceof ArgumentError) { + this.error(err.message) + } else { + throw err + } + } + } else { + [ namespace, args ] = this._parse_known_args(args, namespace) + } + + if (hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR)) { + args = args.concat(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR)) + delattr(namespace, _UNRECOGNIZED_ARGS_ATTR) + } + + return [ namespace, args ] + } + + _parse_known_args(arg_strings, namespace) { + // replace arg strings that are file references + if (this.fromfile_prefix_chars !== undefined) { + arg_strings = this._read_args_from_files(arg_strings) + } + + // map all mutually exclusive arguments to the other arguments + // they can't occur with + let action_conflicts = new Map() + for (let mutex_group of this._mutually_exclusive_groups) { + let group_actions = mutex_group._group_actions + for (let [ i, mutex_action ] of Object.entries(mutex_group._group_actions)) { + let conflicts = action_conflicts.get(mutex_action) || [] + conflicts = conflicts.concat(group_actions.slice(0, +i)) + conflicts = conflicts.concat(group_actions.slice(+i + 1)) + action_conflicts.set(mutex_action, conflicts) + } + } + + // find all option indices, and determine the arg_string_pattern + // which has an 'O' if there is an option at an index, + // an 'A' if there is an argument, or a '-' if there is a '--' + let option_string_indices = {} + let arg_string_pattern_parts = [] + let arg_strings_iter = Object.entries(arg_strings)[Symbol.iterator]() + for (let [ i, arg_string ] of arg_strings_iter) { + + // all args after -- are non-options + if (arg_string === '--') { + arg_string_pattern_parts.push('-') + for ([ i, arg_string ] of arg_strings_iter) { + arg_string_pattern_parts.push('A') + } + + // otherwise, add the arg to the arg strings + // and note the index if it was an option + } else { + let option_tuple = this._parse_optional(arg_string) + let pattern + if (option_tuple === undefined) { + pattern = 'A' + } else { + option_string_indices[i] = option_tuple + pattern = 'O' + } + arg_string_pattern_parts.push(pattern) + } + } + + // join the pieces together to form the pattern + let arg_strings_pattern = arg_string_pattern_parts.join('') + + // converts arg strings to the appropriate and then takes the action + let seen_actions = new Set() + let seen_non_default_actions = new Set() + let extras + + let take_action = (action, argument_strings, option_string = undefined) => { + seen_actions.add(action) + let argument_values = this._get_values(action, argument_strings) + + // error if this argument is not allowed with other previously + // seen arguments, assuming that actions that use the default + // value don't really count as "present" + if (argument_values !== action.default) { + seen_non_default_actions.add(action) + for (let conflict_action of action_conflicts.get(action) || []) { + if (seen_non_default_actions.has(conflict_action)) { + let msg = 'not allowed with argument %s' + let action_name = _get_action_name(conflict_action) + throw new ArgumentError(action, sub(msg, action_name)) + } + } + } + + // take the action if we didn't receive a SUPPRESS value + // (e.g. from a default) + if (argument_values !== SUPPRESS) { + action(this, namespace, argument_values, option_string) + } + } + + // function to convert arg_strings into an optional action + let consume_optional = start_index => { + + // get the optional identified at this index + let option_tuple = option_string_indices[start_index] + let [ action, option_string, explicit_arg ] = option_tuple + + // identify additional optionals in the same arg string + // (e.g. -xyz is the same as -x -y -z if no args are required) + let action_tuples = [] + let stop + for (;;) { + + // if we found no optional action, skip it + if (action === undefined) { + extras.push(arg_strings[start_index]) + return start_index + 1 + } + + // if there is an explicit argument, try to match the + // optional's string arguments to only this + if (explicit_arg !== undefined) { + let arg_count = this._match_argument(action, 'A') + + // if the action is a single-dash option and takes no + // arguments, try to parse more single-dash options out + // of the tail of the option string + let chars = this.prefix_chars + if (arg_count === 0 && !chars.includes(option_string[1])) { + action_tuples.push([ action, [], option_string ]) + let char = option_string[0] + option_string = char + explicit_arg[0] + let new_explicit_arg = explicit_arg.slice(1) || undefined + let optionals_map = this._option_string_actions + if (hasattr(optionals_map, option_string)) { + action = optionals_map[option_string] + explicit_arg = new_explicit_arg + } else { + let msg = 'ignored explicit argument %r' + throw new ArgumentError(action, sub(msg, explicit_arg)) + } + + // if the action expect exactly one argument, we've + // successfully matched the option; exit the loop + } else if (arg_count === 1) { + stop = start_index + 1 + let args = [ explicit_arg ] + action_tuples.push([ action, args, option_string ]) + break + + // error if a double-dash option did not use the + // explicit argument + } else { + let msg = 'ignored explicit argument %r' + throw new ArgumentError(action, sub(msg, explicit_arg)) + } + + // if there is no explicit argument, try to match the + // optional's string arguments with the following strings + // if successful, exit the loop + } else { + let start = start_index + 1 + let selected_patterns = arg_strings_pattern.slice(start) + let arg_count = this._match_argument(action, selected_patterns) + stop = start + arg_count + let args = arg_strings.slice(start, stop) + action_tuples.push([ action, args, option_string ]) + break + } + } + + // add the Optional to the list and return the index at which + // the Optional's string args stopped + assert(action_tuples.length) + for (let [ action, args, option_string ] of action_tuples) { + take_action(action, args, option_string) + } + return stop + } + + // the list of Positionals left to be parsed; this is modified + // by consume_positionals() + let positionals = this._get_positional_actions() + + // function to convert arg_strings into positional actions + let consume_positionals = start_index => { + // match as many Positionals as possible + let selected_pattern = arg_strings_pattern.slice(start_index) + let arg_counts = this._match_arguments_partial(positionals, selected_pattern) + + // slice off the appropriate arg strings for each Positional + // and add the Positional and its args to the list + for (let i = 0; i < positionals.length && i < arg_counts.length; i++) { + let action = positionals[i] + let arg_count = arg_counts[i] + let args = arg_strings.slice(start_index, start_index + arg_count) + start_index += arg_count + take_action(action, args) + } + + // slice off the Positionals that we just parsed and return the + // index at which the Positionals' string args stopped + positionals = positionals.slice(arg_counts.length) + return start_index + } + + // consume Positionals and Optionals alternately, until we have + // passed the last option string + extras = [] + let start_index = 0 + let max_option_string_index = Math.max(-1, ...Object.keys(option_string_indices).map(Number)) + while (start_index <= max_option_string_index) { + + // consume any Positionals preceding the next option + let next_option_string_index = Math.min( + // eslint-disable-next-line no-loop-func + ...Object.keys(option_string_indices).map(Number).filter(index => index >= start_index) + ) + if (start_index !== next_option_string_index) { + let positionals_end_index = consume_positionals(start_index) + + // only try to parse the next optional if we didn't consume + // the option string during the positionals parsing + if (positionals_end_index > start_index) { + start_index = positionals_end_index + continue + } else { + start_index = positionals_end_index + } + } + + // if we consumed all the positionals we could and we're not + // at the index of an option string, there were extra arguments + if (!(start_index in option_string_indices)) { + let strings = arg_strings.slice(start_index, next_option_string_index) + extras = extras.concat(strings) + start_index = next_option_string_index + } + + // consume the next optional and any arguments for it + start_index = consume_optional(start_index) + } + + // consume any positionals following the last Optional + let stop_index = consume_positionals(start_index) + + // if we didn't consume all the argument strings, there were extras + extras = extras.concat(arg_strings.slice(stop_index)) + + // make sure all required actions were present and also convert + // action defaults which were not given as arguments + let required_actions = [] + for (let action of this._actions) { + if (!seen_actions.has(action)) { + if (action.required) { + required_actions.push(_get_action_name(action)) + } else { + // Convert action default now instead of doing it before + // parsing arguments to avoid calling convert functions + // twice (which may fail) if the argument was given, but + // only if it was defined already in the namespace + if (action.default !== undefined && + typeof action.default === 'string' && + hasattr(namespace, action.dest) && + action.default === getattr(namespace, action.dest)) { + setattr(namespace, action.dest, + this._get_value(action, action.default)) + } + } + } + } + + if (required_actions.length) { + this.error(sub('the following arguments are required: %s', + required_actions.join(', '))) + } + + // make sure all required groups had one option present + for (let group of this._mutually_exclusive_groups) { + if (group.required) { + let no_actions_used = true + for (let action of group._group_actions) { + if (seen_non_default_actions.has(action)) { + no_actions_used = false + break + } + } + + // if no actions were used, report the error + if (no_actions_used) { + let names = group._group_actions + .filter(action => action.help !== SUPPRESS) + .map(action => _get_action_name(action)) + let msg = 'one of the arguments %s is required' + this.error(sub(msg, names.join(' '))) + } + } + } + + // return the updated namespace and the extra arguments + return [ namespace, extras ] + } + + _read_args_from_files(arg_strings) { + // expand arguments referencing files + let new_arg_strings = [] + for (let arg_string of arg_strings) { + + // for regular arguments, just add them back into the list + if (!arg_string || !this.fromfile_prefix_chars.includes(arg_string[0])) { + new_arg_strings.push(arg_string) + + // replace arguments referencing files with the file content + } else { + try { + let args_file = fs.readFileSync(arg_string.slice(1), 'utf8') + let arg_strings = [] + for (let arg_line of splitlines(args_file)) { + for (let arg of this.convert_arg_line_to_args(arg_line)) { + arg_strings.push(arg) + } + } + arg_strings = this._read_args_from_files(arg_strings) + new_arg_strings = new_arg_strings.concat(arg_strings) + } catch (err) { + this.error(err.message) + } + } + } + + // return the modified argument list + return new_arg_strings + } + + convert_arg_line_to_args(arg_line) { + return [arg_line] + } + + _match_argument(action, arg_strings_pattern) { + // match the pattern for this action to the arg strings + let nargs_pattern = this._get_nargs_pattern(action) + let match = arg_strings_pattern.match(new RegExp('^' + nargs_pattern)) + + // raise an exception if we weren't able to find a match + if (match === null) { + let nargs_errors = { + undefined: 'expected one argument', + [OPTIONAL]: 'expected at most one argument', + [ONE_OR_MORE]: 'expected at least one argument' + } + let msg = nargs_errors[action.nargs] + if (msg === undefined) { + msg = sub(action.nargs === 1 ? 'expected %s argument' : 'expected %s arguments', action.nargs) + } + throw new ArgumentError(action, msg) + } + + // return the number of arguments matched + return match[1].length + } + + _match_arguments_partial(actions, arg_strings_pattern) { + // progressively shorten the actions list by slicing off the + // final actions until we find a match + let result = [] + for (let i of range(actions.length, 0, -1)) { + let actions_slice = actions.slice(0, i) + let pattern = actions_slice.map(action => this._get_nargs_pattern(action)).join('') + let match = arg_strings_pattern.match(new RegExp('^' + pattern)) + if (match !== null) { + result = result.concat(match.slice(1).map(string => string.length)) + break + } + } + + // return the list of arg string counts + return result + } + + _parse_optional(arg_string) { + // if it's an empty string, it was meant to be a positional + if (!arg_string) { + return undefined + } + + // if it doesn't start with a prefix, it was meant to be positional + if (!this.prefix_chars.includes(arg_string[0])) { + return undefined + } + + // if the option string is present in the parser, return the action + if (arg_string in this._option_string_actions) { + let action = this._option_string_actions[arg_string] + return [ action, arg_string, undefined ] + } + + // if it's just a single character, it was meant to be positional + if (arg_string.length === 1) { + return undefined + } + + // if the option string before the "=" is present, return the action + if (arg_string.includes('=')) { + let [ option_string, explicit_arg ] = _string_split(arg_string, '=', 1) + if (option_string in this._option_string_actions) { + let action = this._option_string_actions[option_string] + return [ action, option_string, explicit_arg ] + } + } + + // search through all possible prefixes of the option string + // and all actions in the parser for possible interpretations + let option_tuples = this._get_option_tuples(arg_string) + + // if multiple actions match, the option string was ambiguous + if (option_tuples.length > 1) { + let options = option_tuples.map(([ /*action*/, option_string/*, explicit_arg*/ ]) => option_string).join(', ') + let args = {option: arg_string, matches: options} + let msg = 'ambiguous option: %(option)s could match %(matches)s' + this.error(sub(msg, args)) + + // if exactly one action matched, this segmentation is good, + // so return the parsed action + } else if (option_tuples.length === 1) { + let [ option_tuple ] = option_tuples + return option_tuple + } + + // if it was not found as an option, but it looks like a negative + // number, it was meant to be positional + // unless there are negative-number-like options + if (this._negative_number_matcher.test(arg_string)) { + if (!this._has_negative_number_optionals.length) { + return undefined + } + } + + // if it contains a space, it was meant to be a positional + if (arg_string.includes(' ')) { + return undefined + } + + // it was meant to be an optional but there is no such option + // in this parser (though it might be a valid option in a subparser) + return [ undefined, arg_string, undefined ] + } + + _get_option_tuples(option_string) { + let result = [] + + // option strings starting with two prefix characters are only + // split at the '=' + let chars = this.prefix_chars + if (chars.includes(option_string[0]) && chars.includes(option_string[1])) { + if (this.allow_abbrev) { + let option_prefix, explicit_arg + if (option_string.includes('=')) { + [ option_prefix, explicit_arg ] = _string_split(option_string, '=', 1) + } else { + option_prefix = option_string + explicit_arg = undefined + } + for (let option_string of Object.keys(this._option_string_actions)) { + if (option_string.startsWith(option_prefix)) { + let action = this._option_string_actions[option_string] + let tup = [ action, option_string, explicit_arg ] + result.push(tup) + } + } + } + + // single character options can be concatenated with their arguments + // but multiple character options always have to have their argument + // separate + } else if (chars.includes(option_string[0]) && !chars.includes(option_string[1])) { + let option_prefix = option_string + let explicit_arg = undefined + let short_option_prefix = option_string.slice(0, 2) + let short_explicit_arg = option_string.slice(2) + + for (let option_string of Object.keys(this._option_string_actions)) { + if (option_string === short_option_prefix) { + let action = this._option_string_actions[option_string] + let tup = [ action, option_string, short_explicit_arg ] + result.push(tup) + } else if (option_string.startsWith(option_prefix)) { + let action = this._option_string_actions[option_string] + let tup = [ action, option_string, explicit_arg ] + result.push(tup) + } + } + + // shouldn't ever get here + } else { + this.error(sub('unexpected option string: %s', option_string)) + } + + // return the collected option tuples + return result + } + + _get_nargs_pattern(action) { + // in all examples below, we have to allow for '--' args + // which are represented as '-' in the pattern + let nargs = action.nargs + let nargs_pattern + + // the default (None) is assumed to be a single argument + if (nargs === undefined) { + nargs_pattern = '(-*A-*)' + + // allow zero or one arguments + } else if (nargs === OPTIONAL) { + nargs_pattern = '(-*A?-*)' + + // allow zero or more arguments + } else if (nargs === ZERO_OR_MORE) { + nargs_pattern = '(-*[A-]*)' + + // allow one or more arguments + } else if (nargs === ONE_OR_MORE) { + nargs_pattern = '(-*A[A-]*)' + + // allow any number of options or arguments + } else if (nargs === REMAINDER) { + nargs_pattern = '([-AO]*)' + + // allow one argument followed by any number of options or arguments + } else if (nargs === PARSER) { + nargs_pattern = '(-*A[-AO]*)' + + // suppress action, like nargs=0 + } else if (nargs === SUPPRESS) { + nargs_pattern = '(-*-*)' + + // all others should be integers + } else { + nargs_pattern = sub('(-*%s-*)', 'A'.repeat(nargs).split('').join('-*')) + } + + // if this is an optional action, -- is not allowed + if (action.option_strings.length) { + nargs_pattern = nargs_pattern.replace(/-\*/g, '') + nargs_pattern = nargs_pattern.replace(/-/g, '') + } + + // return the pattern + return nargs_pattern + } + + // ======================== + // Alt command line argument parsing, allowing free intermix + // ======================== + + parse_intermixed_args(args = undefined, namespace = undefined) { + let argv + [ args, argv ] = this.parse_known_intermixed_args(args, namespace) + if (argv.length) { + let msg = 'unrecognized arguments: %s' + this.error(sub(msg, argv.join(' '))) + } + return args + } + + parse_known_intermixed_args(args = undefined, namespace = undefined) { + // returns a namespace and list of extras + // + // positional can be freely intermixed with optionals. optionals are + // first parsed with all positional arguments deactivated. The 'extras' + // are then parsed. If the parser definition is incompatible with the + // intermixed assumptions (e.g. use of REMAINDER, subparsers) a + // TypeError is raised. + // + // positionals are 'deactivated' by setting nargs and default to + // SUPPRESS. This blocks the addition of that positional to the + // namespace + + let extras + let positionals = this._get_positional_actions() + let a = positionals.filter(action => [ PARSER, REMAINDER ].includes(action.nargs)) + if (a.length) { + throw new TypeError(sub('parse_intermixed_args: positional arg' + + ' with nargs=%s', a[0].nargs)) + } + + for (let group of this._mutually_exclusive_groups) { + for (let action of group._group_actions) { + if (positionals.includes(action)) { + throw new TypeError('parse_intermixed_args: positional in' + + ' mutuallyExclusiveGroup') + } + } + } + + let save_usage + try { + save_usage = this.usage + let remaining_args + try { + if (this.usage === undefined) { + // capture the full usage for use in error messages + this.usage = this.format_usage().slice(7) + } + for (let action of positionals) { + // deactivate positionals + action.save_nargs = action.nargs + // action.nargs = 0 + action.nargs = SUPPRESS + action.save_default = action.default + action.default = SUPPRESS + } + [ namespace, remaining_args ] = this.parse_known_args(args, + namespace) + for (let action of positionals) { + // remove the empty positional values from namespace + let attr = getattr(namespace, action.dest) + if (Array.isArray(attr) && attr.length === 0) { + // eslint-disable-next-line no-console + console.warn(sub('Do not expect %s in %s', action.dest, namespace)) + delattr(namespace, action.dest) + } + } + } finally { + // restore nargs and usage before exiting + for (let action of positionals) { + action.nargs = action.save_nargs + action.default = action.save_default + } + } + let optionals = this._get_optional_actions() + try { + // parse positionals. optionals aren't normally required, but + // they could be, so make sure they aren't. + for (let action of optionals) { + action.save_required = action.required + action.required = false + } + for (let group of this._mutually_exclusive_groups) { + group.save_required = group.required + group.required = false + } + [ namespace, extras ] = this.parse_known_args(remaining_args, + namespace) + } finally { + // restore parser values before exiting + for (let action of optionals) { + action.required = action.save_required + } + for (let group of this._mutually_exclusive_groups) { + group.required = group.save_required + } + } + } finally { + this.usage = save_usage + } + return [ namespace, extras ] + } + + // ======================== + // Value conversion methods + // ======================== + _get_values(action, arg_strings) { + // for everything but PARSER, REMAINDER args, strip out first '--' + if (![PARSER, REMAINDER].includes(action.nargs)) { + try { + _array_remove(arg_strings, '--') + } catch (err) {} + } + + let value + // optional argument produces a default when not present + if (!arg_strings.length && action.nargs === OPTIONAL) { + if (action.option_strings.length) { + value = action.const + } else { + value = action.default + } + if (typeof value === 'string') { + value = this._get_value(action, value) + this._check_value(action, value) + } + + // when nargs='*' on a positional, if there were no command-line + // args, use the default if it is anything other than None + } else if (!arg_strings.length && action.nargs === ZERO_OR_MORE && + !action.option_strings.length) { + if (action.default !== undefined) { + value = action.default + } else { + value = arg_strings + } + this._check_value(action, value) + + // single argument or optional argument produces a single value + } else if (arg_strings.length === 1 && [undefined, OPTIONAL].includes(action.nargs)) { + let arg_string = arg_strings[0] + value = this._get_value(action, arg_string) + this._check_value(action, value) + + // REMAINDER arguments convert all values, checking none + } else if (action.nargs === REMAINDER) { + value = arg_strings.map(v => this._get_value(action, v)) + + // PARSER arguments convert all values, but check only the first + } else if (action.nargs === PARSER) { + value = arg_strings.map(v => this._get_value(action, v)) + this._check_value(action, value[0]) + + // SUPPRESS argument does not put anything in the namespace + } else if (action.nargs === SUPPRESS) { + value = SUPPRESS + + // all other types of nargs produce a list + } else { + value = arg_strings.map(v => this._get_value(action, v)) + for (let v of value) { + this._check_value(action, v) + } + } + + // return the converted value + return value + } + + _get_value(action, arg_string) { + let type_func = this._registry_get('type', action.type, action.type) + if (typeof type_func !== 'function') { + let msg = '%r is not callable' + throw new ArgumentError(action, sub(msg, type_func)) + } + + // convert the value to the appropriate type + let result + try { + try { + result = type_func(arg_string) + } catch (err) { + // Dear TC39, why would you ever consider making es6 classes not callable? + // We had one universal interface, [[Call]], which worked for anything + // (with familiar this-instanceof guard for classes). Now we have two. + if (err instanceof TypeError && + /Class constructor .* cannot be invoked without 'new'/.test(err.message)) { + // eslint-disable-next-line new-cap + result = new type_func(arg_string) + } else { + throw err + } + } + + } catch (err) { + // ArgumentTypeErrors indicate errors + if (err instanceof ArgumentTypeError) { + //let name = getattr(action.type, 'name', repr(action.type)) + let msg = err.message + throw new ArgumentError(action, msg) + + // TypeErrors or ValueErrors also indicate errors + } else if (err instanceof TypeError) { + let name = getattr(action.type, 'name', repr(action.type)) + let args = {type: name, value: arg_string} + let msg = 'invalid %(type)s value: %(value)r' + throw new ArgumentError(action, sub(msg, args)) + } else { + throw err + } + } + + // return the converted value + return result + } + + _check_value(action, value) { + // converted value must be one of the choices (if specified) + if (action.choices !== undefined && !_choices_to_array(action.choices).includes(value)) { + let args = {value, + choices: _choices_to_array(action.choices).map(repr).join(', ')} + let msg = 'invalid choice: %(value)r (choose from %(choices)s)' + throw new ArgumentError(action, sub(msg, args)) + } + } + + // ======================= + // Help-formatting methods + // ======================= + format_usage() { + let formatter = this._get_formatter() + formatter.add_usage(this.usage, this._actions, + this._mutually_exclusive_groups) + return formatter.format_help() + } + + format_help() { + let formatter = this._get_formatter() + + // usage + formatter.add_usage(this.usage, this._actions, + this._mutually_exclusive_groups) + + // description + formatter.add_text(this.description) + + // positionals, optionals and user-defined groups + for (let action_group of this._action_groups) { + formatter.start_section(action_group.title) + formatter.add_text(action_group.description) + formatter.add_arguments(action_group._group_actions) + formatter.end_section() + } + + // epilog + formatter.add_text(this.epilog) + + // determine help from format above + return formatter.format_help() + } + + _get_formatter() { + // eslint-disable-next-line new-cap + return new this.formatter_class({ prog: this.prog }) + } + + // ===================== + // Help-printing methods + // ===================== + print_usage(file = undefined) { + if (file === undefined) file = process.stdout + this._print_message(this.format_usage(), file) + } + + print_help(file = undefined) { + if (file === undefined) file = process.stdout + this._print_message(this.format_help(), file) + } + + _print_message(message, file = undefined) { + if (message) { + if (file === undefined) file = process.stderr + file.write(message) + } + } + + // =============== + // Exiting methods + // =============== + exit(status = 0, message = undefined) { + if (message) { + this._print_message(message, process.stderr) + } + process.exit(status) + } + + error(message) { + /* + * error(message: string) + * + * Prints a usage message incorporating the message to stderr and + * exits. + * + * If you override this in a subclass, it should not return -- it + * should either exit or raise an exception. + */ + + // LEGACY (v1 compatibility), debug mode + if (this.debug === true) throw new Error(message) + // end + this.print_usage(process.stderr) + let args = {prog: this.prog, message: message} + this.exit(2, sub('%(prog)s: error: %(message)s\n', args)) + } +})) + + +module.exports = { + ArgumentParser, + ArgumentError, + ArgumentTypeError, + BooleanOptionalAction, + FileType, + HelpFormatter, + ArgumentDefaultsHelpFormatter, + RawDescriptionHelpFormatter, + RawTextHelpFormatter, + MetavarTypeHelpFormatter, + Namespace, + Action, + ONE_OR_MORE, + OPTIONAL, + PARSER, + REMAINDER, + SUPPRESS, + ZERO_OR_MORE +} + +// LEGACY (v1 compatibility), Const alias +Object.defineProperty(module.exports, 'Const', { + get() { + let result = {} + Object.entries({ ONE_OR_MORE, OPTIONAL, PARSER, REMAINDER, SUPPRESS, ZERO_OR_MORE }).forEach(([ n, v ]) => { + Object.defineProperty(result, n, { + get() { + deprecate(n, sub('use argparse.%s instead of argparse.Const.%s', n, n)) + return v + } + }) + }) + Object.entries({ _UNRECOGNIZED_ARGS_ATTR }).forEach(([ n, v ]) => { + Object.defineProperty(result, n, { + get() { + deprecate(n, sub('argparse.Const.%s is an internal symbol and will no longer be available', n)) + return v + } + }) + }) + return result + }, + enumerable: false +}) +// end diff --git a/node_modules/wfilesencoders/node_modules/argparse/lib/sub.js b/node_modules/wfilesencoders/node_modules/argparse/lib/sub.js new file mode 100644 index 00000000..e3eb3215 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/argparse/lib/sub.js @@ -0,0 +1,67 @@ +// Limited implementation of python % string operator, supports only %s and %r for now +// (other formats are not used here, but may appear in custom templates) + +'use strict' + +const { inspect } = require('util') + + +module.exports = function sub(pattern, ...values) { + let regex = /%(?:(%)|(-)?(\*)?(?:\((\w+)\))?([A-Za-z]))/g + + let result = pattern.replace(regex, function (_, is_literal, is_left_align, is_padded, name, format) { + if (is_literal) return '%' + + let padded_count = 0 + if (is_padded) { + if (values.length === 0) throw new TypeError('not enough arguments for format string') + padded_count = values.shift() + if (!Number.isInteger(padded_count)) throw new TypeError('* wants int') + } + + let str + if (name !== undefined) { + let dict = values[0] + if (typeof dict !== 'object' || dict === null) throw new TypeError('format requires a mapping') + if (!(name in dict)) throw new TypeError(`no such key: '${name}'`) + str = dict[name] + } else { + if (values.length === 0) throw new TypeError('not enough arguments for format string') + str = values.shift() + } + + switch (format) { + case 's': + str = String(str) + break + case 'r': + str = inspect(str) + break + case 'd': + case 'i': + if (typeof str !== 'number') { + throw new TypeError(`%${format} format: a number is required, not ${typeof str}`) + } + str = String(str.toFixed(0)) + break + default: + throw new TypeError(`unsupported format character '${format}'`) + } + + if (padded_count > 0) { + return is_left_align ? str.padEnd(padded_count) : str.padStart(padded_count) + } else { + return str + } + }) + + if (values.length) { + if (values.length === 1 && typeof values[0] === 'object' && values[0] !== null) { + // mapping + } else { + throw new TypeError('not all arguments converted during string formatting') + } + } + + return result +} diff --git a/node_modules/wfilesencoders/node_modules/argparse/lib/textwrap.js b/node_modules/wfilesencoders/node_modules/argparse/lib/textwrap.js new file mode 100644 index 00000000..23d51cdb --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/argparse/lib/textwrap.js @@ -0,0 +1,440 @@ +// Partial port of python's argparse module, version 3.9.0 (only wrap and fill functions): +// https://github.com/python/cpython/blob/v3.9.0b4/Lib/textwrap.py + +'use strict' + +/* + * Text wrapping and filling. + */ + +// Copyright (C) 1999-2001 Gregory P. Ward. +// Copyright (C) 2002, 2003 Python Software Foundation. +// Copyright (C) 2020 argparse.js authors +// Originally written by Greg Ward + +// Hardcode the recognized whitespace characters to the US-ASCII +// whitespace characters. The main reason for doing this is that +// some Unicode spaces (like \u00a0) are non-breaking whitespaces. +// +// This less funky little regex just split on recognized spaces. E.g. +// "Hello there -- you goof-ball, use the -b option!" +// splits into +// Hello/ /there/ /--/ /you/ /goof-ball,/ /use/ /the/ /-b/ /option!/ +const wordsep_simple_re = /([\t\n\x0b\x0c\r ]+)/ + +class TextWrapper { + /* + * Object for wrapping/filling text. The public interface consists of + * the wrap() and fill() methods; the other methods are just there for + * subclasses to override in order to tweak the default behaviour. + * If you want to completely replace the main wrapping algorithm, + * you'll probably have to override _wrap_chunks(). + * + * Several instance attributes control various aspects of wrapping: + * width (default: 70) + * the maximum width of wrapped lines (unless break_long_words + * is false) + * initial_indent (default: "") + * string that will be prepended to the first line of wrapped + * output. Counts towards the line's width. + * subsequent_indent (default: "") + * string that will be prepended to all lines save the first + * of wrapped output; also counts towards each line's width. + * expand_tabs (default: true) + * Expand tabs in input text to spaces before further processing. + * Each tab will become 0 .. 'tabsize' spaces, depending on its position + * in its line. If false, each tab is treated as a single character. + * tabsize (default: 8) + * Expand tabs in input text to 0 .. 'tabsize' spaces, unless + * 'expand_tabs' is false. + * replace_whitespace (default: true) + * Replace all whitespace characters in the input text by spaces + * after tab expansion. Note that if expand_tabs is false and + * replace_whitespace is true, every tab will be converted to a + * single space! + * fix_sentence_endings (default: false) + * Ensure that sentence-ending punctuation is always followed + * by two spaces. Off by default because the algorithm is + * (unavoidably) imperfect. + * break_long_words (default: true) + * Break words longer than 'width'. If false, those words will not + * be broken, and some lines might be longer than 'width'. + * break_on_hyphens (default: true) + * Allow breaking hyphenated words. If true, wrapping will occur + * preferably on whitespaces and right after hyphens part of + * compound words. + * drop_whitespace (default: true) + * Drop leading and trailing whitespace from lines. + * max_lines (default: None) + * Truncate wrapped lines. + * placeholder (default: ' [...]') + * Append to the last line of truncated text. + */ + + constructor(options = {}) { + let { + width = 70, + initial_indent = '', + subsequent_indent = '', + expand_tabs = true, + replace_whitespace = true, + fix_sentence_endings = false, + break_long_words = true, + drop_whitespace = true, + break_on_hyphens = true, + tabsize = 8, + max_lines = undefined, + placeholder=' [...]' + } = options + + this.width = width + this.initial_indent = initial_indent + this.subsequent_indent = subsequent_indent + this.expand_tabs = expand_tabs + this.replace_whitespace = replace_whitespace + this.fix_sentence_endings = fix_sentence_endings + this.break_long_words = break_long_words + this.drop_whitespace = drop_whitespace + this.break_on_hyphens = break_on_hyphens + this.tabsize = tabsize + this.max_lines = max_lines + this.placeholder = placeholder + } + + + // -- Private methods ----------------------------------------------- + // (possibly useful for subclasses to override) + + _munge_whitespace(text) { + /* + * _munge_whitespace(text : string) -> string + * + * Munge whitespace in text: expand tabs and convert all other + * whitespace characters to spaces. Eg. " foo\\tbar\\n\\nbaz" + * becomes " foo bar baz". + */ + if (this.expand_tabs) { + text = text.replace(/\t/g, ' '.repeat(this.tabsize)) // not strictly correct in js + } + if (this.replace_whitespace) { + text = text.replace(/[\t\n\x0b\x0c\r]/g, ' ') + } + return text + } + + _split(text) { + /* + * _split(text : string) -> [string] + * + * Split the text to wrap into indivisible chunks. Chunks are + * not quite the same as words; see _wrap_chunks() for full + * details. As an example, the text + * Look, goof-ball -- use the -b option! + * breaks into the following chunks: + * 'Look,', ' ', 'goof-', 'ball', ' ', '--', ' ', + * 'use', ' ', 'the', ' ', '-b', ' ', 'option!' + * if break_on_hyphens is True, or in: + * 'Look,', ' ', 'goof-ball', ' ', '--', ' ', + * 'use', ' ', 'the', ' ', '-b', ' ', option!' + * otherwise. + */ + let chunks = text.split(wordsep_simple_re) + chunks = chunks.filter(Boolean) + return chunks + } + + _handle_long_word(reversed_chunks, cur_line, cur_len, width) { + /* + * _handle_long_word(chunks : [string], + * cur_line : [string], + * cur_len : int, width : int) + * + * Handle a chunk of text (most likely a word, not whitespace) that + * is too long to fit in any line. + */ + // Figure out when indent is larger than the specified width, and make + // sure at least one character is stripped off on every pass + let space_left + if (width < 1) { + space_left = 1 + } else { + space_left = width - cur_len + } + + // If we're allowed to break long words, then do so: put as much + // of the next chunk onto the current line as will fit. + if (this.break_long_words) { + cur_line.push(reversed_chunks[reversed_chunks.length - 1].slice(0, space_left)) + reversed_chunks[reversed_chunks.length - 1] = reversed_chunks[reversed_chunks.length - 1].slice(space_left) + + // Otherwise, we have to preserve the long word intact. Only add + // it to the current line if there's nothing already there -- + // that minimizes how much we violate the width constraint. + } else if (!cur_line) { + cur_line.push(...reversed_chunks.pop()) + } + + // If we're not allowed to break long words, and there's already + // text on the current line, do nothing. Next time through the + // main loop of _wrap_chunks(), we'll wind up here again, but + // cur_len will be zero, so the next line will be entirely + // devoted to the long word that we can't handle right now. + } + + _wrap_chunks(chunks) { + /* + * _wrap_chunks(chunks : [string]) -> [string] + * + * Wrap a sequence of text chunks and return a list of lines of + * length 'self.width' or less. (If 'break_long_words' is false, + * some lines may be longer than this.) Chunks correspond roughly + * to words and the whitespace between them: each chunk is + * indivisible (modulo 'break_long_words'), but a line break can + * come between any two chunks. Chunks should not have internal + * whitespace; ie. a chunk is either all whitespace or a "word". + * Whitespace chunks will be removed from the beginning and end of + * lines, but apart from that whitespace is preserved. + */ + let lines = [] + let indent + if (this.width <= 0) { + throw Error(`invalid width ${this.width} (must be > 0)`) + } + if (this.max_lines !== undefined) { + if (this.max_lines > 1) { + indent = this.subsequent_indent + } else { + indent = this.initial_indent + } + if (indent.length + this.placeholder.trimStart().length > this.width) { + throw Error('placeholder too large for max width') + } + } + + // Arrange in reverse order so items can be efficiently popped + // from a stack of chucks. + chunks = chunks.reverse() + + while (chunks.length > 0) { + + // Start the list of chunks that will make up the current line. + // cur_len is just the length of all the chunks in cur_line. + let cur_line = [] + let cur_len = 0 + + // Figure out which static string will prefix this line. + let indent + if (lines) { + indent = this.subsequent_indent + } else { + indent = this.initial_indent + } + + // Maximum width for this line. + let width = this.width - indent.length + + // First chunk on line is whitespace -- drop it, unless this + // is the very beginning of the text (ie. no lines started yet). + if (this.drop_whitespace && chunks[chunks.length - 1].trim() === '' && lines.length > 0) { + chunks.pop() + } + + while (chunks.length > 0) { + let l = chunks[chunks.length - 1].length + + // Can at least squeeze this chunk onto the current line. + if (cur_len + l <= width) { + cur_line.push(chunks.pop()) + cur_len += l + + // Nope, this line is full. + } else { + break + } + } + + // The current line is full, and the next chunk is too big to + // fit on *any* line (not just this one). + if (chunks.length && chunks[chunks.length - 1].length > width) { + this._handle_long_word(chunks, cur_line, cur_len, width) + cur_len = cur_line.map(l => l.length).reduce((a, b) => a + b, 0) + } + + // If the last chunk on this line is all whitespace, drop it. + if (this.drop_whitespace && cur_line.length > 0 && cur_line[cur_line.length - 1].trim() === '') { + cur_len -= cur_line[cur_line.length - 1].length + cur_line.pop() + } + + if (cur_line) { + if (this.max_lines === undefined || + lines.length + 1 < this.max_lines || + (chunks.length === 0 || + this.drop_whitespace && + chunks.length === 1 && + !chunks[0].trim()) && cur_len <= width) { + // Convert current line back to a string and store it in + // list of all lines (return value). + lines.push(indent + cur_line.join('')) + } else { + let had_break = false + while (cur_line) { + if (cur_line[cur_line.length - 1].trim() && + cur_len + this.placeholder.length <= width) { + cur_line.push(this.placeholder) + lines.push(indent + cur_line.join('')) + had_break = true + break + } + cur_len -= cur_line[-1].length + cur_line.pop() + } + if (!had_break) { + if (lines) { + let prev_line = lines[lines.length - 1].trimEnd() + if (prev_line.length + this.placeholder.length <= + this.width) { + lines[lines.length - 1] = prev_line + this.placeholder + break + } + } + lines.push(indent + this.placeholder.lstrip()) + } + break + } + } + } + + return lines + } + + _split_chunks(text) { + text = this._munge_whitespace(text) + return this._split(text) + } + + // -- Public interface ---------------------------------------------- + + wrap(text) { + /* + * wrap(text : string) -> [string] + * + * Reformat the single paragraph in 'text' so it fits in lines of + * no more than 'self.width' columns, and return a list of wrapped + * lines. Tabs in 'text' are expanded with string.expandtabs(), + * and all other whitespace characters (including newline) are + * converted to space. + */ + let chunks = this._split_chunks(text) + // not implemented in js + //if (this.fix_sentence_endings) { + // this._fix_sentence_endings(chunks) + //} + return this._wrap_chunks(chunks) + } + + fill(text) { + /* + * fill(text : string) -> string + * + * Reformat the single paragraph in 'text' to fit in lines of no + * more than 'self.width' columns, and return a new string + * containing the entire wrapped paragraph. + */ + return this.wrap(text).join('\n') + } +} + + +// -- Convenience interface --------------------------------------------- + +function wrap(text, options = {}) { + /* + * Wrap a single paragraph of text, returning a list of wrapped lines. + * + * Reformat the single paragraph in 'text' so it fits in lines of no + * more than 'width' columns, and return a list of wrapped lines. By + * default, tabs in 'text' are expanded with string.expandtabs(), and + * all other whitespace characters (including newline) are converted to + * space. See TextWrapper class for available keyword args to customize + * wrapping behaviour. + */ + let { width = 70, ...kwargs } = options + let w = new TextWrapper(Object.assign({ width }, kwargs)) + return w.wrap(text) +} + +function fill(text, options = {}) { + /* + * Fill a single paragraph of text, returning a new string. + * + * Reformat the single paragraph in 'text' to fit in lines of no more + * than 'width' columns, and return a new string containing the entire + * wrapped paragraph. As with wrap(), tabs are expanded and other + * whitespace characters converted to space. See TextWrapper class for + * available keyword args to customize wrapping behaviour. + */ + let { width = 70, ...kwargs } = options + let w = new TextWrapper(Object.assign({ width }, kwargs)) + return w.fill(text) +} + +// -- Loosely related functionality ------------------------------------- + +let _whitespace_only_re = /^[ \t]+$/mg +let _leading_whitespace_re = /(^[ \t]*)(?:[^ \t\n])/mg + +function dedent(text) { + /* + * Remove any common leading whitespace from every line in `text`. + * + * This can be used to make triple-quoted strings line up with the left + * edge of the display, while still presenting them in the source code + * in indented form. + * + * Note that tabs and spaces are both treated as whitespace, but they + * are not equal: the lines " hello" and "\\thello" are + * considered to have no common leading whitespace. + * + * Entirely blank lines are normalized to a newline character. + */ + // Look for the longest leading string of spaces and tabs common to + // all lines. + let margin = undefined + text = text.replace(_whitespace_only_re, '') + let indents = text.match(_leading_whitespace_re) || [] + for (let indent of indents) { + indent = indent.slice(0, -1) + + if (margin === undefined) { + margin = indent + + // Current line more deeply indented than previous winner: + // no change (previous winner is still on top). + } else if (indent.startsWith(margin)) { + // pass + + // Current line consistent with and no deeper than previous winner: + // it's the new winner. + } else if (margin.startsWith(indent)) { + margin = indent + + // Find the largest common whitespace between current line and previous + // winner. + } else { + for (let i = 0; i < margin.length && i < indent.length; i++) { + if (margin[i] !== indent[i]) { + margin = margin.slice(0, i) + break + } + } + } + } + + if (margin) { + text = text.replace(new RegExp('^' + margin, 'mg'), '') + } + return text +} + +module.exports = { wrap, fill, dedent } diff --git a/node_modules/wfilesencoders/node_modules/argparse/package.json b/node_modules/wfilesencoders/node_modules/argparse/package.json new file mode 100644 index 00000000..647d2aff --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/argparse/package.json @@ -0,0 +1,31 @@ +{ + "name": "argparse", + "description": "CLI arguments parser. Native port of python's argparse.", + "version": "2.0.1", + "keywords": [ + "cli", + "parser", + "argparse", + "option", + "args" + ], + "main": "argparse.js", + "files": [ + "argparse.js", + "lib/" + ], + "license": "Python-2.0", + "repository": "nodeca/argparse", + "scripts": { + "lint": "eslint .", + "test": "npm run lint && nyc mocha", + "coverage": "npm run test && nyc report --reporter html" + }, + "devDependencies": { + "@babel/eslint-parser": "^7.11.0", + "@babel/plugin-syntax-class-properties": "^7.10.4", + "eslint": "^7.5.0", + "mocha": "^8.0.1", + "nyc": "^15.1.0" + } +} diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/CHANGELOG.md b/node_modules/wfilesencoders/node_modules/js-yaml/CHANGELOG.md new file mode 100644 index 00000000..ff2375e0 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/CHANGELOG.md @@ -0,0 +1,616 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## [4.1.0] - 2021-04-15 +### Added +- Types are now exported as `yaml.types.XXX`. +- Every type now has `options` property with original arguments kept as they were + (see `yaml.types.int.options` as an example). + +### Changed +- `Schema.extend()` now keeps old type order in case of conflicts + (e.g. Schema.extend([ a, b, c ]).extend([ b, a, d ]) is now ordered as `abcd` instead of `cbad`). + + +## [4.0.0] - 2021-01-03 +### Changed +- Check [migration guide](migrate_v3_to_v4.md) to see details for all breaking changes. +- Breaking: "unsafe" tags `!!js/function`, `!!js/regexp`, `!!js/undefined` are + moved to [js-yaml-js-types](https://github.com/nodeca/js-yaml-js-types) package. +- Breaking: removed `safe*` functions. Use `load`, `loadAll`, `dump` + instead which are all now safe by default. +- `yaml.DEFAULT_SAFE_SCHEMA` and `yaml.DEFAULT_FULL_SCHEMA` are removed, use + `yaml.DEFAULT_SCHEMA` instead. +- `yaml.Schema.create(schema, tags)` is removed, use `schema.extend(tags)` instead. +- `!!binary` now always mapped to `Uint8Array` on load. +- Reduced nesting of `/lib` folder. +- Parse numbers according to YAML 1.2 instead of YAML 1.1 (`01234` is now decimal, + `0o1234` is octal, `1:23` is parsed as string instead of base60). +- `dump()` no longer quotes `:`, `[`, `]`, `(`, `)` except when necessary, #470, #557. +- Line and column in exceptions are now formatted as `(X:Y)` instead of + `at line X, column Y` (also present in compact format), #332. +- Code snippet created in exceptions now contains multiple lines with line numbers. +- `dump()` now serializes `undefined` as `null` in collections and removes keys with + `undefined` in mappings, #571. +- `dump()` with `skipInvalid=true` now serializes invalid items in collections as null. +- Custom tags starting with `!` are now dumped as `!tag` instead of `!`, #576. +- Custom tags starting with `tag:yaml.org,2002:` are now shorthanded using `!!`, #258. + +### Added +- Added `.mjs` (es modules) support. +- Added `quotingType` and `forceQuotes` options for dumper to configure + string literal style, #290, #529. +- Added `styles: { '!!null': 'empty' }` option for dumper + (serializes `{ foo: null }` as "`foo: `"), #570. +- Added `replacer` option (similar to option in JSON.stringify), #339. +- Custom `Tag` can now handle all tags or multiple tags with the same prefix, #385. + +### Fixed +- Astral characters are no longer encoded by `dump()`, #587. +- "duplicate mapping key" exception now points at the correct column, #452. +- Extra commas in flow collections (e.g. `[foo,,bar]`) now throw an exception + instead of producing null, #321. +- `__proto__` key no longer overrides object prototype, #164. +- Removed `bower.json`. +- Tags are now url-decoded in `load()` and url-encoded in `dump()` + (previously usage of custom non-ascii tags may have led to invalid YAML that can't be parsed). +- Anchors now work correctly with empty nodes, #301. +- Fix incorrect parsing of invalid block mapping syntax, #418. +- Throw an error if block sequence/mapping indent contains a tab, #80. + + +## [3.14.1] - 2020-12-07 +### Security +- Fix possible code execution in (already unsafe) `.load()` (in &anchor). + + +## [3.14.0] - 2020-05-22 +### Changed +- Support `safe/loadAll(input, options)` variant of call. +- CI: drop outdated nodejs versions. +- Dev deps bump. + +### Fixed +- Quote `=` in plain scalars #519. +- Check the node type for `!` tag in case user manually specifies it. +- Verify that there are no null-bytes in input. +- Fix wrong quote position when writing condensed flow, #526. + + +## [3.13.1] - 2019-04-05 +### Security +- Fix possible code execution in (already unsafe) `.load()`, #480. + + +## [3.13.0] - 2019-03-20 +### Security +- Security fix: `safeLoad()` can hang when arrays with nested refs + used as key. Now throws exception for nested arrays. #475. + + +## [3.12.2] - 2019-02-26 +### Fixed +- Fix `noArrayIndent` option for root level, #468. + + +## [3.12.1] - 2019-01-05 +### Added +- Added `noArrayIndent` option, #432. + + +## [3.12.0] - 2018-06-02 +### Changed +- Support arrow functions without a block statement, #421. + + +## [3.11.0] - 2018-03-05 +### Added +- Add arrow functions suport for `!!js/function`. + +### Fixed +- Fix dump in bin/octal/hex formats for negative integers, #399. + + +## [3.10.0] - 2017-09-10 +### Fixed +- Fix `condenseFlow` output (quote keys for sure, instead of spaces), #371, #370. +- Dump astrals as codepoints instead of surrogate pair, #368. + + +## [3.9.1] - 2017-07-08 +### Fixed +- Ensure stack is present for custom errors in node 7.+, #351. + + +## [3.9.0] - 2017-07-08 +### Added +- Add `condenseFlow` option (to create pretty URL query params), #346. + +### Fixed +- Support array return from safeLoadAll/loadAll, #350. + + +## [3.8.4] - 2017-05-08 +### Fixed +- Dumper: prevent space after dash for arrays that wrap, #343. + + +## [3.8.3] - 2017-04-05 +### Fixed +- Should not allow numbers to begin and end with underscore, #335. + + +## [3.8.2] - 2017-03-02 +### Fixed +- Fix `!!float 123` (integers) parse, #333. +- Don't allow leading zeros in floats (except 0, 0.xxx). +- Allow positive exponent without sign in floats. + + +## [3.8.1] - 2017-02-07 +### Changed +- Maintenance: update browserified build. + + +## [3.8.0] - 2017-02-07 +### Fixed +- Fix reported position for `duplicated mapping key` errors. + Now points to block start instead of block end. + (#243, thanks to @shockey). + + +## [3.7.0] - 2016-11-12 +### Added +- Support polymorphism for tags (#300, thanks to @monken). + +### Fixed +- Fix parsing of quotes followed by newlines (#304, thanks to @dplepage). + + +## [3.6.1] - 2016-05-11 +### Fixed +- Fix output cut on a pipe, #286. + + +## [3.6.0] - 2016-04-16 +### Fixed +- Dumper rewrite, fix multiple bugs with trailing `\n`. + Big thanks to @aepsilon! +- Loader: fix leading/trailing newlines in block scalars, @aepsilon. + + +## [3.5.5] - 2016-03-17 +### Fixed +- Date parse fix: don't allow dates with on digit in month and day, #268. + + +## [3.5.4] - 2016-03-09 +### Added +- `noCompatMode` for dumper, to disable quoting YAML 1.1 values. + + +## [3.5.3] - 2016-02-11 +### Changed +- Maintenance release. + + +## [3.5.2] - 2016-01-11 +### Changed +- Maintenance: missed comma in bower config. + + +## [3.5.1] - 2016-01-11 +### Changed +- Removed `inherit` dependency, #239. +- Better browserify workaround for esprima load. +- Demo rewrite. + + +## [3.5.0] - 2016-01-10 +### Fixed +- Dumper. Fold strings only, #217. +- Dumper. `norefs` option, to clone linked objects, #229. +- Loader. Throw a warning for duplicate keys, #166. +- Improved browserify support (mark `esprima` & `Buffer` excluded). + + +## [3.4.6] - 2015-11-26 +### Changed +- Use standalone `inherit` to keep browserified files clear. + + +## [3.4.5] - 2015-11-23 +### Added +- Added `lineWidth` option to dumper. + + +## [3.4.4] - 2015-11-21 +### Fixed +- Fixed floats dump (missed dot for scientific format), #220. +- Allow non-printable characters inside quoted scalars, #192. + + +## [3.4.3] - 2015-10-10 +### Changed +- Maintenance release - deps bump (esprima, argparse). + + +## [3.4.2] - 2015-09-09 +### Fixed +- Fixed serialization of duplicated entries in sequences, #205. + Thanks to @vogelsgesang. + + +## [3.4.1] - 2015-09-05 +### Fixed +- Fixed stacktrace handling in generated errors, for browsers (FF/IE). + + +## [3.4.0] - 2015-08-23 +### Changed +- Don't throw on warnings anymore. Use `onWarning` option to catch. +- Throw error on unknown tags (was warning before). +- Reworked internals of error class. + +### Fixed +- Fixed multiline keys dump, #197. Thanks to @tcr. +- Fixed heading line breaks in some scalars (regression). + + +## [3.3.1] - 2015-05-13 +### Added +- Added `.sortKeys` dumper option, thanks to @rjmunro. + +### Fixed +- Fixed astral characters support, #191. + + +## [3.3.0] - 2015-04-26 +### Changed +- Significantly improved long strings formatting in dumper, thanks to @isaacs. +- Strip BOM if exists. + + +## [3.2.7] - 2015-02-19 +### Changed +- Maintenance release. +- Updated dependencies. +- HISTORY.md -> CHANGELOG.md + + +## [3.2.6] - 2015-02-07 +### Fixed +- Fixed encoding of UTF-16 surrogate pairs. (e.g. "\U0001F431" CAT FACE). +- Fixed demo dates dump (#113, thanks to @Hypercubed). + + +## [3.2.5] - 2014-12-28 +### Fixed +- Fixed resolving of all built-in types on empty nodes. +- Fixed invalid warning on empty lines within quoted scalars and flow collections. +- Fixed bug: Tag on an empty node didn't resolve in some cases. + + +## [3.2.4] - 2014-12-19 +### Fixed +- Fixed resolving of !!null tag on an empty node. + + +## [3.2.3] - 2014-11-08 +### Fixed +- Implemented dumping of objects with circular and cross references. +- Partially fixed aliasing of constructed objects. (see issue #141 for details) + + +## [3.2.2] - 2014-09-07 +### Fixed +- Fixed infinite loop on unindented block scalars. +- Rewritten base64 encode/decode in binary type, to keep code licence clear. + + +## [3.2.1] - 2014-08-24 +### Fixed +- Nothig new. Just fix npm publish error. + + +## [3.2.0] - 2014-08-24 +### Added +- Added input piping support to CLI. + +### Fixed +- Fixed typo, that could cause hand on initial indent (#139). + + +## [3.1.0] - 2014-07-07 +### Changed +- 1.5x-2x speed boost. +- Removed deprecated `require('xxx.yml')` support. +- Significant code cleanup and refactoring. +- Internal API changed. If you used custom types - see updated examples. + Others are not affected. +- Even if the input string has no trailing line break character, + it will be parsed as if it has one. +- Added benchmark scripts. +- Moved bower files to /dist folder +- Bugfixes. + + +## [3.0.2] - 2014-02-27 +### Fixed +- Fixed bug: "constructor" string parsed as `null`. + + +## [3.0.1] - 2013-12-22 +### Fixed +- Fixed parsing of literal scalars. (issue #108) +- Prevented adding unnecessary spaces in object dumps. (issue #68) +- Fixed dumping of objects with very long (> 1024 in length) keys. + + +## [3.0.0] - 2013-12-16 +### Changed +- Refactored code. Changed API for custom types. +- Removed output colors in CLI, dump json by default. +- Removed big dependencies from browser version (esprima, buffer). Load `esprima` manually, if `!!js/function` needed. `!!bin` now returns Array in browser +- AMD support. +- Don't quote dumped strings because of `-` & `?` (if not first char). +- __Deprecated__ loading yaml files via `require()`, as not recommended + behaviour for node. + + +## [2.1.3] - 2013-10-16 +### Fixed +- Fix wrong loading of empty block scalars. + + +## [2.1.2] - 2013-10-07 +### Fixed +- Fix unwanted line breaks in folded scalars. + + +## [2.1.1] - 2013-10-02 +### Fixed +- Dumper now respects deprecated booleans syntax from YAML 1.0/1.1 +- Fixed reader bug in JSON-like sequences/mappings. + + +## [2.1.0] - 2013-06-05 +### Added +- Add standard YAML schemas: Failsafe (`FAILSAFE_SCHEMA`), + JSON (`JSON_SCHEMA`) and Core (`CORE_SCHEMA`). +- Add `skipInvalid` dumper option. + +### Changed +- Rename `DEFAULT_SCHEMA` to `DEFAULT_FULL_SCHEMA` + and `SAFE_SCHEMA` to `DEFAULT_SAFE_SCHEMA`. +- Use `safeLoad` for `require` extension. + +### Fixed +- Bug fix: export `NIL` constant from the public interface. + + +## [2.0.5] - 2013-04-26 +### Security +- Close security issue in !!js/function constructor. + Big thanks to @nealpoole for security audit. + + +## [2.0.4] - 2013-04-08 +### Changed +- Updated .npmignore to reduce package size + + +## [2.0.3] - 2013-02-26 +### Fixed +- Fixed dumping of empty arrays ans objects. ([] and {} instead of null) + + +## [2.0.2] - 2013-02-15 +### Fixed +- Fixed input validation: tabs are printable characters. + + +## [2.0.1] - 2013-02-09 +### Fixed +- Fixed error, when options not passed to function cass + + +## [2.0.0] - 2013-02-09 +### Changed +- Full rewrite. New architecture. Fast one-stage parsing. +- Changed custom types API. +- Added YAML dumper. + + +## [1.0.3] - 2012-11-05 +### Fixed +- Fixed utf-8 files loading. + + +## [1.0.2] - 2012-08-02 +### Fixed +- Pull out hand-written shims. Use ES5-Shims for old browsers support. See #44. +- Fix timstamps incorectly parsed in local time when no time part specified. + + +## [1.0.1] - 2012-07-07 +### Fixed +- Fixes `TypeError: 'undefined' is not an object` under Safari. Thanks Phuong. +- Fix timestamps incorrectly parsed in local time. Thanks @caolan. Closes #46. + + +## [1.0.0] - 2012-07-01 +### Changed +- `y`, `yes`, `n`, `no`, `on`, `off` are not converted to Booleans anymore. + Fixes #42. +- `require(filename)` now returns a single document and throws an Error if + file contains more than one document. +- CLI was merged back from js-yaml.bin + + +## [0.3.7] - 2012-02-28 +### Fixed +- Fix export of `addConstructor()`. Closes #39. + + +## [0.3.6] - 2012-02-22 +### Changed +- Removed AMD parts - too buggy to use. Need help to rewrite from scratch + +### Fixed +- Removed YUI compressor warning (renamed `double` variable). Closes #40. + + +## [0.3.5] - 2012-01-10 +### Fixed +- Workagound for .npmignore fuckup under windows. Thanks to airportyh. + + +## [0.3.4] - 2011-12-24 +### Fixed +- Fixes str[] for oldIEs support. +- Adds better has change support for browserified demo. +- improves compact output of Error. Closes #33. + + +## [0.3.3] - 2011-12-20 +### Added +- adds `compact` stringification of Errors. + +### Changed +- jsyaml executable moved to separate module. + + +## [0.3.2] - 2011-12-16 +### Added +- Added jsyaml executable. +- Added !!js/function support. Closes #12. + +### Fixed +- Fixes ug with block style scalars. Closes #26. +- All sources are passing JSLint now. +- Fixes bug in Safari. Closes #28. +- Fixes bug in Opers. Closes #29. +- Improves browser support. Closes #20. + + +## [0.3.1] - 2011-11-18 +### Added +- Added AMD support for browserified version. +- Added permalinks for online demo YAML snippets. Now we have YPaste service, lol. +- Added !!js/regexp and !!js/undefined types. Partially solves #12. + +### Changed +- Wrapped browserified js-yaml into closure. + +### Fixed +- Fixed the resolvement of non-specific tags. Closes #17. +- Fixed !!set mapping. +- Fixed month parse in dates. Closes #19. + + +## [0.3.0] - 2011-11-09 +### Added +- Added browserified version. Closes #13. +- Added live demo of browserified version. +- Ported some of the PyYAML tests. See #14. + +### Fixed +- Removed JS.Class dependency. Closes #3. +- Fixed timestamp bug when fraction was given. + + +## [0.2.2] - 2011-11-06 +### Fixed +- Fixed crash on docs without ---. Closes #8. +- Fixed multiline string parse +- Fixed tests/comments for using array as key + + +## [0.2.1] - 2011-11-02 +### Fixed +- Fixed short file read (<4k). Closes #9. + + +## [0.2.0] - 2011-11-02 +### Changed +- First public release + + +[4.1.0]: https://github.com/nodeca/js-yaml/compare/4.0.0...4.1.0 +[4.0.0]: https://github.com/nodeca/js-yaml/compare/3.14.0...4.0.0 +[3.14.0]: https://github.com/nodeca/js-yaml/compare/3.13.1...3.14.0 +[3.13.1]: https://github.com/nodeca/js-yaml/compare/3.13.0...3.13.1 +[3.13.0]: https://github.com/nodeca/js-yaml/compare/3.12.2...3.13.0 +[3.12.2]: https://github.com/nodeca/js-yaml/compare/3.12.1...3.12.2 +[3.12.1]: https://github.com/nodeca/js-yaml/compare/3.12.0...3.12.1 +[3.12.0]: https://github.com/nodeca/js-yaml/compare/3.11.0...3.12.0 +[3.11.0]: https://github.com/nodeca/js-yaml/compare/3.10.0...3.11.0 +[3.10.0]: https://github.com/nodeca/js-yaml/compare/3.9.1...3.10.0 +[3.9.1]: https://github.com/nodeca/js-yaml/compare/3.9.0...3.9.1 +[3.9.0]: https://github.com/nodeca/js-yaml/compare/3.8.4...3.9.0 +[3.8.4]: https://github.com/nodeca/js-yaml/compare/3.8.3...3.8.4 +[3.8.3]: https://github.com/nodeca/js-yaml/compare/3.8.2...3.8.3 +[3.8.2]: https://github.com/nodeca/js-yaml/compare/3.8.1...3.8.2 +[3.8.1]: https://github.com/nodeca/js-yaml/compare/3.8.0...3.8.1 +[3.8.0]: https://github.com/nodeca/js-yaml/compare/3.7.0...3.8.0 +[3.7.0]: https://github.com/nodeca/js-yaml/compare/3.6.1...3.7.0 +[3.6.1]: https://github.com/nodeca/js-yaml/compare/3.6.0...3.6.1 +[3.6.0]: https://github.com/nodeca/js-yaml/compare/3.5.5...3.6.0 +[3.5.5]: https://github.com/nodeca/js-yaml/compare/3.5.4...3.5.5 +[3.5.4]: https://github.com/nodeca/js-yaml/compare/3.5.3...3.5.4 +[3.5.3]: https://github.com/nodeca/js-yaml/compare/3.5.2...3.5.3 +[3.5.2]: https://github.com/nodeca/js-yaml/compare/3.5.1...3.5.2 +[3.5.1]: https://github.com/nodeca/js-yaml/compare/3.5.0...3.5.1 +[3.5.0]: https://github.com/nodeca/js-yaml/compare/3.4.6...3.5.0 +[3.4.6]: https://github.com/nodeca/js-yaml/compare/3.4.5...3.4.6 +[3.4.5]: https://github.com/nodeca/js-yaml/compare/3.4.4...3.4.5 +[3.4.4]: https://github.com/nodeca/js-yaml/compare/3.4.3...3.4.4 +[3.4.3]: https://github.com/nodeca/js-yaml/compare/3.4.2...3.4.3 +[3.4.2]: https://github.com/nodeca/js-yaml/compare/3.4.1...3.4.2 +[3.4.1]: https://github.com/nodeca/js-yaml/compare/3.4.0...3.4.1 +[3.4.0]: https://github.com/nodeca/js-yaml/compare/3.3.1...3.4.0 +[3.3.1]: https://github.com/nodeca/js-yaml/compare/3.3.0...3.3.1 +[3.3.0]: https://github.com/nodeca/js-yaml/compare/3.2.7...3.3.0 +[3.2.7]: https://github.com/nodeca/js-yaml/compare/3.2.6...3.2.7 +[3.2.6]: https://github.com/nodeca/js-yaml/compare/3.2.5...3.2.6 +[3.2.5]: https://github.com/nodeca/js-yaml/compare/3.2.4...3.2.5 +[3.2.4]: https://github.com/nodeca/js-yaml/compare/3.2.3...3.2.4 +[3.2.3]: https://github.com/nodeca/js-yaml/compare/3.2.2...3.2.3 +[3.2.2]: https://github.com/nodeca/js-yaml/compare/3.2.1...3.2.2 +[3.2.1]: https://github.com/nodeca/js-yaml/compare/3.2.0...3.2.1 +[3.2.0]: https://github.com/nodeca/js-yaml/compare/3.1.0...3.2.0 +[3.1.0]: https://github.com/nodeca/js-yaml/compare/3.0.2...3.1.0 +[3.0.2]: https://github.com/nodeca/js-yaml/compare/3.0.1...3.0.2 +[3.0.1]: https://github.com/nodeca/js-yaml/compare/3.0.0...3.0.1 +[3.0.0]: https://github.com/nodeca/js-yaml/compare/2.1.3...3.0.0 +[2.1.3]: https://github.com/nodeca/js-yaml/compare/2.1.2...2.1.3 +[2.1.2]: https://github.com/nodeca/js-yaml/compare/2.1.1...2.1.2 +[2.1.1]: https://github.com/nodeca/js-yaml/compare/2.1.0...2.1.1 +[2.1.0]: https://github.com/nodeca/js-yaml/compare/2.0.5...2.1.0 +[2.0.5]: https://github.com/nodeca/js-yaml/compare/2.0.4...2.0.5 +[2.0.4]: https://github.com/nodeca/js-yaml/compare/2.0.3...2.0.4 +[2.0.3]: https://github.com/nodeca/js-yaml/compare/2.0.2...2.0.3 +[2.0.2]: https://github.com/nodeca/js-yaml/compare/2.0.1...2.0.2 +[2.0.1]: https://github.com/nodeca/js-yaml/compare/2.0.0...2.0.1 +[2.0.0]: https://github.com/nodeca/js-yaml/compare/1.0.3...2.0.0 +[1.0.3]: https://github.com/nodeca/js-yaml/compare/1.0.2...1.0.3 +[1.0.2]: https://github.com/nodeca/js-yaml/compare/1.0.1...1.0.2 +[1.0.1]: https://github.com/nodeca/js-yaml/compare/1.0.0...1.0.1 +[1.0.0]: https://github.com/nodeca/js-yaml/compare/0.3.7...1.0.0 +[0.3.7]: https://github.com/nodeca/js-yaml/compare/0.3.6...0.3.7 +[0.3.6]: https://github.com/nodeca/js-yaml/compare/0.3.5...0.3.6 +[0.3.5]: https://github.com/nodeca/js-yaml/compare/0.3.4...0.3.5 +[0.3.4]: https://github.com/nodeca/js-yaml/compare/0.3.3...0.3.4 +[0.3.3]: https://github.com/nodeca/js-yaml/compare/0.3.2...0.3.3 +[0.3.2]: https://github.com/nodeca/js-yaml/compare/0.3.1...0.3.2 +[0.3.1]: https://github.com/nodeca/js-yaml/compare/0.3.0...0.3.1 +[0.3.0]: https://github.com/nodeca/js-yaml/compare/0.2.2...0.3.0 +[0.2.2]: https://github.com/nodeca/js-yaml/compare/0.2.1...0.2.2 +[0.2.1]: https://github.com/nodeca/js-yaml/compare/0.2.0...0.2.1 +[0.2.0]: https://github.com/nodeca/js-yaml/releases/tag/0.2.0 diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/LICENSE b/node_modules/wfilesencoders/node_modules/js-yaml/LICENSE new file mode 100644 index 00000000..09d3a29e --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/LICENSE @@ -0,0 +1,21 @@ +(The MIT License) + +Copyright (C) 2011-2015 by Vitaly Puzrin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/README.md b/node_modules/wfilesencoders/node_modules/js-yaml/README.md new file mode 100644 index 00000000..3cbc4bd2 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/README.md @@ -0,0 +1,246 @@ +JS-YAML - YAML 1.2 parser / writer for JavaScript +================================================= + +[![CI](https://github.com/nodeca/js-yaml/workflows/CI/badge.svg?branch=master)](https://github.com/nodeca/js-yaml/actions) +[![NPM version](https://img.shields.io/npm/v/js-yaml.svg)](https://www.npmjs.org/package/js-yaml) + +__[Online Demo](http://nodeca.github.com/js-yaml/)__ + + +This is an implementation of [YAML](http://yaml.org/), a human-friendly data +serialization language. Started as [PyYAML](http://pyyaml.org/) port, it was +completely rewritten from scratch. Now it's very fast, and supports 1.2 spec. + + +Installation +------------ + +### YAML module for node.js + +``` +npm install js-yaml +``` + + +### CLI executable + +If you want to inspect your YAML files from CLI, install js-yaml globally: + +``` +npm install -g js-yaml +``` + +#### Usage + +``` +usage: js-yaml [-h] [-v] [-c] [-t] file + +Positional arguments: + file File with YAML document(s) + +Optional arguments: + -h, --help Show this help message and exit. + -v, --version Show program's version number and exit. + -c, --compact Display errors in compact mode + -t, --trace Show stack trace on error +``` + + +API +--- + +Here we cover the most 'useful' methods. If you need advanced details (creating +your own tags), see [examples](https://github.com/nodeca/js-yaml/tree/master/examples) +for more info. + +``` javascript +const yaml = require('js-yaml'); +const fs = require('fs'); + +// Get document, or throw exception on error +try { + const doc = yaml.load(fs.readFileSync('/home/ixti/example.yml', 'utf8')); + console.log(doc); +} catch (e) { + console.log(e); +} +``` + + +### load (string [ , options ]) + +Parses `string` as single YAML document. Returns either a +plain object, a string, a number, `null` or `undefined`, or throws `YAMLException` on error. By default, does +not support regexps, functions and undefined. + +options: + +- `filename` _(default: null)_ - string to be used as a file path in + error/warning messages. +- `onWarning` _(default: null)_ - function to call on warning messages. + Loader will call this function with an instance of `YAMLException` for each warning. +- `schema` _(default: `DEFAULT_SCHEMA`)_ - specifies a schema to use. + - `FAILSAFE_SCHEMA` - only strings, arrays and plain objects: + http://www.yaml.org/spec/1.2/spec.html#id2802346 + - `JSON_SCHEMA` - all JSON-supported types: + http://www.yaml.org/spec/1.2/spec.html#id2803231 + - `CORE_SCHEMA` - same as `JSON_SCHEMA`: + http://www.yaml.org/spec/1.2/spec.html#id2804923 + - `DEFAULT_SCHEMA` - all supported YAML types. +- `json` _(default: false)_ - compatibility with JSON.parse behaviour. If true, then duplicate keys in a mapping will override values rather than throwing an error. + +NOTE: This function **does not** understand multi-document sources, it throws +exception on those. + +NOTE: JS-YAML **does not** support schema-specific tag resolution restrictions. +So, the JSON schema is not as strictly defined in the YAML specification. +It allows numbers in any notation, use `Null` and `NULL` as `null`, etc. +The core schema also has no such restrictions. It allows binary notation for integers. + + +### loadAll (string [, iterator] [, options ]) + +Same as `load()`, but understands multi-document sources. Applies +`iterator` to each document if specified, or returns array of documents. + +``` javascript +const yaml = require('js-yaml'); + +yaml.loadAll(data, function (doc) { + console.log(doc); +}); +``` + + +### dump (object [ , options ]) + +Serializes `object` as a YAML document. Uses `DEFAULT_SCHEMA`, so it will +throw an exception if you try to dump regexps or functions. However, you can +disable exceptions by setting the `skipInvalid` option to `true`. + +options: + +- `indent` _(default: 2)_ - indentation width to use (in spaces). +- `noArrayIndent` _(default: false)_ - when true, will not add an indentation level to array elements +- `skipInvalid` _(default: false)_ - do not throw on invalid types (like function + in the safe schema) and skip pairs and single values with such types. +- `flowLevel` _(default: -1)_ - specifies level of nesting, when to switch from + block to flow style for collections. -1 means block style everwhere +- `styles` - "tag" => "style" map. Each tag may have own set of styles. +- `schema` _(default: `DEFAULT_SCHEMA`)_ specifies a schema to use. +- `sortKeys` _(default: `false`)_ - if `true`, sort keys when dumping YAML. If a + function, use the function to sort the keys. +- `lineWidth` _(default: `80`)_ - set max line width. Set `-1` for unlimited width. +- `noRefs` _(default: `false`)_ - if `true`, don't convert duplicate objects into references +- `noCompatMode` _(default: `false`)_ - if `true` don't try to be compatible with older + yaml versions. Currently: don't quote "yes", "no" and so on, as required for YAML 1.1 +- `condenseFlow` _(default: `false`)_ - if `true` flow sequences will be condensed, omitting the space between `a, b`. Eg. `'[a,b]'`, and omitting the space between `key: value` and quoting the key. Eg. `'{"a":b}'` Can be useful when using yaml for pretty URL query params as spaces are %-encoded. +- `quotingType` _(`'` or `"`, default: `'`)_ - strings will be quoted using this quoting style. If you specify single quotes, double quotes will still be used for non-printable characters. +- `forceQuotes` _(default: `false`)_ - if `true`, all non-key strings will be quoted even if they normally don't need to. +- `replacer` - callback `function (key, value)` called recursively on each key/value in source object (see `replacer` docs for `JSON.stringify`). + +The following table show availlable styles (e.g. "canonical", +"binary"...) available for each tag (.e.g. !!null, !!int ...). Yaml +output is shown on the right side after `=>` (default setting) or `->`: + +``` none +!!null + "canonical" -> "~" + "lowercase" => "null" + "uppercase" -> "NULL" + "camelcase" -> "Null" + +!!int + "binary" -> "0b1", "0b101010", "0b1110001111010" + "octal" -> "0o1", "0o52", "0o16172" + "decimal" => "1", "42", "7290" + "hexadecimal" -> "0x1", "0x2A", "0x1C7A" + +!!bool + "lowercase" => "true", "false" + "uppercase" -> "TRUE", "FALSE" + "camelcase" -> "True", "False" + +!!float + "lowercase" => ".nan", '.inf' + "uppercase" -> ".NAN", '.INF' + "camelcase" -> ".NaN", '.Inf' +``` + +Example: + +``` javascript +dump(object, { + 'styles': { + '!!null': 'canonical' // dump null as ~ + }, + 'sortKeys': true // sort object keys +}); +``` + +Supported YAML types +-------------------- + +The list of standard YAML tags and corresponding JavaScript types. See also +[YAML tag discussion](http://pyyaml.org/wiki/YAMLTagDiscussion) and +[YAML types repository](http://yaml.org/type/). + +``` +!!null '' # null +!!bool 'yes' # bool +!!int '3...' # number +!!float '3.14...' # number +!!binary '...base64...' # buffer +!!timestamp 'YYYY-...' # date +!!omap [ ... ] # array of key-value pairs +!!pairs [ ... ] # array or array pairs +!!set { ... } # array of objects with given keys and null values +!!str '...' # string +!!seq [ ... ] # array +!!map { ... } # object +``` + +**JavaScript-specific tags** + +See [js-yaml-js-types](https://github.com/nodeca/js-yaml-js-types) for +extra types. + + +Caveats +------- + +Note, that you use arrays or objects as key in JS-YAML. JS does not allow objects +or arrays as keys, and stringifies (by calling `toString()` method) them at the +moment of adding them. + +``` yaml +--- +? [ foo, bar ] +: - baz +? { foo: bar } +: - baz + - baz +``` + +``` javascript +{ "foo,bar": ["baz"], "[object Object]": ["baz", "baz"] } +``` + +Also, reading of properties on implicit block mapping keys is not supported yet. +So, the following YAML document cannot be loaded. + +``` yaml +&anchor foo: + foo: bar + *anchor: duplicate key + baz: bat + *anchor: duplicate key +``` + + +js-yaml for enterprise +---------------------- + +Available as part of the Tidelift Subscription + +The maintainers of js-yaml and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-js-yaml?utm_source=npm-js-yaml&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/bin/js-yaml.js b/node_modules/wfilesencoders/node_modules/js-yaml/bin/js-yaml.js new file mode 100755 index 00000000..a182f1af --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/bin/js-yaml.js @@ -0,0 +1,126 @@ +#!/usr/bin/env node + + +'use strict'; + +/*eslint-disable no-console*/ + + +var fs = require('fs'); +var argparse = require('argparse'); +var yaml = require('..'); + + +//////////////////////////////////////////////////////////////////////////////// + + +var cli = new argparse.ArgumentParser({ + prog: 'js-yaml', + add_help: true +}); + +cli.add_argument('-v', '--version', { + action: 'version', + version: require('../package.json').version +}); + +cli.add_argument('-c', '--compact', { + help: 'Display errors in compact mode', + action: 'store_true' +}); + +// deprecated (not needed after we removed output colors) +// option suppressed, but not completely removed for compatibility +cli.add_argument('-j', '--to-json', { + help: argparse.SUPPRESS, + dest: 'json', + action: 'store_true' +}); + +cli.add_argument('-t', '--trace', { + help: 'Show stack trace on error', + action: 'store_true' +}); + +cli.add_argument('file', { + help: 'File to read, utf-8 encoded without BOM', + nargs: '?', + default: '-' +}); + + +//////////////////////////////////////////////////////////////////////////////// + + +var options = cli.parse_args(); + + +//////////////////////////////////////////////////////////////////////////////// + +function readFile(filename, encoding, callback) { + if (options.file === '-') { + // read from stdin + + var chunks = []; + + process.stdin.on('data', function (chunk) { + chunks.push(chunk); + }); + + process.stdin.on('end', function () { + return callback(null, Buffer.concat(chunks).toString(encoding)); + }); + } else { + fs.readFile(filename, encoding, callback); + } +} + +readFile(options.file, 'utf8', function (error, input) { + var output, isYaml; + + if (error) { + if (error.code === 'ENOENT') { + console.error('File not found: ' + options.file); + process.exit(2); + } + + console.error( + options.trace && error.stack || + error.message || + String(error)); + + process.exit(1); + } + + try { + output = JSON.parse(input); + isYaml = false; + } catch (err) { + if (err instanceof SyntaxError) { + try { + output = []; + yaml.loadAll(input, function (doc) { output.push(doc); }, {}); + isYaml = true; + + if (output.length === 0) output = null; + else if (output.length === 1) output = output[0]; + + } catch (e) { + if (options.trace && err.stack) console.error(e.stack); + else console.error(e.toString(options.compact)); + + process.exit(1); + } + } else { + console.error( + options.trace && err.stack || + err.message || + String(err)); + + process.exit(1); + } + } + + if (isYaml) console.log(JSON.stringify(output, null, ' ')); + else console.log(yaml.dump(output)); +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/dist/js-yaml.js b/node_modules/wfilesencoders/node_modules/js-yaml/dist/js-yaml.js new file mode 100644 index 00000000..4cc0ddf6 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/dist/js-yaml.js @@ -0,0 +1,3874 @@ + +/*! js-yaml 4.1.0 https://github.com/nodeca/js-yaml @license MIT */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.jsyaml = {})); +}(this, (function (exports) { 'use strict'; + + function isNothing(subject) { + return (typeof subject === 'undefined') || (subject === null); + } + + + function isObject(subject) { + return (typeof subject === 'object') && (subject !== null); + } + + + function toArray(sequence) { + if (Array.isArray(sequence)) return sequence; + else if (isNothing(sequence)) return []; + + return [ sequence ]; + } + + + function extend(target, source) { + var index, length, key, sourceKeys; + + if (source) { + sourceKeys = Object.keys(source); + + for (index = 0, length = sourceKeys.length; index < length; index += 1) { + key = sourceKeys[index]; + target[key] = source[key]; + } + } + + return target; + } + + + function repeat(string, count) { + var result = '', cycle; + + for (cycle = 0; cycle < count; cycle += 1) { + result += string; + } + + return result; + } + + + function isNegativeZero(number) { + return (number === 0) && (Number.NEGATIVE_INFINITY === 1 / number); + } + + + var isNothing_1 = isNothing; + var isObject_1 = isObject; + var toArray_1 = toArray; + var repeat_1 = repeat; + var isNegativeZero_1 = isNegativeZero; + var extend_1 = extend; + + var common = { + isNothing: isNothing_1, + isObject: isObject_1, + toArray: toArray_1, + repeat: repeat_1, + isNegativeZero: isNegativeZero_1, + extend: extend_1 + }; + + // YAML error class. http://stackoverflow.com/questions/8458984 + + + function formatError(exception, compact) { + var where = '', message = exception.reason || '(unknown reason)'; + + if (!exception.mark) return message; + + if (exception.mark.name) { + where += 'in "' + exception.mark.name + '" '; + } + + where += '(' + (exception.mark.line + 1) + ':' + (exception.mark.column + 1) + ')'; + + if (!compact && exception.mark.snippet) { + where += '\n\n' + exception.mark.snippet; + } + + return message + ' ' + where; + } + + + function YAMLException$1(reason, mark) { + // Super constructor + Error.call(this); + + this.name = 'YAMLException'; + this.reason = reason; + this.mark = mark; + this.message = formatError(this, false); + + // Include stack trace in error object + if (Error.captureStackTrace) { + // Chrome and NodeJS + Error.captureStackTrace(this, this.constructor); + } else { + // FF, IE 10+ and Safari 6+. Fallback for others + this.stack = (new Error()).stack || ''; + } + } + + + // Inherit from Error + YAMLException$1.prototype = Object.create(Error.prototype); + YAMLException$1.prototype.constructor = YAMLException$1; + + + YAMLException$1.prototype.toString = function toString(compact) { + return this.name + ': ' + formatError(this, compact); + }; + + + var exception = YAMLException$1; + + // get snippet for a single line, respecting maxLength + function getLine(buffer, lineStart, lineEnd, position, maxLineLength) { + var head = ''; + var tail = ''; + var maxHalfLength = Math.floor(maxLineLength / 2) - 1; + + if (position - lineStart > maxHalfLength) { + head = ' ... '; + lineStart = position - maxHalfLength + head.length; + } + + if (lineEnd - position > maxHalfLength) { + tail = ' ...'; + lineEnd = position + maxHalfLength - tail.length; + } + + return { + str: head + buffer.slice(lineStart, lineEnd).replace(/\t/g, '→') + tail, + pos: position - lineStart + head.length // relative position + }; + } + + + function padStart(string, max) { + return common.repeat(' ', max - string.length) + string; + } + + + function makeSnippet(mark, options) { + options = Object.create(options || null); + + if (!mark.buffer) return null; + + if (!options.maxLength) options.maxLength = 79; + if (typeof options.indent !== 'number') options.indent = 1; + if (typeof options.linesBefore !== 'number') options.linesBefore = 3; + if (typeof options.linesAfter !== 'number') options.linesAfter = 2; + + var re = /\r?\n|\r|\0/g; + var lineStarts = [ 0 ]; + var lineEnds = []; + var match; + var foundLineNo = -1; + + while ((match = re.exec(mark.buffer))) { + lineEnds.push(match.index); + lineStarts.push(match.index + match[0].length); + + if (mark.position <= match.index && foundLineNo < 0) { + foundLineNo = lineStarts.length - 2; + } + } + + if (foundLineNo < 0) foundLineNo = lineStarts.length - 1; + + var result = '', i, line; + var lineNoLength = Math.min(mark.line + options.linesAfter, lineEnds.length).toString().length; + var maxLineLength = options.maxLength - (options.indent + lineNoLength + 3); + + for (i = 1; i <= options.linesBefore; i++) { + if (foundLineNo - i < 0) break; + line = getLine( + mark.buffer, + lineStarts[foundLineNo - i], + lineEnds[foundLineNo - i], + mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo - i]), + maxLineLength + ); + result = common.repeat(' ', options.indent) + padStart((mark.line - i + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n' + result; + } + + line = getLine(mark.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark.position, maxLineLength); + result += common.repeat(' ', options.indent) + padStart((mark.line + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n'; + result += common.repeat('-', options.indent + lineNoLength + 3 + line.pos) + '^' + '\n'; + + for (i = 1; i <= options.linesAfter; i++) { + if (foundLineNo + i >= lineEnds.length) break; + line = getLine( + mark.buffer, + lineStarts[foundLineNo + i], + lineEnds[foundLineNo + i], + mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo + i]), + maxLineLength + ); + result += common.repeat(' ', options.indent) + padStart((mark.line + i + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n'; + } + + return result.replace(/\n$/, ''); + } + + + var snippet = makeSnippet; + + var TYPE_CONSTRUCTOR_OPTIONS = [ + 'kind', + 'multi', + 'resolve', + 'construct', + 'instanceOf', + 'predicate', + 'represent', + 'representName', + 'defaultStyle', + 'styleAliases' + ]; + + var YAML_NODE_KINDS = [ + 'scalar', + 'sequence', + 'mapping' + ]; + + function compileStyleAliases(map) { + var result = {}; + + if (map !== null) { + Object.keys(map).forEach(function (style) { + map[style].forEach(function (alias) { + result[String(alias)] = style; + }); + }); + } + + return result; + } + + function Type$1(tag, options) { + options = options || {}; + + Object.keys(options).forEach(function (name) { + if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { + throw new exception('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); + } + }); + + // TODO: Add tag format check. + this.options = options; // keep original options in case user wants to extend this type later + this.tag = tag; + this.kind = options['kind'] || null; + this.resolve = options['resolve'] || function () { return true; }; + this.construct = options['construct'] || function (data) { return data; }; + this.instanceOf = options['instanceOf'] || null; + this.predicate = options['predicate'] || null; + this.represent = options['represent'] || null; + this.representName = options['representName'] || null; + this.defaultStyle = options['defaultStyle'] || null; + this.multi = options['multi'] || false; + this.styleAliases = compileStyleAliases(options['styleAliases'] || null); + + if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { + throw new exception('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); + } + } + + var type = Type$1; + + /*eslint-disable max-len*/ + + + + + + function compileList(schema, name) { + var result = []; + + schema[name].forEach(function (currentType) { + var newIndex = result.length; + + result.forEach(function (previousType, previousIndex) { + if (previousType.tag === currentType.tag && + previousType.kind === currentType.kind && + previousType.multi === currentType.multi) { + + newIndex = previousIndex; + } + }); + + result[newIndex] = currentType; + }); + + return result; + } + + + function compileMap(/* lists... */) { + var result = { + scalar: {}, + sequence: {}, + mapping: {}, + fallback: {}, + multi: { + scalar: [], + sequence: [], + mapping: [], + fallback: [] + } + }, index, length; + + function collectType(type) { + if (type.multi) { + result.multi[type.kind].push(type); + result.multi['fallback'].push(type); + } else { + result[type.kind][type.tag] = result['fallback'][type.tag] = type; + } + } + + for (index = 0, length = arguments.length; index < length; index += 1) { + arguments[index].forEach(collectType); + } + return result; + } + + + function Schema$1(definition) { + return this.extend(definition); + } + + + Schema$1.prototype.extend = function extend(definition) { + var implicit = []; + var explicit = []; + + if (definition instanceof type) { + // Schema.extend(type) + explicit.push(definition); + + } else if (Array.isArray(definition)) { + // Schema.extend([ type1, type2, ... ]) + explicit = explicit.concat(definition); + + } else if (definition && (Array.isArray(definition.implicit) || Array.isArray(definition.explicit))) { + // Schema.extend({ explicit: [ type1, type2, ... ], implicit: [ type1, type2, ... ] }) + if (definition.implicit) implicit = implicit.concat(definition.implicit); + if (definition.explicit) explicit = explicit.concat(definition.explicit); + + } else { + throw new exception('Schema.extend argument should be a Type, [ Type ], ' + + 'or a schema definition ({ implicit: [...], explicit: [...] })'); + } + + implicit.forEach(function (type$1) { + if (!(type$1 instanceof type)) { + throw new exception('Specified list of YAML types (or a single Type object) contains a non-Type object.'); + } + + if (type$1.loadKind && type$1.loadKind !== 'scalar') { + throw new exception('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.'); + } + + if (type$1.multi) { + throw new exception('There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.'); + } + }); + + explicit.forEach(function (type$1) { + if (!(type$1 instanceof type)) { + throw new exception('Specified list of YAML types (or a single Type object) contains a non-Type object.'); + } + }); + + var result = Object.create(Schema$1.prototype); + + result.implicit = (this.implicit || []).concat(implicit); + result.explicit = (this.explicit || []).concat(explicit); + + result.compiledImplicit = compileList(result, 'implicit'); + result.compiledExplicit = compileList(result, 'explicit'); + result.compiledTypeMap = compileMap(result.compiledImplicit, result.compiledExplicit); + + return result; + }; + + + var schema = Schema$1; + + var str = new type('tag:yaml.org,2002:str', { + kind: 'scalar', + construct: function (data) { return data !== null ? data : ''; } + }); + + var seq = new type('tag:yaml.org,2002:seq', { + kind: 'sequence', + construct: function (data) { return data !== null ? data : []; } + }); + + var map = new type('tag:yaml.org,2002:map', { + kind: 'mapping', + construct: function (data) { return data !== null ? data : {}; } + }); + + var failsafe = new schema({ + explicit: [ + str, + seq, + map + ] + }); + + function resolveYamlNull(data) { + if (data === null) return true; + + var max = data.length; + + return (max === 1 && data === '~') || + (max === 4 && (data === 'null' || data === 'Null' || data === 'NULL')); + } + + function constructYamlNull() { + return null; + } + + function isNull(object) { + return object === null; + } + + var _null = new type('tag:yaml.org,2002:null', { + kind: 'scalar', + resolve: resolveYamlNull, + construct: constructYamlNull, + predicate: isNull, + represent: { + canonical: function () { return '~'; }, + lowercase: function () { return 'null'; }, + uppercase: function () { return 'NULL'; }, + camelcase: function () { return 'Null'; }, + empty: function () { return ''; } + }, + defaultStyle: 'lowercase' + }); + + function resolveYamlBoolean(data) { + if (data === null) return false; + + var max = data.length; + + return (max === 4 && (data === 'true' || data === 'True' || data === 'TRUE')) || + (max === 5 && (data === 'false' || data === 'False' || data === 'FALSE')); + } + + function constructYamlBoolean(data) { + return data === 'true' || + data === 'True' || + data === 'TRUE'; + } + + function isBoolean(object) { + return Object.prototype.toString.call(object) === '[object Boolean]'; + } + + var bool = new type('tag:yaml.org,2002:bool', { + kind: 'scalar', + resolve: resolveYamlBoolean, + construct: constructYamlBoolean, + predicate: isBoolean, + represent: { + lowercase: function (object) { return object ? 'true' : 'false'; }, + uppercase: function (object) { return object ? 'TRUE' : 'FALSE'; }, + camelcase: function (object) { return object ? 'True' : 'False'; } + }, + defaultStyle: 'lowercase' + }); + + function isHexCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) || + ((0x41/* A */ <= c) && (c <= 0x46/* F */)) || + ((0x61/* a */ <= c) && (c <= 0x66/* f */)); + } + + function isOctCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x37/* 7 */)); + } + + function isDecCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)); + } + + function resolveYamlInteger(data) { + if (data === null) return false; + + var max = data.length, + index = 0, + hasDigits = false, + ch; + + if (!max) return false; + + ch = data[index]; + + // sign + if (ch === '-' || ch === '+') { + ch = data[++index]; + } + + if (ch === '0') { + // 0 + if (index + 1 === max) return true; + ch = data[++index]; + + // base 2, base 8, base 16 + + if (ch === 'b') { + // base 2 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (ch !== '0' && ch !== '1') return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + + + if (ch === 'x') { + // base 16 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isHexCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + + + if (ch === 'o') { + // base 8 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isOctCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + } + + // base 10 (except 0) + + // value should not start with `_`; + if (ch === '_') return false; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isDecCode(data.charCodeAt(index))) { + return false; + } + hasDigits = true; + } + + // Should have digits and should not end with `_` + if (!hasDigits || ch === '_') return false; + + return true; + } + + function constructYamlInteger(data) { + var value = data, sign = 1, ch; + + if (value.indexOf('_') !== -1) { + value = value.replace(/_/g, ''); + } + + ch = value[0]; + + if (ch === '-' || ch === '+') { + if (ch === '-') sign = -1; + value = value.slice(1); + ch = value[0]; + } + + if (value === '0') return 0; + + if (ch === '0') { + if (value[1] === 'b') return sign * parseInt(value.slice(2), 2); + if (value[1] === 'x') return sign * parseInt(value.slice(2), 16); + if (value[1] === 'o') return sign * parseInt(value.slice(2), 8); + } + + return sign * parseInt(value, 10); + } + + function isInteger(object) { + return (Object.prototype.toString.call(object)) === '[object Number]' && + (object % 1 === 0 && !common.isNegativeZero(object)); + } + + var int = new type('tag:yaml.org,2002:int', { + kind: 'scalar', + resolve: resolveYamlInteger, + construct: constructYamlInteger, + predicate: isInteger, + represent: { + binary: function (obj) { return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1); }, + octal: function (obj) { return obj >= 0 ? '0o' + obj.toString(8) : '-0o' + obj.toString(8).slice(1); }, + decimal: function (obj) { return obj.toString(10); }, + /* eslint-disable max-len */ + hexadecimal: function (obj) { return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1); } + }, + defaultStyle: 'decimal', + styleAliases: { + binary: [ 2, 'bin' ], + octal: [ 8, 'oct' ], + decimal: [ 10, 'dec' ], + hexadecimal: [ 16, 'hex' ] + } + }); + + var YAML_FLOAT_PATTERN = new RegExp( + // 2.5e4, 2.5 and integers + '^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?' + + // .2e4, .2 + // special case, seems not from spec + '|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?' + + // .inf + '|[-+]?\\.(?:inf|Inf|INF)' + + // .nan + '|\\.(?:nan|NaN|NAN))$'); + + function resolveYamlFloat(data) { + if (data === null) return false; + + if (!YAML_FLOAT_PATTERN.test(data) || + // Quick hack to not allow integers end with `_` + // Probably should update regexp & check speed + data[data.length - 1] === '_') { + return false; + } + + return true; + } + + function constructYamlFloat(data) { + var value, sign; + + value = data.replace(/_/g, '').toLowerCase(); + sign = value[0] === '-' ? -1 : 1; + + if ('+-'.indexOf(value[0]) >= 0) { + value = value.slice(1); + } + + if (value === '.inf') { + return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; + + } else if (value === '.nan') { + return NaN; + } + return sign * parseFloat(value, 10); + } + + + var SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/; + + function representYamlFloat(object, style) { + var res; + + if (isNaN(object)) { + switch (style) { + case 'lowercase': return '.nan'; + case 'uppercase': return '.NAN'; + case 'camelcase': return '.NaN'; + } + } else if (Number.POSITIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '.inf'; + case 'uppercase': return '.INF'; + case 'camelcase': return '.Inf'; + } + } else if (Number.NEGATIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '-.inf'; + case 'uppercase': return '-.INF'; + case 'camelcase': return '-.Inf'; + } + } else if (common.isNegativeZero(object)) { + return '-0.0'; + } + + res = object.toString(10); + + // JS stringifier can build scientific format without dots: 5e-100, + // while YAML requres dot: 5.e-100. Fix it with simple hack + + return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res; + } + + function isFloat(object) { + return (Object.prototype.toString.call(object) === '[object Number]') && + (object % 1 !== 0 || common.isNegativeZero(object)); + } + + var float = new type('tag:yaml.org,2002:float', { + kind: 'scalar', + resolve: resolveYamlFloat, + construct: constructYamlFloat, + predicate: isFloat, + represent: representYamlFloat, + defaultStyle: 'lowercase' + }); + + var json = failsafe.extend({ + implicit: [ + _null, + bool, + int, + float + ] + }); + + var core = json; + + var YAML_DATE_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9])' + // [2] month + '-([0-9][0-9])$'); // [3] day + + var YAML_TIMESTAMP_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9]?)' + // [2] month + '-([0-9][0-9]?)' + // [3] day + '(?:[Tt]|[ \\t]+)' + // ... + '([0-9][0-9]?)' + // [4] hour + ':([0-9][0-9])' + // [5] minute + ':([0-9][0-9])' + // [6] second + '(?:\\.([0-9]*))?' + // [7] fraction + '(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tz_hour + '(?::([0-9][0-9]))?))?$'); // [11] tz_minute + + function resolveYamlTimestamp(data) { + if (data === null) return false; + if (YAML_DATE_REGEXP.exec(data) !== null) return true; + if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true; + return false; + } + + function constructYamlTimestamp(data) { + var match, year, month, day, hour, minute, second, fraction = 0, + delta = null, tz_hour, tz_minute, date; + + match = YAML_DATE_REGEXP.exec(data); + if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data); + + if (match === null) throw new Error('Date resolve error'); + + // match: [1] year [2] month [3] day + + year = +(match[1]); + month = +(match[2]) - 1; // JS month starts with 0 + day = +(match[3]); + + if (!match[4]) { // no hour + return new Date(Date.UTC(year, month, day)); + } + + // match: [4] hour [5] minute [6] second [7] fraction + + hour = +(match[4]); + minute = +(match[5]); + second = +(match[6]); + + if (match[7]) { + fraction = match[7].slice(0, 3); + while (fraction.length < 3) { // milli-seconds + fraction += '0'; + } + fraction = +fraction; + } + + // match: [8] tz [9] tz_sign [10] tz_hour [11] tz_minute + + if (match[9]) { + tz_hour = +(match[10]); + tz_minute = +(match[11] || 0); + delta = (tz_hour * 60 + tz_minute) * 60000; // delta in mili-seconds + if (match[9] === '-') delta = -delta; + } + + date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction)); + + if (delta) date.setTime(date.getTime() - delta); + + return date; + } + + function representYamlTimestamp(object /*, style*/) { + return object.toISOString(); + } + + var timestamp = new type('tag:yaml.org,2002:timestamp', { + kind: 'scalar', + resolve: resolveYamlTimestamp, + construct: constructYamlTimestamp, + instanceOf: Date, + represent: representYamlTimestamp + }); + + function resolveYamlMerge(data) { + return data === '<<' || data === null; + } + + var merge = new type('tag:yaml.org,2002:merge', { + kind: 'scalar', + resolve: resolveYamlMerge + }); + + /*eslint-disable no-bitwise*/ + + + + + + // [ 64, 65, 66 ] -> [ padding, CR, LF ] + var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r'; + + + function resolveYamlBinary(data) { + if (data === null) return false; + + var code, idx, bitlen = 0, max = data.length, map = BASE64_MAP; + + // Convert one by one. + for (idx = 0; idx < max; idx++) { + code = map.indexOf(data.charAt(idx)); + + // Skip CR/LF + if (code > 64) continue; + + // Fail on illegal characters + if (code < 0) return false; + + bitlen += 6; + } + + // If there are any bits left, source was corrupted + return (bitlen % 8) === 0; + } + + function constructYamlBinary(data) { + var idx, tailbits, + input = data.replace(/[\r\n=]/g, ''), // remove CR/LF & padding to simplify scan + max = input.length, + map = BASE64_MAP, + bits = 0, + result = []; + + // Collect by 6*4 bits (3 bytes) + + for (idx = 0; idx < max; idx++) { + if ((idx % 4 === 0) && idx) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } + + bits = (bits << 6) | map.indexOf(input.charAt(idx)); + } + + // Dump tail + + tailbits = (max % 4) * 6; + + if (tailbits === 0) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } else if (tailbits === 18) { + result.push((bits >> 10) & 0xFF); + result.push((bits >> 2) & 0xFF); + } else if (tailbits === 12) { + result.push((bits >> 4) & 0xFF); + } + + return new Uint8Array(result); + } + + function representYamlBinary(object /*, style*/) { + var result = '', bits = 0, idx, tail, + max = object.length, + map = BASE64_MAP; + + // Convert every three bytes to 4 ASCII characters. + + for (idx = 0; idx < max; idx++) { + if ((idx % 3 === 0) && idx) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } + + bits = (bits << 8) + object[idx]; + } + + // Dump tail + + tail = max % 3; + + if (tail === 0) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } else if (tail === 2) { + result += map[(bits >> 10) & 0x3F]; + result += map[(bits >> 4) & 0x3F]; + result += map[(bits << 2) & 0x3F]; + result += map[64]; + } else if (tail === 1) { + result += map[(bits >> 2) & 0x3F]; + result += map[(bits << 4) & 0x3F]; + result += map[64]; + result += map[64]; + } + + return result; + } + + function isBinary(obj) { + return Object.prototype.toString.call(obj) === '[object Uint8Array]'; + } + + var binary = new type('tag:yaml.org,2002:binary', { + kind: 'scalar', + resolve: resolveYamlBinary, + construct: constructYamlBinary, + predicate: isBinary, + represent: representYamlBinary + }); + + var _hasOwnProperty$3 = Object.prototype.hasOwnProperty; + var _toString$2 = Object.prototype.toString; + + function resolveYamlOmap(data) { + if (data === null) return true; + + var objectKeys = [], index, length, pair, pairKey, pairHasKey, + object = data; + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + pairHasKey = false; + + if (_toString$2.call(pair) !== '[object Object]') return false; + + for (pairKey in pair) { + if (_hasOwnProperty$3.call(pair, pairKey)) { + if (!pairHasKey) pairHasKey = true; + else return false; + } + } + + if (!pairHasKey) return false; + + if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey); + else return false; + } + + return true; + } + + function constructYamlOmap(data) { + return data !== null ? data : []; + } + + var omap = new type('tag:yaml.org,2002:omap', { + kind: 'sequence', + resolve: resolveYamlOmap, + construct: constructYamlOmap + }); + + var _toString$1 = Object.prototype.toString; + + function resolveYamlPairs(data) { + if (data === null) return true; + + var index, length, pair, keys, result, + object = data; + + result = new Array(object.length); + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + + if (_toString$1.call(pair) !== '[object Object]') return false; + + keys = Object.keys(pair); + + if (keys.length !== 1) return false; + + result[index] = [ keys[0], pair[keys[0]] ]; + } + + return true; + } + + function constructYamlPairs(data) { + if (data === null) return []; + + var index, length, pair, keys, result, + object = data; + + result = new Array(object.length); + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + + keys = Object.keys(pair); + + result[index] = [ keys[0], pair[keys[0]] ]; + } + + return result; + } + + var pairs = new type('tag:yaml.org,2002:pairs', { + kind: 'sequence', + resolve: resolveYamlPairs, + construct: constructYamlPairs + }); + + var _hasOwnProperty$2 = Object.prototype.hasOwnProperty; + + function resolveYamlSet(data) { + if (data === null) return true; + + var key, object = data; + + for (key in object) { + if (_hasOwnProperty$2.call(object, key)) { + if (object[key] !== null) return false; + } + } + + return true; + } + + function constructYamlSet(data) { + return data !== null ? data : {}; + } + + var set = new type('tag:yaml.org,2002:set', { + kind: 'mapping', + resolve: resolveYamlSet, + construct: constructYamlSet + }); + + var _default = core.extend({ + implicit: [ + timestamp, + merge + ], + explicit: [ + binary, + omap, + pairs, + set + ] + }); + + /*eslint-disable max-len,no-use-before-define*/ + + + + + + + + var _hasOwnProperty$1 = Object.prototype.hasOwnProperty; + + + var CONTEXT_FLOW_IN = 1; + var CONTEXT_FLOW_OUT = 2; + var CONTEXT_BLOCK_IN = 3; + var CONTEXT_BLOCK_OUT = 4; + + + var CHOMPING_CLIP = 1; + var CHOMPING_STRIP = 2; + var CHOMPING_KEEP = 3; + + + var PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; + var PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/; + var PATTERN_FLOW_INDICATORS = /[,\[\]\{\}]/; + var PATTERN_TAG_HANDLE = /^(?:!|!!|![a-z\-]+!)$/i; + var PATTERN_TAG_URI = /^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i; + + + function _class(obj) { return Object.prototype.toString.call(obj); } + + function is_EOL(c) { + return (c === 0x0A/* LF */) || (c === 0x0D/* CR */); + } + + function is_WHITE_SPACE(c) { + return (c === 0x09/* Tab */) || (c === 0x20/* Space */); + } + + function is_WS_OR_EOL(c) { + return (c === 0x09/* Tab */) || + (c === 0x20/* Space */) || + (c === 0x0A/* LF */) || + (c === 0x0D/* CR */); + } + + function is_FLOW_INDICATOR(c) { + return c === 0x2C/* , */ || + c === 0x5B/* [ */ || + c === 0x5D/* ] */ || + c === 0x7B/* { */ || + c === 0x7D/* } */; + } + + function fromHexCode(c) { + var lc; + + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } + + /*eslint-disable no-bitwise*/ + lc = c | 0x20; + + if ((0x61/* a */ <= lc) && (lc <= 0x66/* f */)) { + return lc - 0x61 + 10; + } + + return -1; + } + + function escapedHexLen(c) { + if (c === 0x78/* x */) { return 2; } + if (c === 0x75/* u */) { return 4; } + if (c === 0x55/* U */) { return 8; } + return 0; + } + + function fromDecimalCode(c) { + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } + + return -1; + } + + function simpleEscapeSequence(c) { + /* eslint-disable indent */ + return (c === 0x30/* 0 */) ? '\x00' : + (c === 0x61/* a */) ? '\x07' : + (c === 0x62/* b */) ? '\x08' : + (c === 0x74/* t */) ? '\x09' : + (c === 0x09/* Tab */) ? '\x09' : + (c === 0x6E/* n */) ? '\x0A' : + (c === 0x76/* v */) ? '\x0B' : + (c === 0x66/* f */) ? '\x0C' : + (c === 0x72/* r */) ? '\x0D' : + (c === 0x65/* e */) ? '\x1B' : + (c === 0x20/* Space */) ? ' ' : + (c === 0x22/* " */) ? '\x22' : + (c === 0x2F/* / */) ? '/' : + (c === 0x5C/* \ */) ? '\x5C' : + (c === 0x4E/* N */) ? '\x85' : + (c === 0x5F/* _ */) ? '\xA0' : + (c === 0x4C/* L */) ? '\u2028' : + (c === 0x50/* P */) ? '\u2029' : ''; + } + + function charFromCodepoint(c) { + if (c <= 0xFFFF) { + return String.fromCharCode(c); + } + // Encode UTF-16 surrogate pair + // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF + return String.fromCharCode( + ((c - 0x010000) >> 10) + 0xD800, + ((c - 0x010000) & 0x03FF) + 0xDC00 + ); + } + + var simpleEscapeCheck = new Array(256); // integer, for fast access + var simpleEscapeMap = new Array(256); + for (var i = 0; i < 256; i++) { + simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0; + simpleEscapeMap[i] = simpleEscapeSequence(i); + } + + + function State$1(input, options) { + this.input = input; + + this.filename = options['filename'] || null; + this.schema = options['schema'] || _default; + this.onWarning = options['onWarning'] || null; + // (Hidden) Remove? makes the loader to expect YAML 1.1 documents + // if such documents have no explicit %YAML directive + this.legacy = options['legacy'] || false; + + this.json = options['json'] || false; + this.listener = options['listener'] || null; + + this.implicitTypes = this.schema.compiledImplicit; + this.typeMap = this.schema.compiledTypeMap; + + this.length = input.length; + this.position = 0; + this.line = 0; + this.lineStart = 0; + this.lineIndent = 0; + + // position of first leading tab in the current line, + // used to make sure there are no tabs in the indentation + this.firstTabInLine = -1; + + this.documents = []; + + /* + this.version; + this.checkLineBreaks; + this.tagMap; + this.anchorMap; + this.tag; + this.anchor; + this.kind; + this.result;*/ + + } + + + function generateError(state, message) { + var mark = { + name: state.filename, + buffer: state.input.slice(0, -1), // omit trailing \0 + position: state.position, + line: state.line, + column: state.position - state.lineStart + }; + + mark.snippet = snippet(mark); + + return new exception(message, mark); + } + + function throwError(state, message) { + throw generateError(state, message); + } + + function throwWarning(state, message) { + if (state.onWarning) { + state.onWarning.call(null, generateError(state, message)); + } + } + + + var directiveHandlers = { + + YAML: function handleYamlDirective(state, name, args) { + + var match, major, minor; + + if (state.version !== null) { + throwError(state, 'duplication of %YAML directive'); + } + + if (args.length !== 1) { + throwError(state, 'YAML directive accepts exactly one argument'); + } + + match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]); + + if (match === null) { + throwError(state, 'ill-formed argument of the YAML directive'); + } + + major = parseInt(match[1], 10); + minor = parseInt(match[2], 10); + + if (major !== 1) { + throwError(state, 'unacceptable YAML version of the document'); + } + + state.version = args[0]; + state.checkLineBreaks = (minor < 2); + + if (minor !== 1 && minor !== 2) { + throwWarning(state, 'unsupported YAML version of the document'); + } + }, + + TAG: function handleTagDirective(state, name, args) { + + var handle, prefix; + + if (args.length !== 2) { + throwError(state, 'TAG directive accepts exactly two arguments'); + } + + handle = args[0]; + prefix = args[1]; + + if (!PATTERN_TAG_HANDLE.test(handle)) { + throwError(state, 'ill-formed tag handle (first argument) of the TAG directive'); + } + + if (_hasOwnProperty$1.call(state.tagMap, handle)) { + throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle'); + } + + if (!PATTERN_TAG_URI.test(prefix)) { + throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive'); + } + + try { + prefix = decodeURIComponent(prefix); + } catch (err) { + throwError(state, 'tag prefix is malformed: ' + prefix); + } + + state.tagMap[handle] = prefix; + } + }; + + + function captureSegment(state, start, end, checkJson) { + var _position, _length, _character, _result; + + if (start < end) { + _result = state.input.slice(start, end); + + if (checkJson) { + for (_position = 0, _length = _result.length; _position < _length; _position += 1) { + _character = _result.charCodeAt(_position); + if (!(_character === 0x09 || + (0x20 <= _character && _character <= 0x10FFFF))) { + throwError(state, 'expected valid JSON character'); + } + } + } else if (PATTERN_NON_PRINTABLE.test(_result)) { + throwError(state, 'the stream contains non-printable characters'); + } + + state.result += _result; + } + } + + function mergeMappings(state, destination, source, overridableKeys) { + var sourceKeys, key, index, quantity; + + if (!common.isObject(source)) { + throwError(state, 'cannot merge mappings; the provided source object is unacceptable'); + } + + sourceKeys = Object.keys(source); + + for (index = 0, quantity = sourceKeys.length; index < quantity; index += 1) { + key = sourceKeys[index]; + + if (!_hasOwnProperty$1.call(destination, key)) { + destination[key] = source[key]; + overridableKeys[key] = true; + } + } + } + + function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, + startLine, startLineStart, startPos) { + + var index, quantity; + + // The output is a plain object here, so keys can only be strings. + // We need to convert keyNode to a string, but doing so can hang the process + // (deeply nested arrays that explode exponentially using aliases). + if (Array.isArray(keyNode)) { + keyNode = Array.prototype.slice.call(keyNode); + + for (index = 0, quantity = keyNode.length; index < quantity; index += 1) { + if (Array.isArray(keyNode[index])) { + throwError(state, 'nested arrays are not supported inside keys'); + } + + if (typeof keyNode === 'object' && _class(keyNode[index]) === '[object Object]') { + keyNode[index] = '[object Object]'; + } + } + } + + // Avoid code execution in load() via toString property + // (still use its own toString for arrays, timestamps, + // and whatever user schema extensions happen to have @@toStringTag) + if (typeof keyNode === 'object' && _class(keyNode) === '[object Object]') { + keyNode = '[object Object]'; + } + + + keyNode = String(keyNode); + + if (_result === null) { + _result = {}; + } + + if (keyTag === 'tag:yaml.org,2002:merge') { + if (Array.isArray(valueNode)) { + for (index = 0, quantity = valueNode.length; index < quantity; index += 1) { + mergeMappings(state, _result, valueNode[index], overridableKeys); + } + } else { + mergeMappings(state, _result, valueNode, overridableKeys); + } + } else { + if (!state.json && + !_hasOwnProperty$1.call(overridableKeys, keyNode) && + _hasOwnProperty$1.call(_result, keyNode)) { + state.line = startLine || state.line; + state.lineStart = startLineStart || state.lineStart; + state.position = startPos || state.position; + throwError(state, 'duplicated mapping key'); + } + + // used for this specific key only because Object.defineProperty is slow + if (keyNode === '__proto__') { + Object.defineProperty(_result, keyNode, { + configurable: true, + enumerable: true, + writable: true, + value: valueNode + }); + } else { + _result[keyNode] = valueNode; + } + delete overridableKeys[keyNode]; + } + + return _result; + } + + function readLineBreak(state) { + var ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x0A/* LF */) { + state.position++; + } else if (ch === 0x0D/* CR */) { + state.position++; + if (state.input.charCodeAt(state.position) === 0x0A/* LF */) { + state.position++; + } + } else { + throwError(state, 'a line break is expected'); + } + + state.line += 1; + state.lineStart = state.position; + state.firstTabInLine = -1; + } + + function skipSeparationSpace(state, allowComments, checkIndent) { + var lineBreaks = 0, + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + if (ch === 0x09/* Tab */ && state.firstTabInLine === -1) { + state.firstTabInLine = state.position; + } + ch = state.input.charCodeAt(++state.position); + } + + if (allowComments && ch === 0x23/* # */) { + do { + ch = state.input.charCodeAt(++state.position); + } while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && ch !== 0); + } + + if (is_EOL(ch)) { + readLineBreak(state); + + ch = state.input.charCodeAt(state.position); + lineBreaks++; + state.lineIndent = 0; + + while (ch === 0x20/* Space */) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + } else { + break; + } + } + + if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) { + throwWarning(state, 'deficient indentation'); + } + + return lineBreaks; + } + + function testDocumentSeparator(state) { + var _position = state.position, + ch; + + ch = state.input.charCodeAt(_position); + + // Condition state.position === state.lineStart is tested + // in parent on each call, for efficiency. No needs to test here again. + if ((ch === 0x2D/* - */ || ch === 0x2E/* . */) && + ch === state.input.charCodeAt(_position + 1) && + ch === state.input.charCodeAt(_position + 2)) { + + _position += 3; + + ch = state.input.charCodeAt(_position); + + if (ch === 0 || is_WS_OR_EOL(ch)) { + return true; + } + } + + return false; + } + + function writeFoldedLines(state, count) { + if (count === 1) { + state.result += ' '; + } else if (count > 1) { + state.result += common.repeat('\n', count - 1); + } + } + + + function readPlainScalar(state, nodeIndent, withinFlowCollection) { + var preceding, + following, + captureStart, + captureEnd, + hasPendingContent, + _line, + _lineStart, + _lineIndent, + _kind = state.kind, + _result = state.result, + ch; + + ch = state.input.charCodeAt(state.position); + + if (is_WS_OR_EOL(ch) || + is_FLOW_INDICATOR(ch) || + ch === 0x23/* # */ || + ch === 0x26/* & */ || + ch === 0x2A/* * */ || + ch === 0x21/* ! */ || + ch === 0x7C/* | */ || + ch === 0x3E/* > */ || + ch === 0x27/* ' */ || + ch === 0x22/* " */ || + ch === 0x25/* % */ || + ch === 0x40/* @ */ || + ch === 0x60/* ` */) { + return false; + } + + if (ch === 0x3F/* ? */ || ch === 0x2D/* - */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + return false; + } + } + + state.kind = 'scalar'; + state.result = ''; + captureStart = captureEnd = state.position; + hasPendingContent = false; + + while (ch !== 0) { + if (ch === 0x3A/* : */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + break; + } + + } else if (ch === 0x23/* # */) { + preceding = state.input.charCodeAt(state.position - 1); + + if (is_WS_OR_EOL(preceding)) { + break; + } + + } else if ((state.position === state.lineStart && testDocumentSeparator(state)) || + withinFlowCollection && is_FLOW_INDICATOR(ch)) { + break; + + } else if (is_EOL(ch)) { + _line = state.line; + _lineStart = state.lineStart; + _lineIndent = state.lineIndent; + skipSeparationSpace(state, false, -1); + + if (state.lineIndent >= nodeIndent) { + hasPendingContent = true; + ch = state.input.charCodeAt(state.position); + continue; + } else { + state.position = captureEnd; + state.line = _line; + state.lineStart = _lineStart; + state.lineIndent = _lineIndent; + break; + } + } + + if (hasPendingContent) { + captureSegment(state, captureStart, captureEnd, false); + writeFoldedLines(state, state.line - _line); + captureStart = captureEnd = state.position; + hasPendingContent = false; + } + + if (!is_WHITE_SPACE(ch)) { + captureEnd = state.position + 1; + } + + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, captureEnd, false); + + if (state.result) { + return true; + } + + state.kind = _kind; + state.result = _result; + return false; + } + + function readSingleQuotedScalar(state, nodeIndent) { + var ch, + captureStart, captureEnd; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x27/* ' */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x27/* ' */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x27/* ' */) { + captureStart = state.position; + state.position++; + captureEnd = state.position; + } else { + return true; + } + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a single quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a single quoted scalar'); + } + + function readDoubleQuotedScalar(state, nodeIndent) { + var captureStart, + captureEnd, + hexLength, + hexResult, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x22/* " */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x22/* " */) { + captureSegment(state, captureStart, state.position, true); + state.position++; + return true; + + } else if (ch === 0x5C/* \ */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (is_EOL(ch)) { + skipSeparationSpace(state, false, nodeIndent); + + // TODO: rework to inline fn with no type cast? + } else if (ch < 256 && simpleEscapeCheck[ch]) { + state.result += simpleEscapeMap[ch]; + state.position++; + + } else if ((tmp = escapedHexLen(ch)) > 0) { + hexLength = tmp; + hexResult = 0; + + for (; hexLength > 0; hexLength--) { + ch = state.input.charCodeAt(++state.position); + + if ((tmp = fromHexCode(ch)) >= 0) { + hexResult = (hexResult << 4) + tmp; + + } else { + throwError(state, 'expected hexadecimal character'); + } + } + + state.result += charFromCodepoint(hexResult); + + state.position++; + + } else { + throwError(state, 'unknown escape sequence'); + } + + captureStart = captureEnd = state.position; + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a double quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a double quoted scalar'); + } + + function readFlowCollection(state, nodeIndent) { + var readNext = true, + _line, + _lineStart, + _pos, + _tag = state.tag, + _result, + _anchor = state.anchor, + following, + terminator, + isPair, + isExplicitPair, + isMapping, + overridableKeys = Object.create(null), + keyNode, + keyTag, + valueNode, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x5B/* [ */) { + terminator = 0x5D;/* ] */ + isMapping = false; + _result = []; + } else if (ch === 0x7B/* { */) { + terminator = 0x7D;/* } */ + isMapping = true; + _result = {}; + } else { + return false; + } + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(++state.position); + + while (ch !== 0) { + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === terminator) { + state.position++; + state.tag = _tag; + state.anchor = _anchor; + state.kind = isMapping ? 'mapping' : 'sequence'; + state.result = _result; + return true; + } else if (!readNext) { + throwError(state, 'missed comma between flow collection entries'); + } else if (ch === 0x2C/* , */) { + // "flow collection entries can never be completely empty", as per YAML 1.2, section 7.4 + throwError(state, "expected the node content, but found ','"); + } + + keyTag = keyNode = valueNode = null; + isPair = isExplicitPair = false; + + if (ch === 0x3F/* ? */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following)) { + isPair = isExplicitPair = true; + state.position++; + skipSeparationSpace(state, true, nodeIndent); + } + } + + _line = state.line; // Save the current line. + _lineStart = state.lineStart; + _pos = state.position; + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + keyTag = state.tag; + keyNode = state.result; + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if ((isExplicitPair || state.line === _line) && ch === 0x3A/* : */) { + isPair = true; + ch = state.input.charCodeAt(++state.position); + skipSeparationSpace(state, true, nodeIndent); + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + valueNode = state.result; + } + + if (isMapping) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos); + } else if (isPair) { + _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos)); + } else { + _result.push(keyNode); + } + + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x2C/* , */) { + readNext = true; + ch = state.input.charCodeAt(++state.position); + } else { + readNext = false; + } + } + + throwError(state, 'unexpected end of the stream within a flow collection'); + } + + function readBlockScalar(state, nodeIndent) { + var captureStart, + folding, + chomping = CHOMPING_CLIP, + didReadContent = false, + detectedIndent = false, + textIndent = nodeIndent, + emptyLines = 0, + atMoreIndented = false, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x7C/* | */) { + folding = false; + } else if (ch === 0x3E/* > */) { + folding = true; + } else { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + + while (ch !== 0) { + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { + if (CHOMPING_CLIP === chomping) { + chomping = (ch === 0x2B/* + */) ? CHOMPING_KEEP : CHOMPING_STRIP; + } else { + throwError(state, 'repeat of a chomping mode identifier'); + } + + } else if ((tmp = fromDecimalCode(ch)) >= 0) { + if (tmp === 0) { + throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one'); + } else if (!detectedIndent) { + textIndent = nodeIndent + tmp - 1; + detectedIndent = true; + } else { + throwError(state, 'repeat of an indentation width identifier'); + } + + } else { + break; + } + } + + if (is_WHITE_SPACE(ch)) { + do { ch = state.input.charCodeAt(++state.position); } + while (is_WHITE_SPACE(ch)); + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (!is_EOL(ch) && (ch !== 0)); + } + } + + while (ch !== 0) { + readLineBreak(state); + state.lineIndent = 0; + + ch = state.input.charCodeAt(state.position); + + while ((!detectedIndent || state.lineIndent < textIndent) && + (ch === 0x20/* Space */)) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + + if (!detectedIndent && state.lineIndent > textIndent) { + textIndent = state.lineIndent; + } + + if (is_EOL(ch)) { + emptyLines++; + continue; + } + + // End of the scalar. + if (state.lineIndent < textIndent) { + + // Perform the chomping. + if (chomping === CHOMPING_KEEP) { + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } else if (chomping === CHOMPING_CLIP) { + if (didReadContent) { // i.e. only if the scalar is not empty. + state.result += '\n'; + } + } + + // Break this `while` cycle and go to the funciton's epilogue. + break; + } + + // Folded style: use fancy rules to handle line breaks. + if (folding) { + + // Lines starting with white space characters (more-indented lines) are not folded. + if (is_WHITE_SPACE(ch)) { + atMoreIndented = true; + // except for the first content line (cf. Example 8.1) + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + + // End of more-indented block. + } else if (atMoreIndented) { + atMoreIndented = false; + state.result += common.repeat('\n', emptyLines + 1); + + // Just one line break - perceive as the same line. + } else if (emptyLines === 0) { + if (didReadContent) { // i.e. only if we have already read some scalar content. + state.result += ' '; + } + + // Several line breaks - perceive as different lines. + } else { + state.result += common.repeat('\n', emptyLines); + } + + // Literal style: just add exact number of line breaks between content lines. + } else { + // Keep all line breaks except the header line break. + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } + + didReadContent = true; + detectedIndent = true; + emptyLines = 0; + captureStart = state.position; + + while (!is_EOL(ch) && (ch !== 0)) { + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, state.position, false); + } + + return true; + } + + function readBlockSequence(state, nodeIndent) { + var _line, + _tag = state.tag, + _anchor = state.anchor, + _result = [], + following, + detected = false, + ch; + + // there is a leading tab before this token, so it can't be a block sequence/mapping; + // it can still be flow sequence/mapping or a scalar + if (state.firstTabInLine !== -1) return false; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + if (state.firstTabInLine !== -1) { + state.position = state.firstTabInLine; + throwError(state, 'tab characters must not be used in indentation'); + } + + if (ch !== 0x2D/* - */) { + break; + } + + following = state.input.charCodeAt(state.position + 1); + + if (!is_WS_OR_EOL(following)) { + break; + } + + detected = true; + state.position++; + + if (skipSeparationSpace(state, true, -1)) { + if (state.lineIndent <= nodeIndent) { + _result.push(null); + ch = state.input.charCodeAt(state.position); + continue; + } + } + + _line = state.line; + composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true); + _result.push(state.result); + skipSeparationSpace(state, true, -1); + + ch = state.input.charCodeAt(state.position); + + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a sequence entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'sequence'; + state.result = _result; + return true; + } + return false; + } + + function readBlockMapping(state, nodeIndent, flowIndent) { + var following, + allowCompact, + _line, + _keyLine, + _keyLineStart, + _keyPos, + _tag = state.tag, + _anchor = state.anchor, + _result = {}, + overridableKeys = Object.create(null), + keyTag = null, + keyNode = null, + valueNode = null, + atExplicitKey = false, + detected = false, + ch; + + // there is a leading tab before this token, so it can't be a block sequence/mapping; + // it can still be flow sequence/mapping or a scalar + if (state.firstTabInLine !== -1) return false; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + if (!atExplicitKey && state.firstTabInLine !== -1) { + state.position = state.firstTabInLine; + throwError(state, 'tab characters must not be used in indentation'); + } + + following = state.input.charCodeAt(state.position + 1); + _line = state.line; // Save the current line. + + // + // Explicit notation case. There are two separate blocks: + // first for the key (denoted by "?") and second for the value (denoted by ":") + // + if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && is_WS_OR_EOL(following)) { + + if (ch === 0x3F/* ? */) { + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + + detected = true; + atExplicitKey = true; + allowCompact = true; + + } else if (atExplicitKey) { + // i.e. 0x3A/* : */ === character after the explicit key. + atExplicitKey = false; + allowCompact = true; + + } else { + throwError(state, 'incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line'); + } + + state.position += 1; + ch = following; + + // + // Implicit notation case. Flow-style node as the key first, then ":", and the value. + // + } else { + _keyLine = state.line; + _keyLineStart = state.lineStart; + _keyPos = state.position; + + if (!composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) { + // Neither implicit nor explicit notation. + // Reading is done. Go to the epilogue. + break; + } + + if (state.line === _line) { + ch = state.input.charCodeAt(state.position); + + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (ch === 0x3A/* : */) { + ch = state.input.charCodeAt(++state.position); + + if (!is_WS_OR_EOL(ch)) { + throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping'); + } + + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + + detected = true; + atExplicitKey = false; + allowCompact = false; + keyTag = state.tag; + keyNode = state.result; + + } else if (detected) { + throwError(state, 'can not read an implicit mapping pair; a colon is missed'); + + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + + } else if (detected) { + throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key'); + + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + } + + // + // Common reading code for both explicit and implicit notations. + // + if (state.line === _line || state.lineIndent > nodeIndent) { + if (atExplicitKey) { + _keyLine = state.line; + _keyLineStart = state.lineStart; + _keyPos = state.position; + } + + if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) { + if (atExplicitKey) { + keyNode = state.result; + } else { + valueNode = state.result; + } + } + + if (!atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + } + + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a mapping entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + + // + // Epilogue. + // + + // Special case: last mapping's node contains only the key in explicit notation. + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + } + + // Expose the resulting mapping. + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'mapping'; + state.result = _result; + } + + return detected; + } + + function readTagProperty(state) { + var _position, + isVerbatim = false, + isNamed = false, + tagHandle, + tagName, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x21/* ! */) return false; + + if (state.tag !== null) { + throwError(state, 'duplication of a tag property'); + } + + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x3C/* < */) { + isVerbatim = true; + ch = state.input.charCodeAt(++state.position); + + } else if (ch === 0x21/* ! */) { + isNamed = true; + tagHandle = '!!'; + ch = state.input.charCodeAt(++state.position); + + } else { + tagHandle = '!'; + } + + _position = state.position; + + if (isVerbatim) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && ch !== 0x3E/* > */); + + if (state.position < state.length) { + tagName = state.input.slice(_position, state.position); + ch = state.input.charCodeAt(++state.position); + } else { + throwError(state, 'unexpected end of the stream within a verbatim tag'); + } + } else { + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + + if (ch === 0x21/* ! */) { + if (!isNamed) { + tagHandle = state.input.slice(_position - 1, state.position + 1); + + if (!PATTERN_TAG_HANDLE.test(tagHandle)) { + throwError(state, 'named tag handle cannot contain such characters'); + } + + isNamed = true; + _position = state.position + 1; + } else { + throwError(state, 'tag suffix cannot contain exclamation marks'); + } + } + + ch = state.input.charCodeAt(++state.position); + } + + tagName = state.input.slice(_position, state.position); + + if (PATTERN_FLOW_INDICATORS.test(tagName)) { + throwError(state, 'tag suffix cannot contain flow indicator characters'); + } + } + + if (tagName && !PATTERN_TAG_URI.test(tagName)) { + throwError(state, 'tag name cannot contain such characters: ' + tagName); + } + + try { + tagName = decodeURIComponent(tagName); + } catch (err) { + throwError(state, 'tag name is malformed: ' + tagName); + } + + if (isVerbatim) { + state.tag = tagName; + + } else if (_hasOwnProperty$1.call(state.tagMap, tagHandle)) { + state.tag = state.tagMap[tagHandle] + tagName; + + } else if (tagHandle === '!') { + state.tag = '!' + tagName; + + } else if (tagHandle === '!!') { + state.tag = 'tag:yaml.org,2002:' + tagName; + + } else { + throwError(state, 'undeclared tag handle "' + tagHandle + '"'); + } + + return true; + } + + function readAnchorProperty(state) { + var _position, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x26/* & */) return false; + + if (state.anchor !== null) { + throwError(state, 'duplication of an anchor property'); + } + + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (state.position === _position) { + throwError(state, 'name of an anchor node must contain at least one character'); + } + + state.anchor = state.input.slice(_position, state.position); + return true; + } + + function readAlias(state) { + var _position, alias, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x2A/* * */) return false; + + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (state.position === _position) { + throwError(state, 'name of an alias node must contain at least one character'); + } + + alias = state.input.slice(_position, state.position); + + if (!_hasOwnProperty$1.call(state.anchorMap, alias)) { + throwError(state, 'unidentified alias "' + alias + '"'); + } + + state.result = state.anchorMap[alias]; + skipSeparationSpace(state, true, -1); + return true; + } + + function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) { + var allowBlockStyles, + allowBlockScalars, + allowBlockCollections, + indentStatus = 1, // 1: this>parent, 0: this=parent, -1: this parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } + } + + if (indentStatus === 1) { + while (readTagProperty(state) || readAnchorProperty(state)) { + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + allowBlockCollections = allowBlockStyles; + + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } else { + allowBlockCollections = false; + } + } + } + + if (allowBlockCollections) { + allowBlockCollections = atNewLine || allowCompact; + } + + if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) { + if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) { + flowIndent = parentIndent; + } else { + flowIndent = parentIndent + 1; + } + + blockIndent = state.position - state.lineStart; + + if (indentStatus === 1) { + if (allowBlockCollections && + (readBlockSequence(state, blockIndent) || + readBlockMapping(state, blockIndent, flowIndent)) || + readFlowCollection(state, flowIndent)) { + hasContent = true; + } else { + if ((allowBlockScalars && readBlockScalar(state, flowIndent)) || + readSingleQuotedScalar(state, flowIndent) || + readDoubleQuotedScalar(state, flowIndent)) { + hasContent = true; + + } else if (readAlias(state)) { + hasContent = true; + + if (state.tag !== null || state.anchor !== null) { + throwError(state, 'alias node should not have any properties'); + } + + } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) { + hasContent = true; + + if (state.tag === null) { + state.tag = '?'; + } + } + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } else if (indentStatus === 0) { + // Special case: block sequences are allowed to have same indentation level as the parent. + // http://www.yaml.org/spec/1.2/spec.html#id2799784 + hasContent = allowBlockCollections && readBlockSequence(state, blockIndent); + } + } + + if (state.tag === null) { + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + + } else if (state.tag === '?') { + // Implicit resolving is not allowed for non-scalar types, and '?' + // non-specific tag is only automatically assigned to plain scalars. + // + // We only need to check kind conformity in case user explicitly assigns '?' + // tag, for example like this: "! [0]" + // + if (state.result !== null && state.kind !== 'scalar') { + throwError(state, 'unacceptable node kind for ! tag; it should be "scalar", not "' + state.kind + '"'); + } + + for (typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) { + type = state.implicitTypes[typeIndex]; + + if (type.resolve(state.result)) { // `state.result` updated in resolver if matched + state.result = type.construct(state.result); + state.tag = type.tag; + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + break; + } + } + } else if (state.tag !== '!') { + if (_hasOwnProperty$1.call(state.typeMap[state.kind || 'fallback'], state.tag)) { + type = state.typeMap[state.kind || 'fallback'][state.tag]; + } else { + // looking for multi type + type = null; + typeList = state.typeMap.multi[state.kind || 'fallback']; + + for (typeIndex = 0, typeQuantity = typeList.length; typeIndex < typeQuantity; typeIndex += 1) { + if (state.tag.slice(0, typeList[typeIndex].tag.length) === typeList[typeIndex].tag) { + type = typeList[typeIndex]; + break; + } + } + } + + if (!type) { + throwError(state, 'unknown tag !<' + state.tag + '>'); + } + + if (state.result !== null && type.kind !== state.kind) { + throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"'); + } + + if (!type.resolve(state.result, state.tag)) { // `state.result` updated in resolver if matched + throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag'); + } else { + state.result = type.construct(state.result, state.tag); + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } + + if (state.listener !== null) { + state.listener('close', state); + } + return state.tag !== null || state.anchor !== null || hasContent; + } + + function readDocument(state) { + var documentStart = state.position, + _position, + directiveName, + directiveArgs, + hasDirectives = false, + ch; + + state.version = null; + state.checkLineBreaks = state.legacy; + state.tagMap = Object.create(null); + state.anchorMap = Object.create(null); + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + skipSeparationSpace(state, true, -1); + + ch = state.input.charCodeAt(state.position); + + if (state.lineIndent > 0 || ch !== 0x25/* % */) { + break; + } + + hasDirectives = true; + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + directiveName = state.input.slice(_position, state.position); + directiveArgs = []; + + if (directiveName.length < 1) { + throwError(state, 'directive name must not be less than one character in length'); + } + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && !is_EOL(ch)); + break; + } + + if (is_EOL(ch)) break; + + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + directiveArgs.push(state.input.slice(_position, state.position)); + } + + if (ch !== 0) readLineBreak(state); + + if (_hasOwnProperty$1.call(directiveHandlers, directiveName)) { + directiveHandlers[directiveName](state, directiveName, directiveArgs); + } else { + throwWarning(state, 'unknown document directive "' + directiveName + '"'); + } + } + + skipSeparationSpace(state, true, -1); + + if (state.lineIndent === 0 && + state.input.charCodeAt(state.position) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 1) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 2) === 0x2D/* - */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + + } else if (hasDirectives) { + throwError(state, 'directives end mark is expected'); + } + + composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true); + skipSeparationSpace(state, true, -1); + + if (state.checkLineBreaks && + PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) { + throwWarning(state, 'non-ASCII line breaks are interpreted as content'); + } + + state.documents.push(state.result); + + if (state.position === state.lineStart && testDocumentSeparator(state)) { + + if (state.input.charCodeAt(state.position) === 0x2E/* . */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + } + return; + } + + if (state.position < (state.length - 1)) { + throwError(state, 'end of the stream or a document separator is expected'); + } else { + return; + } + } + + + function loadDocuments(input, options) { + input = String(input); + options = options || {}; + + if (input.length !== 0) { + + // Add tailing `\n` if not exists + if (input.charCodeAt(input.length - 1) !== 0x0A/* LF */ && + input.charCodeAt(input.length - 1) !== 0x0D/* CR */) { + input += '\n'; + } + + // Strip BOM + if (input.charCodeAt(0) === 0xFEFF) { + input = input.slice(1); + } + } + + var state = new State$1(input, options); + + var nullpos = input.indexOf('\0'); + + if (nullpos !== -1) { + state.position = nullpos; + throwError(state, 'null byte is not allowed in input'); + } + + // Use 0 as string terminator. That significantly simplifies bounds check. + state.input += '\0'; + + while (state.input.charCodeAt(state.position) === 0x20/* Space */) { + state.lineIndent += 1; + state.position += 1; + } + + while (state.position < (state.length - 1)) { + readDocument(state); + } + + return state.documents; + } + + + function loadAll$1(input, iterator, options) { + if (iterator !== null && typeof iterator === 'object' && typeof options === 'undefined') { + options = iterator; + iterator = null; + } + + var documents = loadDocuments(input, options); + + if (typeof iterator !== 'function') { + return documents; + } + + for (var index = 0, length = documents.length; index < length; index += 1) { + iterator(documents[index]); + } + } + + + function load$1(input, options) { + var documents = loadDocuments(input, options); + + if (documents.length === 0) { + /*eslint-disable no-undefined*/ + return undefined; + } else if (documents.length === 1) { + return documents[0]; + } + throw new exception('expected a single document in the stream, but found more'); + } + + + var loadAll_1 = loadAll$1; + var load_1 = load$1; + + var loader = { + loadAll: loadAll_1, + load: load_1 + }; + + /*eslint-disable no-use-before-define*/ + + + + + + var _toString = Object.prototype.toString; + var _hasOwnProperty = Object.prototype.hasOwnProperty; + + var CHAR_BOM = 0xFEFF; + var CHAR_TAB = 0x09; /* Tab */ + var CHAR_LINE_FEED = 0x0A; /* LF */ + var CHAR_CARRIAGE_RETURN = 0x0D; /* CR */ + var CHAR_SPACE = 0x20; /* Space */ + var CHAR_EXCLAMATION = 0x21; /* ! */ + var CHAR_DOUBLE_QUOTE = 0x22; /* " */ + var CHAR_SHARP = 0x23; /* # */ + var CHAR_PERCENT = 0x25; /* % */ + var CHAR_AMPERSAND = 0x26; /* & */ + var CHAR_SINGLE_QUOTE = 0x27; /* ' */ + var CHAR_ASTERISK = 0x2A; /* * */ + var CHAR_COMMA = 0x2C; /* , */ + var CHAR_MINUS = 0x2D; /* - */ + var CHAR_COLON = 0x3A; /* : */ + var CHAR_EQUALS = 0x3D; /* = */ + var CHAR_GREATER_THAN = 0x3E; /* > */ + var CHAR_QUESTION = 0x3F; /* ? */ + var CHAR_COMMERCIAL_AT = 0x40; /* @ */ + var CHAR_LEFT_SQUARE_BRACKET = 0x5B; /* [ */ + var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */ + var CHAR_GRAVE_ACCENT = 0x60; /* ` */ + var CHAR_LEFT_CURLY_BRACKET = 0x7B; /* { */ + var CHAR_VERTICAL_LINE = 0x7C; /* | */ + var CHAR_RIGHT_CURLY_BRACKET = 0x7D; /* } */ + + var ESCAPE_SEQUENCES = {}; + + ESCAPE_SEQUENCES[0x00] = '\\0'; + ESCAPE_SEQUENCES[0x07] = '\\a'; + ESCAPE_SEQUENCES[0x08] = '\\b'; + ESCAPE_SEQUENCES[0x09] = '\\t'; + ESCAPE_SEQUENCES[0x0A] = '\\n'; + ESCAPE_SEQUENCES[0x0B] = '\\v'; + ESCAPE_SEQUENCES[0x0C] = '\\f'; + ESCAPE_SEQUENCES[0x0D] = '\\r'; + ESCAPE_SEQUENCES[0x1B] = '\\e'; + ESCAPE_SEQUENCES[0x22] = '\\"'; + ESCAPE_SEQUENCES[0x5C] = '\\\\'; + ESCAPE_SEQUENCES[0x85] = '\\N'; + ESCAPE_SEQUENCES[0xA0] = '\\_'; + ESCAPE_SEQUENCES[0x2028] = '\\L'; + ESCAPE_SEQUENCES[0x2029] = '\\P'; + + var DEPRECATED_BOOLEANS_SYNTAX = [ + 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON', + 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF' + ]; + + var DEPRECATED_BASE60_SYNTAX = /^[-+]?[0-9_]+(?::[0-9_]+)+(?:\.[0-9_]*)?$/; + + function compileStyleMap(schema, map) { + var result, keys, index, length, tag, style, type; + + if (map === null) return {}; + + result = {}; + keys = Object.keys(map); + + for (index = 0, length = keys.length; index < length; index += 1) { + tag = keys[index]; + style = String(map[tag]); + + if (tag.slice(0, 2) === '!!') { + tag = 'tag:yaml.org,2002:' + tag.slice(2); + } + type = schema.compiledTypeMap['fallback'][tag]; + + if (type && _hasOwnProperty.call(type.styleAliases, style)) { + style = type.styleAliases[style]; + } + + result[tag] = style; + } + + return result; + } + + function encodeHex(character) { + var string, handle, length; + + string = character.toString(16).toUpperCase(); + + if (character <= 0xFF) { + handle = 'x'; + length = 2; + } else if (character <= 0xFFFF) { + handle = 'u'; + length = 4; + } else if (character <= 0xFFFFFFFF) { + handle = 'U'; + length = 8; + } else { + throw new exception('code point within a string may not be greater than 0xFFFFFFFF'); + } + + return '\\' + handle + common.repeat('0', length - string.length) + string; + } + + + var QUOTING_TYPE_SINGLE = 1, + QUOTING_TYPE_DOUBLE = 2; + + function State(options) { + this.schema = options['schema'] || _default; + this.indent = Math.max(1, (options['indent'] || 2)); + this.noArrayIndent = options['noArrayIndent'] || false; + this.skipInvalid = options['skipInvalid'] || false; + this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']); + this.styleMap = compileStyleMap(this.schema, options['styles'] || null); + this.sortKeys = options['sortKeys'] || false; + this.lineWidth = options['lineWidth'] || 80; + this.noRefs = options['noRefs'] || false; + this.noCompatMode = options['noCompatMode'] || false; + this.condenseFlow = options['condenseFlow'] || false; + this.quotingType = options['quotingType'] === '"' ? QUOTING_TYPE_DOUBLE : QUOTING_TYPE_SINGLE; + this.forceQuotes = options['forceQuotes'] || false; + this.replacer = typeof options['replacer'] === 'function' ? options['replacer'] : null; + + this.implicitTypes = this.schema.compiledImplicit; + this.explicitTypes = this.schema.compiledExplicit; + + this.tag = null; + this.result = ''; + + this.duplicates = []; + this.usedDuplicates = null; + } + + // Indents every line in a string. Empty lines (\n only) are not indented. + function indentString(string, spaces) { + var ind = common.repeat(' ', spaces), + position = 0, + next = -1, + result = '', + line, + length = string.length; + + while (position < length) { + next = string.indexOf('\n', position); + if (next === -1) { + line = string.slice(position); + position = length; + } else { + line = string.slice(position, next + 1); + position = next + 1; + } + + if (line.length && line !== '\n') result += ind; + + result += line; + } + + return result; + } + + function generateNextLine(state, level) { + return '\n' + common.repeat(' ', state.indent * level); + } + + function testImplicitResolving(state, str) { + var index, length, type; + + for (index = 0, length = state.implicitTypes.length; index < length; index += 1) { + type = state.implicitTypes[index]; + + if (type.resolve(str)) { + return true; + } + } + + return false; + } + + // [33] s-white ::= s-space | s-tab + function isWhitespace(c) { + return c === CHAR_SPACE || c === CHAR_TAB; + } + + // Returns true if the character can be printed without escaping. + // From YAML 1.2: "any allowed characters known to be non-printable + // should also be escaped. [However,] This isn’t mandatory" + // Derived from nb-char - \t - #x85 - #xA0 - #x2028 - #x2029. + function isPrintable(c) { + return (0x00020 <= c && c <= 0x00007E) + || ((0x000A1 <= c && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029) + || ((0x0E000 <= c && c <= 0x00FFFD) && c !== CHAR_BOM) + || (0x10000 <= c && c <= 0x10FFFF); + } + + // [34] ns-char ::= nb-char - s-white + // [27] nb-char ::= c-printable - b-char - c-byte-order-mark + // [26] b-char ::= b-line-feed | b-carriage-return + // Including s-white (for some reason, examples doesn't match specs in this aspect) + // ns-char ::= c-printable - b-line-feed - b-carriage-return - c-byte-order-mark + function isNsCharOrWhitespace(c) { + return isPrintable(c) + && c !== CHAR_BOM + // - b-char + && c !== CHAR_CARRIAGE_RETURN + && c !== CHAR_LINE_FEED; + } + + // [127] ns-plain-safe(c) ::= c = flow-out ⇒ ns-plain-safe-out + // c = flow-in ⇒ ns-plain-safe-in + // c = block-key ⇒ ns-plain-safe-out + // c = flow-key ⇒ ns-plain-safe-in + // [128] ns-plain-safe-out ::= ns-char + // [129] ns-plain-safe-in ::= ns-char - c-flow-indicator + // [130] ns-plain-char(c) ::= ( ns-plain-safe(c) - “:” - “#” ) + // | ( /* An ns-char preceding */ “#” ) + // | ( “:” /* Followed by an ns-plain-safe(c) */ ) + function isPlainSafe(c, prev, inblock) { + var cIsNsCharOrWhitespace = isNsCharOrWhitespace(c); + var cIsNsChar = cIsNsCharOrWhitespace && !isWhitespace(c); + return ( + // ns-plain-safe + inblock ? // c = flow-in + cIsNsCharOrWhitespace + : cIsNsCharOrWhitespace + // - c-flow-indicator + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + ) + // ns-plain-char + && c !== CHAR_SHARP // false on '#' + && !(prev === CHAR_COLON && !cIsNsChar) // false on ': ' + || (isNsCharOrWhitespace(prev) && !isWhitespace(prev) && c === CHAR_SHARP) // change to true on '[^ ]#' + || (prev === CHAR_COLON && cIsNsChar); // change to true on ':[^ ]' + } + + // Simplified test for values allowed as the first character in plain style. + function isPlainSafeFirst(c) { + // Uses a subset of ns-char - c-indicator + // where ns-char = nb-char - s-white. + // No support of ( ( “?” | “:” | “-” ) /* Followed by an ns-plain-safe(c)) */ ) part + return isPrintable(c) && c !== CHAR_BOM + && !isWhitespace(c) // - s-white + // - (c-indicator ::= + // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}” + && c !== CHAR_MINUS + && c !== CHAR_QUESTION + && c !== CHAR_COLON + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + // | “#” | “&” | “*” | “!” | “|” | “=” | “>” | “'” | “"” + && c !== CHAR_SHARP + && c !== CHAR_AMPERSAND + && c !== CHAR_ASTERISK + && c !== CHAR_EXCLAMATION + && c !== CHAR_VERTICAL_LINE + && c !== CHAR_EQUALS + && c !== CHAR_GREATER_THAN + && c !== CHAR_SINGLE_QUOTE + && c !== CHAR_DOUBLE_QUOTE + // | “%” | “@” | “`”) + && c !== CHAR_PERCENT + && c !== CHAR_COMMERCIAL_AT + && c !== CHAR_GRAVE_ACCENT; + } + + // Simplified test for values allowed as the last character in plain style. + function isPlainSafeLast(c) { + // just not whitespace or colon, it will be checked to be plain character later + return !isWhitespace(c) && c !== CHAR_COLON; + } + + // Same as 'string'.codePointAt(pos), but works in older browsers. + function codePointAt(string, pos) { + var first = string.charCodeAt(pos), second; + if (first >= 0xD800 && first <= 0xDBFF && pos + 1 < string.length) { + second = string.charCodeAt(pos + 1); + if (second >= 0xDC00 && second <= 0xDFFF) { + // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; + } + } + return first; + } + + // Determines whether block indentation indicator is required. + function needIndentIndicator(string) { + var leadingSpaceRe = /^\n* /; + return leadingSpaceRe.test(string); + } + + var STYLE_PLAIN = 1, + STYLE_SINGLE = 2, + STYLE_LITERAL = 3, + STYLE_FOLDED = 4, + STYLE_DOUBLE = 5; + + // Determines which scalar styles are possible and returns the preferred style. + // lineWidth = -1 => no limit. + // Pre-conditions: str.length > 0. + // Post-conditions: + // STYLE_PLAIN or STYLE_SINGLE => no \n are in the string. + // STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1). + // STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1). + function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, + testAmbiguousType, quotingType, forceQuotes, inblock) { + + var i; + var char = 0; + var prevChar = null; + var hasLineBreak = false; + var hasFoldableLine = false; // only checked if shouldTrackWidth + var shouldTrackWidth = lineWidth !== -1; + var previousLineBreak = -1; // count the first line correctly + var plain = isPlainSafeFirst(codePointAt(string, 0)) + && isPlainSafeLast(codePointAt(string, string.length - 1)); + + if (singleLineOnly || forceQuotes) { + // Case: no block styles. + // Check for disallowed characters to rule out plain and single. + for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char, prevChar, inblock); + prevChar = char; + } + } else { + // Case: block styles permitted. + for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + if (char === CHAR_LINE_FEED) { + hasLineBreak = true; + // Check if any line can be folded. + if (shouldTrackWidth) { + hasFoldableLine = hasFoldableLine || + // Foldable line = too long, and not more-indented. + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' '); + previousLineBreak = i; + } + } else if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char, prevChar, inblock); + prevChar = char; + } + // in case the end is missing a \n + hasFoldableLine = hasFoldableLine || (shouldTrackWidth && + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' ')); + } + // Although every style can represent \n without escaping, prefer block styles + // for multiline, since they're more readable and they don't add empty lines. + // Also prefer folding a super-long line. + if (!hasLineBreak && !hasFoldableLine) { + // Strings interpretable as another type have to be quoted; + // e.g. the string 'true' vs. the boolean true. + if (plain && !forceQuotes && !testAmbiguousType(string)) { + return STYLE_PLAIN; + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE; + } + // Edge case: block indentation indicator can only have one digit. + if (indentPerLevel > 9 && needIndentIndicator(string)) { + return STYLE_DOUBLE; + } + // At this point we know block styles are valid. + // Prefer literal style unless we want to fold. + if (!forceQuotes) { + return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL; + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE; + } + + // Note: line breaking/folding is implemented for only the folded style. + // NB. We drop the last trailing newline (if any) of a returned block scalar + // since the dumper adds its own newline. This always works: + // • No ending newline => unaffected; already using strip "-" chomping. + // • Ending newline => removed then restored. + // Importantly, this keeps the "+" chomp indicator from gaining an extra line. + function writeScalar(state, string, level, iskey, inblock) { + state.dump = (function () { + if (string.length === 0) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? '""' : "''"; + } + if (!state.noCompatMode) { + if (DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1 || DEPRECATED_BASE60_SYNTAX.test(string)) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? ('"' + string + '"') : ("'" + string + "'"); + } + } + + var indent = state.indent * Math.max(1, level); // no 0-indent scalars + // As indentation gets deeper, let the width decrease monotonically + // to the lower bound min(state.lineWidth, 40). + // Note that this implies + // state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound. + // state.lineWidth > 40 + state.indent: width decreases until the lower bound. + // This behaves better than a constant minimum width which disallows narrower options, + // or an indent threshold which causes the width to suddenly increase. + var lineWidth = state.lineWidth === -1 + ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent); + + // Without knowing if keys are implicit/explicit, assume implicit for safety. + var singleLineOnly = iskey + // No block styles in flow mode. + || (state.flowLevel > -1 && level >= state.flowLevel); + function testAmbiguity(string) { + return testImplicitResolving(state, string); + } + + switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, + testAmbiguity, state.quotingType, state.forceQuotes && !iskey, inblock)) { + + case STYLE_PLAIN: + return string; + case STYLE_SINGLE: + return "'" + string.replace(/'/g, "''") + "'"; + case STYLE_LITERAL: + return '|' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(string, indent)); + case STYLE_FOLDED: + return '>' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(foldString(string, lineWidth), indent)); + case STYLE_DOUBLE: + return '"' + escapeString(string) + '"'; + default: + throw new exception('impossible error: invalid scalar style'); + } + }()); + } + + // Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9. + function blockHeader(string, indentPerLevel) { + var indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : ''; + + // note the special case: the string '\n' counts as a "trailing" empty line. + var clip = string[string.length - 1] === '\n'; + var keep = clip && (string[string.length - 2] === '\n' || string === '\n'); + var chomp = keep ? '+' : (clip ? '' : '-'); + + return indentIndicator + chomp + '\n'; + } + + // (See the note for writeScalar.) + function dropEndingNewline(string) { + return string[string.length - 1] === '\n' ? string.slice(0, -1) : string; + } + + // Note: a long line without a suitable break point will exceed the width limit. + // Pre-conditions: every char in str isPrintable, str.length > 0, width > 0. + function foldString(string, width) { + // In folded style, $k$ consecutive newlines output as $k+1$ newlines— + // unless they're before or after a more-indented line, or at the very + // beginning or end, in which case $k$ maps to $k$. + // Therefore, parse each chunk as newline(s) followed by a content line. + var lineRe = /(\n+)([^\n]*)/g; + + // first line (possibly an empty line) + var result = (function () { + var nextLF = string.indexOf('\n'); + nextLF = nextLF !== -1 ? nextLF : string.length; + lineRe.lastIndex = nextLF; + return foldLine(string.slice(0, nextLF), width); + }()); + // If we haven't reached the first content line yet, don't add an extra \n. + var prevMoreIndented = string[0] === '\n' || string[0] === ' '; + var moreIndented; + + // rest of the lines + var match; + while ((match = lineRe.exec(string))) { + var prefix = match[1], line = match[2]; + moreIndented = (line[0] === ' '); + result += prefix + + (!prevMoreIndented && !moreIndented && line !== '' + ? '\n' : '') + + foldLine(line, width); + prevMoreIndented = moreIndented; + } + + return result; + } + + // Greedy line breaking. + // Picks the longest line under the limit each time, + // otherwise settles for the shortest line over the limit. + // NB. More-indented lines *cannot* be folded, as that would add an extra \n. + function foldLine(line, width) { + if (line === '' || line[0] === ' ') return line; + + // Since a more-indented line adds a \n, breaks can't be followed by a space. + var breakRe = / [^ ]/g; // note: the match index will always be <= length-2. + var match; + // start is an inclusive index. end, curr, and next are exclusive. + var start = 0, end, curr = 0, next = 0; + var result = ''; + + // Invariants: 0 <= start <= length-1. + // 0 <= curr <= next <= max(0, length-2). curr - start <= width. + // Inside the loop: + // A match implies length >= 2, so curr and next are <= length-2. + while ((match = breakRe.exec(line))) { + next = match.index; + // maintain invariant: curr - start <= width + if (next - start > width) { + end = (curr > start) ? curr : next; // derive end <= length-2 + result += '\n' + line.slice(start, end); + // skip the space that was output as \n + start = end + 1; // derive start <= length-1 + } + curr = next; + } + + // By the invariants, start <= length-1, so there is something left over. + // It is either the whole string or a part starting from non-whitespace. + result += '\n'; + // Insert a break if the remainder is too long and there is a break available. + if (line.length - start > width && curr > start) { + result += line.slice(start, curr) + '\n' + line.slice(curr + 1); + } else { + result += line.slice(start); + } + + return result.slice(1); // drop extra \n joiner + } + + // Escapes a double-quoted string. + function escapeString(string) { + var result = ''; + var char = 0; + var escapeSeq; + + for (var i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + escapeSeq = ESCAPE_SEQUENCES[char]; + + if (!escapeSeq && isPrintable(char)) { + result += string[i]; + if (char >= 0x10000) result += string[i + 1]; + } else { + result += escapeSeq || encodeHex(char); + } + } + + return result; + } + + function writeFlowSequence(state, level, object) { + var _result = '', + _tag = state.tag, + index, + length, + value; + + for (index = 0, length = object.length; index < length; index += 1) { + value = object[index]; + + if (state.replacer) { + value = state.replacer.call(object, String(index), value); + } + + // Write only valid elements, put null instead of invalid elements. + if (writeNode(state, level, value, false, false) || + (typeof value === 'undefined' && + writeNode(state, level, null, false, false))) { + + if (_result !== '') _result += ',' + (!state.condenseFlow ? ' ' : ''); + _result += state.dump; + } + } + + state.tag = _tag; + state.dump = '[' + _result + ']'; + } + + function writeBlockSequence(state, level, object, compact) { + var _result = '', + _tag = state.tag, + index, + length, + value; + + for (index = 0, length = object.length; index < length; index += 1) { + value = object[index]; + + if (state.replacer) { + value = state.replacer.call(object, String(index), value); + } + + // Write only valid elements, put null instead of invalid elements. + if (writeNode(state, level + 1, value, true, true, false, true) || + (typeof value === 'undefined' && + writeNode(state, level + 1, null, true, true, false, true))) { + + if (!compact || _result !== '') { + _result += generateNextLine(state, level); + } + + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + _result += '-'; + } else { + _result += '- '; + } + + _result += state.dump; + } + } + + state.tag = _tag; + state.dump = _result || '[]'; // Empty sequence if no valid values. + } + + function writeFlowMapping(state, level, object) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + pairBuffer; + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + + pairBuffer = ''; + if (_result !== '') pairBuffer += ', '; + + if (state.condenseFlow) pairBuffer += '"'; + + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue); + } + + if (!writeNode(state, level, objectKey, false, false)) { + continue; // Skip this pair because of invalid key; + } + + if (state.dump.length > 1024) pairBuffer += '? '; + + pairBuffer += state.dump + (state.condenseFlow ? '"' : '') + ':' + (state.condenseFlow ? '' : ' '); + + if (!writeNode(state, level, objectValue, false, false)) { + continue; // Skip this pair because of invalid value. + } + + pairBuffer += state.dump; + + // Both key and value are valid. + _result += pairBuffer; + } + + state.tag = _tag; + state.dump = '{' + _result + '}'; + } + + function writeBlockMapping(state, level, object, compact) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + explicitPair, + pairBuffer; + + // Allow sorting keys so that the output file is deterministic + if (state.sortKeys === true) { + // Default sorting + objectKeyList.sort(); + } else if (typeof state.sortKeys === 'function') { + // Custom sort function + objectKeyList.sort(state.sortKeys); + } else if (state.sortKeys) { + // Something is wrong + throw new exception('sortKeys must be a boolean or a function'); + } + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + pairBuffer = ''; + + if (!compact || _result !== '') { + pairBuffer += generateNextLine(state, level); + } + + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue); + } + + if (!writeNode(state, level + 1, objectKey, true, true, true)) { + continue; // Skip this pair because of invalid key. + } + + explicitPair = (state.tag !== null && state.tag !== '?') || + (state.dump && state.dump.length > 1024); + + if (explicitPair) { + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += '?'; + } else { + pairBuffer += '? '; + } + } + + pairBuffer += state.dump; + + if (explicitPair) { + pairBuffer += generateNextLine(state, level); + } + + if (!writeNode(state, level + 1, objectValue, true, explicitPair)) { + continue; // Skip this pair because of invalid value. + } + + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += ':'; + } else { + pairBuffer += ': '; + } + + pairBuffer += state.dump; + + // Both key and value are valid. + _result += pairBuffer; + } + + state.tag = _tag; + state.dump = _result || '{}'; // Empty mapping if no valid pairs. + } + + function detectType(state, object, explicit) { + var _result, typeList, index, length, type, style; + + typeList = explicit ? state.explicitTypes : state.implicitTypes; + + for (index = 0, length = typeList.length; index < length; index += 1) { + type = typeList[index]; + + if ((type.instanceOf || type.predicate) && + (!type.instanceOf || ((typeof object === 'object') && (object instanceof type.instanceOf))) && + (!type.predicate || type.predicate(object))) { + + if (explicit) { + if (type.multi && type.representName) { + state.tag = type.representName(object); + } else { + state.tag = type.tag; + } + } else { + state.tag = '?'; + } + + if (type.represent) { + style = state.styleMap[type.tag] || type.defaultStyle; + + if (_toString.call(type.represent) === '[object Function]') { + _result = type.represent(object, style); + } else if (_hasOwnProperty.call(type.represent, style)) { + _result = type.represent[style](object, style); + } else { + throw new exception('!<' + type.tag + '> tag resolver accepts not "' + style + '" style'); + } + + state.dump = _result; + } + + return true; + } + } + + return false; + } + + // Serializes `object` and writes it to global `result`. + // Returns true on success, or false on invalid object. + // + function writeNode(state, level, object, block, compact, iskey, isblockseq) { + state.tag = null; + state.dump = object; + + if (!detectType(state, object, false)) { + detectType(state, object, true); + } + + var type = _toString.call(state.dump); + var inblock = block; + var tagStr; + + if (block) { + block = (state.flowLevel < 0 || state.flowLevel > level); + } + + var objectOrArray = type === '[object Object]' || type === '[object Array]', + duplicateIndex, + duplicate; + + if (objectOrArray) { + duplicateIndex = state.duplicates.indexOf(object); + duplicate = duplicateIndex !== -1; + } + + if ((state.tag !== null && state.tag !== '?') || duplicate || (state.indent !== 2 && level > 0)) { + compact = false; + } + + if (duplicate && state.usedDuplicates[duplicateIndex]) { + state.dump = '*ref_' + duplicateIndex; + } else { + if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) { + state.usedDuplicates[duplicateIndex] = true; + } + if (type === '[object Object]') { + if (block && (Object.keys(state.dump).length !== 0)) { + writeBlockMapping(state, level, state.dump, compact); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowMapping(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object Array]') { + if (block && (state.dump.length !== 0)) { + if (state.noArrayIndent && !isblockseq && level > 0) { + writeBlockSequence(state, level - 1, state.dump, compact); + } else { + writeBlockSequence(state, level, state.dump, compact); + } + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowSequence(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object String]') { + if (state.tag !== '?') { + writeScalar(state, state.dump, level, iskey, inblock); + } + } else if (type === '[object Undefined]') { + return false; + } else { + if (state.skipInvalid) return false; + throw new exception('unacceptable kind of an object to dump ' + type); + } + + if (state.tag !== null && state.tag !== '?') { + // Need to encode all characters except those allowed by the spec: + // + // [35] ns-dec-digit ::= [#x30-#x39] /* 0-9 */ + // [36] ns-hex-digit ::= ns-dec-digit + // | [#x41-#x46] /* A-F */ | [#x61-#x66] /* a-f */ + // [37] ns-ascii-letter ::= [#x41-#x5A] /* A-Z */ | [#x61-#x7A] /* a-z */ + // [38] ns-word-char ::= ns-dec-digit | ns-ascii-letter | “-” + // [39] ns-uri-char ::= “%” ns-hex-digit ns-hex-digit | ns-word-char | “#” + // | “;” | “/” | “?” | “:” | “@” | “&” | “=” | “+” | “$” | “,” + // | “_” | “.” | “!” | “~” | “*” | “'” | “(” | “)” | “[” | “]” + // + // Also need to encode '!' because it has special meaning (end of tag prefix). + // + tagStr = encodeURI( + state.tag[0] === '!' ? state.tag.slice(1) : state.tag + ).replace(/!/g, '%21'); + + if (state.tag[0] === '!') { + tagStr = '!' + tagStr; + } else if (tagStr.slice(0, 18) === 'tag:yaml.org,2002:') { + tagStr = '!!' + tagStr.slice(18); + } else { + tagStr = '!<' + tagStr + '>'; + } + + state.dump = tagStr + ' ' + state.dump; + } + } + + return true; + } + + function getDuplicateReferences(object, state) { + var objects = [], + duplicatesIndexes = [], + index, + length; + + inspectNode(object, objects, duplicatesIndexes); + + for (index = 0, length = duplicatesIndexes.length; index < length; index += 1) { + state.duplicates.push(objects[duplicatesIndexes[index]]); + } + state.usedDuplicates = new Array(length); + } + + function inspectNode(object, objects, duplicatesIndexes) { + var objectKeyList, + index, + length; + + if (object !== null && typeof object === 'object') { + index = objects.indexOf(object); + if (index !== -1) { + if (duplicatesIndexes.indexOf(index) === -1) { + duplicatesIndexes.push(index); + } + } else { + objects.push(object); + + if (Array.isArray(object)) { + for (index = 0, length = object.length; index < length; index += 1) { + inspectNode(object[index], objects, duplicatesIndexes); + } + } else { + objectKeyList = Object.keys(object); + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + inspectNode(object[objectKeyList[index]], objects, duplicatesIndexes); + } + } + } + } + } + + function dump$1(input, options) { + options = options || {}; + + var state = new State(options); + + if (!state.noRefs) getDuplicateReferences(input, state); + + var value = input; + + if (state.replacer) { + value = state.replacer.call({ '': value }, '', value); + } + + if (writeNode(state, 0, value, true, true)) return state.dump + '\n'; + + return ''; + } + + var dump_1 = dump$1; + + var dumper = { + dump: dump_1 + }; + + function renamed(from, to) { + return function () { + throw new Error('Function yaml.' + from + ' is removed in js-yaml 4. ' + + 'Use yaml.' + to + ' instead, which is now safe by default.'); + }; + } + + + var Type = type; + var Schema = schema; + var FAILSAFE_SCHEMA = failsafe; + var JSON_SCHEMA = json; + var CORE_SCHEMA = core; + var DEFAULT_SCHEMA = _default; + var load = loader.load; + var loadAll = loader.loadAll; + var dump = dumper.dump; + var YAMLException = exception; + + // Re-export all types in case user wants to create custom schema + var types = { + binary: binary, + float: float, + map: map, + null: _null, + pairs: pairs, + set: set, + timestamp: timestamp, + bool: bool, + int: int, + merge: merge, + omap: omap, + seq: seq, + str: str + }; + + // Removed functions from JS-YAML 3.0.x + var safeLoad = renamed('safeLoad', 'load'); + var safeLoadAll = renamed('safeLoadAll', 'loadAll'); + var safeDump = renamed('safeDump', 'dump'); + + var jsYaml = { + Type: Type, + Schema: Schema, + FAILSAFE_SCHEMA: FAILSAFE_SCHEMA, + JSON_SCHEMA: JSON_SCHEMA, + CORE_SCHEMA: CORE_SCHEMA, + DEFAULT_SCHEMA: DEFAULT_SCHEMA, + load: load, + loadAll: loadAll, + dump: dump, + YAMLException: YAMLException, + types: types, + safeLoad: safeLoad, + safeLoadAll: safeLoadAll, + safeDump: safeDump + }; + + exports.CORE_SCHEMA = CORE_SCHEMA; + exports.DEFAULT_SCHEMA = DEFAULT_SCHEMA; + exports.FAILSAFE_SCHEMA = FAILSAFE_SCHEMA; + exports.JSON_SCHEMA = JSON_SCHEMA; + exports.Schema = Schema; + exports.Type = Type; + exports.YAMLException = YAMLException; + exports.default = jsYaml; + exports.dump = dump; + exports.load = load; + exports.loadAll = loadAll; + exports.safeDump = safeDump; + exports.safeLoad = safeLoad; + exports.safeLoadAll = safeLoadAll; + exports.types = types; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/dist/js-yaml.min.js b/node_modules/wfilesencoders/node_modules/js-yaml/dist/js-yaml.min.js new file mode 100644 index 00000000..bdd8eef5 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/dist/js-yaml.min.js @@ -0,0 +1,2 @@ +/*! js-yaml 4.1.0 https://github.com/nodeca/js-yaml @license MIT */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).jsyaml={})}(this,(function(e){"use strict";function t(e){return null==e}var n={isNothing:t,isObject:function(e){return"object"==typeof e&&null!==e},toArray:function(e){return Array.isArray(e)?e:t(e)?[]:[e]},repeat:function(e,t){var n,i="";for(n=0;nl&&(t=i-l+(o=" ... ").length),n-i>l&&(n=i+l-(a=" ...").length),{str:o+e.slice(t,n).replace(/\t/g,"→")+a,pos:i-t+o.length}}function l(e,t){return n.repeat(" ",t-e.length)+e}var c=function(e,t){if(t=Object.create(t||null),!e.buffer)return null;t.maxLength||(t.maxLength=79),"number"!=typeof t.indent&&(t.indent=1),"number"!=typeof t.linesBefore&&(t.linesBefore=3),"number"!=typeof t.linesAfter&&(t.linesAfter=2);for(var i,r=/\r?\n|\r|\0/g,o=[0],c=[],s=-1;i=r.exec(e.buffer);)c.push(i.index),o.push(i.index+i[0].length),e.position<=i.index&&s<0&&(s=o.length-2);s<0&&(s=o.length-1);var u,p,f="",d=Math.min(e.line+t.linesAfter,c.length).toString().length,h=t.maxLength-(t.indent+d+3);for(u=1;u<=t.linesBefore&&!(s-u<0);u++)p=a(e.buffer,o[s-u],c[s-u],e.position-(o[s]-o[s-u]),h),f=n.repeat(" ",t.indent)+l((e.line-u+1).toString(),d)+" | "+p.str+"\n"+f;for(p=a(e.buffer,o[s],c[s],e.position,h),f+=n.repeat(" ",t.indent)+l((e.line+1).toString(),d)+" | "+p.str+"\n",f+=n.repeat("-",t.indent+d+3+p.pos)+"^\n",u=1;u<=t.linesAfter&&!(s+u>=c.length);u++)p=a(e.buffer,o[s+u],c[s+u],e.position-(o[s]-o[s+u]),h),f+=n.repeat(" ",t.indent)+l((e.line+u+1).toString(),d)+" | "+p.str+"\n";return f.replace(/\n$/,"")},s=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],u=["scalar","sequence","mapping"];var p=function(e,t){if(t=t||{},Object.keys(t).forEach((function(t){if(-1===s.indexOf(t))throw new o('Unknown option "'+t+'" is met in definition of "'+e+'" YAML type.')})),this.options=t,this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(e){return e},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.representName=t.representName||null,this.defaultStyle=t.defaultStyle||null,this.multi=t.multi||!1,this.styleAliases=function(e){var t={};return null!==e&&Object.keys(e).forEach((function(n){e[n].forEach((function(e){t[String(e)]=n}))})),t}(t.styleAliases||null),-1===u.indexOf(this.kind))throw new o('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')};function f(e,t){var n=[];return e[t].forEach((function(e){var t=n.length;n.forEach((function(n,i){n.tag===e.tag&&n.kind===e.kind&&n.multi===e.multi&&(t=i)})),n[t]=e})),n}function d(e){return this.extend(e)}d.prototype.extend=function(e){var t=[],n=[];if(e instanceof p)n.push(e);else if(Array.isArray(e))n=n.concat(e);else{if(!e||!Array.isArray(e.implicit)&&!Array.isArray(e.explicit))throw new o("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })");e.implicit&&(t=t.concat(e.implicit)),e.explicit&&(n=n.concat(e.explicit))}t.forEach((function(e){if(!(e instanceof p))throw new o("Specified list of YAML types (or a single Type object) contains a non-Type object.");if(e.loadKind&&"scalar"!==e.loadKind)throw new o("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.");if(e.multi)throw new o("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.")})),n.forEach((function(e){if(!(e instanceof p))throw new o("Specified list of YAML types (or a single Type object) contains a non-Type object.")}));var i=Object.create(d.prototype);return i.implicit=(this.implicit||[]).concat(t),i.explicit=(this.explicit||[]).concat(n),i.compiledImplicit=f(i,"implicit"),i.compiledExplicit=f(i,"explicit"),i.compiledTypeMap=function(){var e,t,n={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}};function i(e){e.multi?(n.multi[e.kind].push(e),n.multi.fallback.push(e)):n[e.kind][e.tag]=n.fallback[e.tag]=e}for(e=0,t=arguments.length;e=0?"0b"+e.toString(2):"-0b"+e.toString(2).slice(1)},octal:function(e){return e>=0?"0o"+e.toString(8):"-0o"+e.toString(8).slice(1)},decimal:function(e){return e.toString(10)},hexadecimal:function(e){return e>=0?"0x"+e.toString(16).toUpperCase():"-0x"+e.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}}),x=new RegExp("^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");var I=/^[-+]?[0-9]+e/;var S=new p("tag:yaml.org,2002:float",{kind:"scalar",resolve:function(e){return null!==e&&!(!x.test(e)||"_"===e[e.length-1])},construct:function(e){var t,n;return n="-"===(t=e.replace(/_/g,"").toLowerCase())[0]?-1:1,"+-".indexOf(t[0])>=0&&(t=t.slice(1)),".inf"===t?1===n?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:".nan"===t?NaN:n*parseFloat(t,10)},predicate:function(e){return"[object Number]"===Object.prototype.toString.call(e)&&(e%1!=0||n.isNegativeZero(e))},represent:function(e,t){var i;if(isNaN(e))switch(t){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===e)switch(t){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===e)switch(t){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(n.isNegativeZero(e))return"-0.0";return i=e.toString(10),I.test(i)?i.replace("e",".e"):i},defaultStyle:"lowercase"}),O=b.extend({implicit:[A,v,C,S]}),j=O,T=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),N=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");var F=new p("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:function(e){return null!==e&&(null!==T.exec(e)||null!==N.exec(e))},construct:function(e){var t,n,i,r,o,a,l,c,s=0,u=null;if(null===(t=T.exec(e))&&(t=N.exec(e)),null===t)throw new Error("Date resolve error");if(n=+t[1],i=+t[2]-1,r=+t[3],!t[4])return new Date(Date.UTC(n,i,r));if(o=+t[4],a=+t[5],l=+t[6],t[7]){for(s=t[7].slice(0,3);s.length<3;)s+="0";s=+s}return t[9]&&(u=6e4*(60*+t[10]+ +(t[11]||0)),"-"===t[9]&&(u=-u)),c=new Date(Date.UTC(n,i,r,o,a,l,s)),u&&c.setTime(c.getTime()-u),c},instanceOf:Date,represent:function(e){return e.toISOString()}});var E=new p("tag:yaml.org,2002:merge",{kind:"scalar",resolve:function(e){return"<<"===e||null===e}}),M="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r";var L=new p("tag:yaml.org,2002:binary",{kind:"scalar",resolve:function(e){if(null===e)return!1;var t,n,i=0,r=e.length,o=M;for(n=0;n64)){if(t<0)return!1;i+=6}return i%8==0},construct:function(e){var t,n,i=e.replace(/[\r\n=]/g,""),r=i.length,o=M,a=0,l=[];for(t=0;t>16&255),l.push(a>>8&255),l.push(255&a)),a=a<<6|o.indexOf(i.charAt(t));return 0===(n=r%4*6)?(l.push(a>>16&255),l.push(a>>8&255),l.push(255&a)):18===n?(l.push(a>>10&255),l.push(a>>2&255)):12===n&&l.push(a>>4&255),new Uint8Array(l)},predicate:function(e){return"[object Uint8Array]"===Object.prototype.toString.call(e)},represent:function(e){var t,n,i="",r=0,o=e.length,a=M;for(t=0;t>18&63],i+=a[r>>12&63],i+=a[r>>6&63],i+=a[63&r]),r=(r<<8)+e[t];return 0===(n=o%3)?(i+=a[r>>18&63],i+=a[r>>12&63],i+=a[r>>6&63],i+=a[63&r]):2===n?(i+=a[r>>10&63],i+=a[r>>4&63],i+=a[r<<2&63],i+=a[64]):1===n&&(i+=a[r>>2&63],i+=a[r<<4&63],i+=a[64],i+=a[64]),i}}),_=Object.prototype.hasOwnProperty,D=Object.prototype.toString;var U=new p("tag:yaml.org,2002:omap",{kind:"sequence",resolve:function(e){if(null===e)return!0;var t,n,i,r,o,a=[],l=e;for(t=0,n=l.length;t>10),56320+(e-65536&1023))}for(var ie=new Array(256),re=new Array(256),oe=0;oe<256;oe++)ie[oe]=te(oe)?1:0,re[oe]=te(oe);function ae(e,t){this.input=e,this.filename=t.filename||null,this.schema=t.schema||K,this.onWarning=t.onWarning||null,this.legacy=t.legacy||!1,this.json=t.json||!1,this.listener=t.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=e.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.firstTabInLine=-1,this.documents=[]}function le(e,t){var n={name:e.filename,buffer:e.input.slice(0,-1),position:e.position,line:e.line,column:e.position-e.lineStart};return n.snippet=c(n),new o(t,n)}function ce(e,t){throw le(e,t)}function se(e,t){e.onWarning&&e.onWarning.call(null,le(e,t))}var ue={YAML:function(e,t,n){var i,r,o;null!==e.version&&ce(e,"duplication of %YAML directive"),1!==n.length&&ce(e,"YAML directive accepts exactly one argument"),null===(i=/^([0-9]+)\.([0-9]+)$/.exec(n[0]))&&ce(e,"ill-formed argument of the YAML directive"),r=parseInt(i[1],10),o=parseInt(i[2],10),1!==r&&ce(e,"unacceptable YAML version of the document"),e.version=n[0],e.checkLineBreaks=o<2,1!==o&&2!==o&&se(e,"unsupported YAML version of the document")},TAG:function(e,t,n){var i,r;2!==n.length&&ce(e,"TAG directive accepts exactly two arguments"),i=n[0],r=n[1],G.test(i)||ce(e,"ill-formed tag handle (first argument) of the TAG directive"),P.call(e.tagMap,i)&&ce(e,'there is a previously declared suffix for "'+i+'" tag handle'),V.test(r)||ce(e,"ill-formed tag prefix (second argument) of the TAG directive");try{r=decodeURIComponent(r)}catch(t){ce(e,"tag prefix is malformed: "+r)}e.tagMap[i]=r}};function pe(e,t,n,i){var r,o,a,l;if(t1&&(e.result+=n.repeat("\n",t-1))}function be(e,t){var n,i,r=e.tag,o=e.anchor,a=[],l=!1;if(-1!==e.firstTabInLine)return!1;for(null!==e.anchor&&(e.anchorMap[e.anchor]=a),i=e.input.charCodeAt(e.position);0!==i&&(-1!==e.firstTabInLine&&(e.position=e.firstTabInLine,ce(e,"tab characters must not be used in indentation")),45===i)&&z(e.input.charCodeAt(e.position+1));)if(l=!0,e.position++,ge(e,!0,-1)&&e.lineIndent<=t)a.push(null),i=e.input.charCodeAt(e.position);else if(n=e.line,we(e,t,3,!1,!0),a.push(e.result),ge(e,!0,-1),i=e.input.charCodeAt(e.position),(e.line===n||e.lineIndent>t)&&0!==i)ce(e,"bad indentation of a sequence entry");else if(e.lineIndentt?g=1:e.lineIndent===t?g=0:e.lineIndentt?g=1:e.lineIndent===t?g=0:e.lineIndentt)&&(y&&(a=e.line,l=e.lineStart,c=e.position),we(e,t,4,!0,r)&&(y?g=e.result:m=e.result),y||(de(e,f,d,h,g,m,a,l,c),h=g=m=null),ge(e,!0,-1),s=e.input.charCodeAt(e.position)),(e.line===o||e.lineIndent>t)&&0!==s)ce(e,"bad indentation of a mapping entry");else if(e.lineIndent=0))break;0===o?ce(e,"bad explicit indentation width of a block scalar; it cannot be less than one"):u?ce(e,"repeat of an indentation width identifier"):(p=t+o-1,u=!0)}if(Q(a)){do{a=e.input.charCodeAt(++e.position)}while(Q(a));if(35===a)do{a=e.input.charCodeAt(++e.position)}while(!J(a)&&0!==a)}for(;0!==a;){for(he(e),e.lineIndent=0,a=e.input.charCodeAt(e.position);(!u||e.lineIndentp&&(p=e.lineIndent),J(a))f++;else{if(e.lineIndent0){for(r=a,o=0;r>0;r--)(a=ee(l=e.input.charCodeAt(++e.position)))>=0?o=(o<<4)+a:ce(e,"expected hexadecimal character");e.result+=ne(o),e.position++}else ce(e,"unknown escape sequence");n=i=e.position}else J(l)?(pe(e,n,i,!0),ye(e,ge(e,!1,t)),n=i=e.position):e.position===e.lineStart&&me(e)?ce(e,"unexpected end of the document within a double quoted scalar"):(e.position++,i=e.position)}ce(e,"unexpected end of the stream within a double quoted scalar")}(e,d)?y=!0:!function(e){var t,n,i;if(42!==(i=e.input.charCodeAt(e.position)))return!1;for(i=e.input.charCodeAt(++e.position),t=e.position;0!==i&&!z(i)&&!X(i);)i=e.input.charCodeAt(++e.position);return e.position===t&&ce(e,"name of an alias node must contain at least one character"),n=e.input.slice(t,e.position),P.call(e.anchorMap,n)||ce(e,'unidentified alias "'+n+'"'),e.result=e.anchorMap[n],ge(e,!0,-1),!0}(e)?function(e,t,n){var i,r,o,a,l,c,s,u,p=e.kind,f=e.result;if(z(u=e.input.charCodeAt(e.position))||X(u)||35===u||38===u||42===u||33===u||124===u||62===u||39===u||34===u||37===u||64===u||96===u)return!1;if((63===u||45===u)&&(z(i=e.input.charCodeAt(e.position+1))||n&&X(i)))return!1;for(e.kind="scalar",e.result="",r=o=e.position,a=!1;0!==u;){if(58===u){if(z(i=e.input.charCodeAt(e.position+1))||n&&X(i))break}else if(35===u){if(z(e.input.charCodeAt(e.position-1)))break}else{if(e.position===e.lineStart&&me(e)||n&&X(u))break;if(J(u)){if(l=e.line,c=e.lineStart,s=e.lineIndent,ge(e,!1,-1),e.lineIndent>=t){a=!0,u=e.input.charCodeAt(e.position);continue}e.position=o,e.line=l,e.lineStart=c,e.lineIndent=s;break}}a&&(pe(e,r,o,!1),ye(e,e.line-l),r=o=e.position,a=!1),Q(u)||(o=e.position+1),u=e.input.charCodeAt(++e.position)}return pe(e,r,o,!1),!!e.result||(e.kind=p,e.result=f,!1)}(e,d,1===i)&&(y=!0,null===e.tag&&(e.tag="?")):(y=!0,null===e.tag&&null===e.anchor||ce(e,"alias node should not have any properties")),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):0===g&&(y=c&&be(e,h))),null===e.tag)null!==e.anchor&&(e.anchorMap[e.anchor]=e.result);else if("?"===e.tag){for(null!==e.result&&"scalar"!==e.kind&&ce(e,'unacceptable node kind for ! tag; it should be "scalar", not "'+e.kind+'"'),s=0,u=e.implicitTypes.length;s"),null!==e.result&&f.kind!==e.kind&&ce(e,"unacceptable node kind for !<"+e.tag+'> tag; it should be "'+f.kind+'", not "'+e.kind+'"'),f.resolve(e.result,e.tag)?(e.result=f.construct(e.result,e.tag),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):ce(e,"cannot resolve a node with !<"+e.tag+"> explicit tag")}return null!==e.listener&&e.listener("close",e),null!==e.tag||null!==e.anchor||y}function ke(e){var t,n,i,r,o=e.position,a=!1;for(e.version=null,e.checkLineBreaks=e.legacy,e.tagMap=Object.create(null),e.anchorMap=Object.create(null);0!==(r=e.input.charCodeAt(e.position))&&(ge(e,!0,-1),r=e.input.charCodeAt(e.position),!(e.lineIndent>0||37!==r));){for(a=!0,r=e.input.charCodeAt(++e.position),t=e.position;0!==r&&!z(r);)r=e.input.charCodeAt(++e.position);for(i=[],(n=e.input.slice(t,e.position)).length<1&&ce(e,"directive name must not be less than one character in length");0!==r;){for(;Q(r);)r=e.input.charCodeAt(++e.position);if(35===r){do{r=e.input.charCodeAt(++e.position)}while(0!==r&&!J(r));break}if(J(r))break;for(t=e.position;0!==r&&!z(r);)r=e.input.charCodeAt(++e.position);i.push(e.input.slice(t,e.position))}0!==r&&he(e),P.call(ue,n)?ue[n](e,n,i):se(e,'unknown document directive "'+n+'"')}ge(e,!0,-1),0===e.lineIndent&&45===e.input.charCodeAt(e.position)&&45===e.input.charCodeAt(e.position+1)&&45===e.input.charCodeAt(e.position+2)?(e.position+=3,ge(e,!0,-1)):a&&ce(e,"directives end mark is expected"),we(e,e.lineIndent-1,4,!1,!0),ge(e,!0,-1),e.checkLineBreaks&&H.test(e.input.slice(o,e.position))&&se(e,"non-ASCII line breaks are interpreted as content"),e.documents.push(e.result),e.position===e.lineStart&&me(e)?46===e.input.charCodeAt(e.position)&&(e.position+=3,ge(e,!0,-1)):e.position=55296&&i<=56319&&t+1=56320&&n<=57343?1024*(i-55296)+n-56320+65536:i}function Re(e){return/^\n* /.test(e)}function Be(e,t,n,i,r,o,a,l){var c,s,u=0,p=null,f=!1,d=!1,h=-1!==i,g=-1,m=De(s=Ye(e,0))&&s!==Oe&&!_e(s)&&45!==s&&63!==s&&58!==s&&44!==s&&91!==s&&93!==s&&123!==s&&125!==s&&35!==s&&38!==s&&42!==s&&33!==s&&124!==s&&61!==s&&62!==s&&39!==s&&34!==s&&37!==s&&64!==s&&96!==s&&function(e){return!_e(e)&&58!==e}(Ye(e,e.length-1));if(t||a)for(c=0;c=65536?c+=2:c++){if(!De(u=Ye(e,c)))return 5;m=m&&qe(u,p,l),p=u}else{for(c=0;c=65536?c+=2:c++){if(10===(u=Ye(e,c)))f=!0,h&&(d=d||c-g-1>i&&" "!==e[g+1],g=c);else if(!De(u))return 5;m=m&&qe(u,p,l),p=u}d=d||h&&c-g-1>i&&" "!==e[g+1]}return f||d?n>9&&Re(e)?5:a?2===o?5:2:d?4:3:!m||a||r(e)?2===o?5:2:1}function Ke(e,t,n,i,r){e.dump=function(){if(0===t.length)return 2===e.quotingType?'""':"''";if(!e.noCompatMode&&(-1!==Te.indexOf(t)||Ne.test(t)))return 2===e.quotingType?'"'+t+'"':"'"+t+"'";var a=e.indent*Math.max(1,n),l=-1===e.lineWidth?-1:Math.max(Math.min(e.lineWidth,40),e.lineWidth-a),c=i||e.flowLevel>-1&&n>=e.flowLevel;switch(Be(t,c,e.indent,l,(function(t){return function(e,t){var n,i;for(n=0,i=e.implicitTypes.length;n"+Pe(t,e.indent)+We(Me(function(e,t){var n,i,r=/(\n+)([^\n]*)/g,o=(l=e.indexOf("\n"),l=-1!==l?l:e.length,r.lastIndex=l,He(e.slice(0,l),t)),a="\n"===e[0]||" "===e[0];var l;for(;i=r.exec(e);){var c=i[1],s=i[2];n=" "===s[0],o+=c+(a||n||""===s?"":"\n")+He(s,t),a=n}return o}(t,l),a));case 5:return'"'+function(e){for(var t,n="",i=0,r=0;r=65536?r+=2:r++)i=Ye(e,r),!(t=je[i])&&De(i)?(n+=e[r],i>=65536&&(n+=e[r+1])):n+=t||Fe(i);return n}(t)+'"';default:throw new o("impossible error: invalid scalar style")}}()}function Pe(e,t){var n=Re(e)?String(t):"",i="\n"===e[e.length-1];return n+(i&&("\n"===e[e.length-2]||"\n"===e)?"+":i?"":"-")+"\n"}function We(e){return"\n"===e[e.length-1]?e.slice(0,-1):e}function He(e,t){if(""===e||" "===e[0])return e;for(var n,i,r=/ [^ ]/g,o=0,a=0,l=0,c="";n=r.exec(e);)(l=n.index)-o>t&&(i=a>o?a:l,c+="\n"+e.slice(o,i),o=i+1),a=l;return c+="\n",e.length-o>t&&a>o?c+=e.slice(o,a)+"\n"+e.slice(a+1):c+=e.slice(o),c.slice(1)}function $e(e,t,n,i){var r,o,a,l="",c=e.tag;for(r=0,o=n.length;r tag resolver accepts not "'+s+'" style');i=c.represent[s](t,s)}e.dump=i}return!0}return!1}function Ve(e,t,n,i,r,a,l){e.tag=null,e.dump=n,Ge(e,n,!1)||Ge(e,n,!0);var c,s=Ie.call(e.dump),u=i;i&&(i=e.flowLevel<0||e.flowLevel>t);var p,f,d="[object Object]"===s||"[object Array]"===s;if(d&&(f=-1!==(p=e.duplicates.indexOf(n))),(null!==e.tag&&"?"!==e.tag||f||2!==e.indent&&t>0)&&(r=!1),f&&e.usedDuplicates[p])e.dump="*ref_"+p;else{if(d&&f&&!e.usedDuplicates[p]&&(e.usedDuplicates[p]=!0),"[object Object]"===s)i&&0!==Object.keys(e.dump).length?(!function(e,t,n,i){var r,a,l,c,s,u,p="",f=e.tag,d=Object.keys(n);if(!0===e.sortKeys)d.sort();else if("function"==typeof e.sortKeys)d.sort(e.sortKeys);else if(e.sortKeys)throw new o("sortKeys must be a boolean or a function");for(r=0,a=d.length;r1024)&&(e.dump&&10===e.dump.charCodeAt(0)?u+="?":u+="? "),u+=e.dump,s&&(u+=Le(e,t)),Ve(e,t+1,c,!0,s)&&(e.dump&&10===e.dump.charCodeAt(0)?u+=":":u+=": ",p+=u+=e.dump));e.tag=f,e.dump=p||"{}"}(e,t,e.dump,r),f&&(e.dump="&ref_"+p+e.dump)):(!function(e,t,n){var i,r,o,a,l,c="",s=e.tag,u=Object.keys(n);for(i=0,r=u.length;i1024&&(l+="? "),l+=e.dump+(e.condenseFlow?'"':"")+":"+(e.condenseFlow?"":" "),Ve(e,t,a,!1,!1)&&(c+=l+=e.dump));e.tag=s,e.dump="{"+c+"}"}(e,t,e.dump),f&&(e.dump="&ref_"+p+" "+e.dump));else if("[object Array]"===s)i&&0!==e.dump.length?(e.noArrayIndent&&!l&&t>0?$e(e,t-1,e.dump,r):$e(e,t,e.dump,r),f&&(e.dump="&ref_"+p+e.dump)):(!function(e,t,n){var i,r,o,a="",l=e.tag;for(i=0,r=n.length;i",e.dump=c+" "+e.dump)}return!0}function Ze(e,t){var n,i,r=[],o=[];for(Je(e,r,o),n=0,i=o.length;n maxHalfLength) { + head = ' ... '; + lineStart = position - maxHalfLength + head.length; + } + + if (lineEnd - position > maxHalfLength) { + tail = ' ...'; + lineEnd = position + maxHalfLength - tail.length; + } + + return { + str: head + buffer.slice(lineStart, lineEnd).replace(/\t/g, '→') + tail, + pos: position - lineStart + head.length // relative position + }; +} + + +function padStart(string, max) { + return common.repeat(' ', max - string.length) + string; +} + + +function makeSnippet(mark, options) { + options = Object.create(options || null); + + if (!mark.buffer) return null; + + if (!options.maxLength) options.maxLength = 79; + if (typeof options.indent !== 'number') options.indent = 1; + if (typeof options.linesBefore !== 'number') options.linesBefore = 3; + if (typeof options.linesAfter !== 'number') options.linesAfter = 2; + + var re = /\r?\n|\r|\0/g; + var lineStarts = [ 0 ]; + var lineEnds = []; + var match; + var foundLineNo = -1; + + while ((match = re.exec(mark.buffer))) { + lineEnds.push(match.index); + lineStarts.push(match.index + match[0].length); + + if (mark.position <= match.index && foundLineNo < 0) { + foundLineNo = lineStarts.length - 2; + } + } + + if (foundLineNo < 0) foundLineNo = lineStarts.length - 1; + + var result = '', i, line; + var lineNoLength = Math.min(mark.line + options.linesAfter, lineEnds.length).toString().length; + var maxLineLength = options.maxLength - (options.indent + lineNoLength + 3); + + for (i = 1; i <= options.linesBefore; i++) { + if (foundLineNo - i < 0) break; + line = getLine( + mark.buffer, + lineStarts[foundLineNo - i], + lineEnds[foundLineNo - i], + mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo - i]), + maxLineLength + ); + result = common.repeat(' ', options.indent) + padStart((mark.line - i + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n' + result; + } + + line = getLine(mark.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark.position, maxLineLength); + result += common.repeat(' ', options.indent) + padStart((mark.line + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n'; + result += common.repeat('-', options.indent + lineNoLength + 3 + line.pos) + '^' + '\n'; + + for (i = 1; i <= options.linesAfter; i++) { + if (foundLineNo + i >= lineEnds.length) break; + line = getLine( + mark.buffer, + lineStarts[foundLineNo + i], + lineEnds[foundLineNo + i], + mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo + i]), + maxLineLength + ); + result += common.repeat(' ', options.indent) + padStart((mark.line + i + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n'; + } + + return result.replace(/\n$/, ''); +} + + +var snippet = makeSnippet; + +var TYPE_CONSTRUCTOR_OPTIONS = [ + 'kind', + 'multi', + 'resolve', + 'construct', + 'instanceOf', + 'predicate', + 'represent', + 'representName', + 'defaultStyle', + 'styleAliases' +]; + +var YAML_NODE_KINDS = [ + 'scalar', + 'sequence', + 'mapping' +]; + +function compileStyleAliases(map) { + var result = {}; + + if (map !== null) { + Object.keys(map).forEach(function (style) { + map[style].forEach(function (alias) { + result[String(alias)] = style; + }); + }); + } + + return result; +} + +function Type$1(tag, options) { + options = options || {}; + + Object.keys(options).forEach(function (name) { + if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { + throw new exception('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); + } + }); + + // TODO: Add tag format check. + this.options = options; // keep original options in case user wants to extend this type later + this.tag = tag; + this.kind = options['kind'] || null; + this.resolve = options['resolve'] || function () { return true; }; + this.construct = options['construct'] || function (data) { return data; }; + this.instanceOf = options['instanceOf'] || null; + this.predicate = options['predicate'] || null; + this.represent = options['represent'] || null; + this.representName = options['representName'] || null; + this.defaultStyle = options['defaultStyle'] || null; + this.multi = options['multi'] || false; + this.styleAliases = compileStyleAliases(options['styleAliases'] || null); + + if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { + throw new exception('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); + } +} + +var type = Type$1; + +/*eslint-disable max-len*/ + + + + + +function compileList(schema, name) { + var result = []; + + schema[name].forEach(function (currentType) { + var newIndex = result.length; + + result.forEach(function (previousType, previousIndex) { + if (previousType.tag === currentType.tag && + previousType.kind === currentType.kind && + previousType.multi === currentType.multi) { + + newIndex = previousIndex; + } + }); + + result[newIndex] = currentType; + }); + + return result; +} + + +function compileMap(/* lists... */) { + var result = { + scalar: {}, + sequence: {}, + mapping: {}, + fallback: {}, + multi: { + scalar: [], + sequence: [], + mapping: [], + fallback: [] + } + }, index, length; + + function collectType(type) { + if (type.multi) { + result.multi[type.kind].push(type); + result.multi['fallback'].push(type); + } else { + result[type.kind][type.tag] = result['fallback'][type.tag] = type; + } + } + + for (index = 0, length = arguments.length; index < length; index += 1) { + arguments[index].forEach(collectType); + } + return result; +} + + +function Schema$1(definition) { + return this.extend(definition); +} + + +Schema$1.prototype.extend = function extend(definition) { + var implicit = []; + var explicit = []; + + if (definition instanceof type) { + // Schema.extend(type) + explicit.push(definition); + + } else if (Array.isArray(definition)) { + // Schema.extend([ type1, type2, ... ]) + explicit = explicit.concat(definition); + + } else if (definition && (Array.isArray(definition.implicit) || Array.isArray(definition.explicit))) { + // Schema.extend({ explicit: [ type1, type2, ... ], implicit: [ type1, type2, ... ] }) + if (definition.implicit) implicit = implicit.concat(definition.implicit); + if (definition.explicit) explicit = explicit.concat(definition.explicit); + + } else { + throw new exception('Schema.extend argument should be a Type, [ Type ], ' + + 'or a schema definition ({ implicit: [...], explicit: [...] })'); + } + + implicit.forEach(function (type$1) { + if (!(type$1 instanceof type)) { + throw new exception('Specified list of YAML types (or a single Type object) contains a non-Type object.'); + } + + if (type$1.loadKind && type$1.loadKind !== 'scalar') { + throw new exception('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.'); + } + + if (type$1.multi) { + throw new exception('There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.'); + } + }); + + explicit.forEach(function (type$1) { + if (!(type$1 instanceof type)) { + throw new exception('Specified list of YAML types (or a single Type object) contains a non-Type object.'); + } + }); + + var result = Object.create(Schema$1.prototype); + + result.implicit = (this.implicit || []).concat(implicit); + result.explicit = (this.explicit || []).concat(explicit); + + result.compiledImplicit = compileList(result, 'implicit'); + result.compiledExplicit = compileList(result, 'explicit'); + result.compiledTypeMap = compileMap(result.compiledImplicit, result.compiledExplicit); + + return result; +}; + + +var schema = Schema$1; + +var str = new type('tag:yaml.org,2002:str', { + kind: 'scalar', + construct: function (data) { return data !== null ? data : ''; } +}); + +var seq = new type('tag:yaml.org,2002:seq', { + kind: 'sequence', + construct: function (data) { return data !== null ? data : []; } +}); + +var map = new type('tag:yaml.org,2002:map', { + kind: 'mapping', + construct: function (data) { return data !== null ? data : {}; } +}); + +var failsafe = new schema({ + explicit: [ + str, + seq, + map + ] +}); + +function resolveYamlNull(data) { + if (data === null) return true; + + var max = data.length; + + return (max === 1 && data === '~') || + (max === 4 && (data === 'null' || data === 'Null' || data === 'NULL')); +} + +function constructYamlNull() { + return null; +} + +function isNull(object) { + return object === null; +} + +var _null = new type('tag:yaml.org,2002:null', { + kind: 'scalar', + resolve: resolveYamlNull, + construct: constructYamlNull, + predicate: isNull, + represent: { + canonical: function () { return '~'; }, + lowercase: function () { return 'null'; }, + uppercase: function () { return 'NULL'; }, + camelcase: function () { return 'Null'; }, + empty: function () { return ''; } + }, + defaultStyle: 'lowercase' +}); + +function resolveYamlBoolean(data) { + if (data === null) return false; + + var max = data.length; + + return (max === 4 && (data === 'true' || data === 'True' || data === 'TRUE')) || + (max === 5 && (data === 'false' || data === 'False' || data === 'FALSE')); +} + +function constructYamlBoolean(data) { + return data === 'true' || + data === 'True' || + data === 'TRUE'; +} + +function isBoolean(object) { + return Object.prototype.toString.call(object) === '[object Boolean]'; +} + +var bool = new type('tag:yaml.org,2002:bool', { + kind: 'scalar', + resolve: resolveYamlBoolean, + construct: constructYamlBoolean, + predicate: isBoolean, + represent: { + lowercase: function (object) { return object ? 'true' : 'false'; }, + uppercase: function (object) { return object ? 'TRUE' : 'FALSE'; }, + camelcase: function (object) { return object ? 'True' : 'False'; } + }, + defaultStyle: 'lowercase' +}); + +function isHexCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) || + ((0x41/* A */ <= c) && (c <= 0x46/* F */)) || + ((0x61/* a */ <= c) && (c <= 0x66/* f */)); +} + +function isOctCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x37/* 7 */)); +} + +function isDecCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)); +} + +function resolveYamlInteger(data) { + if (data === null) return false; + + var max = data.length, + index = 0, + hasDigits = false, + ch; + + if (!max) return false; + + ch = data[index]; + + // sign + if (ch === '-' || ch === '+') { + ch = data[++index]; + } + + if (ch === '0') { + // 0 + if (index + 1 === max) return true; + ch = data[++index]; + + // base 2, base 8, base 16 + + if (ch === 'b') { + // base 2 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (ch !== '0' && ch !== '1') return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + + + if (ch === 'x') { + // base 16 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isHexCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + + + if (ch === 'o') { + // base 8 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isOctCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + } + + // base 10 (except 0) + + // value should not start with `_`; + if (ch === '_') return false; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isDecCode(data.charCodeAt(index))) { + return false; + } + hasDigits = true; + } + + // Should have digits and should not end with `_` + if (!hasDigits || ch === '_') return false; + + return true; +} + +function constructYamlInteger(data) { + var value = data, sign = 1, ch; + + if (value.indexOf('_') !== -1) { + value = value.replace(/_/g, ''); + } + + ch = value[0]; + + if (ch === '-' || ch === '+') { + if (ch === '-') sign = -1; + value = value.slice(1); + ch = value[0]; + } + + if (value === '0') return 0; + + if (ch === '0') { + if (value[1] === 'b') return sign * parseInt(value.slice(2), 2); + if (value[1] === 'x') return sign * parseInt(value.slice(2), 16); + if (value[1] === 'o') return sign * parseInt(value.slice(2), 8); + } + + return sign * parseInt(value, 10); +} + +function isInteger(object) { + return (Object.prototype.toString.call(object)) === '[object Number]' && + (object % 1 === 0 && !common.isNegativeZero(object)); +} + +var int = new type('tag:yaml.org,2002:int', { + kind: 'scalar', + resolve: resolveYamlInteger, + construct: constructYamlInteger, + predicate: isInteger, + represent: { + binary: function (obj) { return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1); }, + octal: function (obj) { return obj >= 0 ? '0o' + obj.toString(8) : '-0o' + obj.toString(8).slice(1); }, + decimal: function (obj) { return obj.toString(10); }, + /* eslint-disable max-len */ + hexadecimal: function (obj) { return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1); } + }, + defaultStyle: 'decimal', + styleAliases: { + binary: [ 2, 'bin' ], + octal: [ 8, 'oct' ], + decimal: [ 10, 'dec' ], + hexadecimal: [ 16, 'hex' ] + } +}); + +var YAML_FLOAT_PATTERN = new RegExp( + // 2.5e4, 2.5 and integers + '^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?' + + // .2e4, .2 + // special case, seems not from spec + '|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?' + + // .inf + '|[-+]?\\.(?:inf|Inf|INF)' + + // .nan + '|\\.(?:nan|NaN|NAN))$'); + +function resolveYamlFloat(data) { + if (data === null) return false; + + if (!YAML_FLOAT_PATTERN.test(data) || + // Quick hack to not allow integers end with `_` + // Probably should update regexp & check speed + data[data.length - 1] === '_') { + return false; + } + + return true; +} + +function constructYamlFloat(data) { + var value, sign; + + value = data.replace(/_/g, '').toLowerCase(); + sign = value[0] === '-' ? -1 : 1; + + if ('+-'.indexOf(value[0]) >= 0) { + value = value.slice(1); + } + + if (value === '.inf') { + return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; + + } else if (value === '.nan') { + return NaN; + } + return sign * parseFloat(value, 10); +} + + +var SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/; + +function representYamlFloat(object, style) { + var res; + + if (isNaN(object)) { + switch (style) { + case 'lowercase': return '.nan'; + case 'uppercase': return '.NAN'; + case 'camelcase': return '.NaN'; + } + } else if (Number.POSITIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '.inf'; + case 'uppercase': return '.INF'; + case 'camelcase': return '.Inf'; + } + } else if (Number.NEGATIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '-.inf'; + case 'uppercase': return '-.INF'; + case 'camelcase': return '-.Inf'; + } + } else if (common.isNegativeZero(object)) { + return '-0.0'; + } + + res = object.toString(10); + + // JS stringifier can build scientific format without dots: 5e-100, + // while YAML requres dot: 5.e-100. Fix it with simple hack + + return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res; +} + +function isFloat(object) { + return (Object.prototype.toString.call(object) === '[object Number]') && + (object % 1 !== 0 || common.isNegativeZero(object)); +} + +var float = new type('tag:yaml.org,2002:float', { + kind: 'scalar', + resolve: resolveYamlFloat, + construct: constructYamlFloat, + predicate: isFloat, + represent: representYamlFloat, + defaultStyle: 'lowercase' +}); + +var json = failsafe.extend({ + implicit: [ + _null, + bool, + int, + float + ] +}); + +var core = json; + +var YAML_DATE_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9])' + // [2] month + '-([0-9][0-9])$'); // [3] day + +var YAML_TIMESTAMP_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9]?)' + // [2] month + '-([0-9][0-9]?)' + // [3] day + '(?:[Tt]|[ \\t]+)' + // ... + '([0-9][0-9]?)' + // [4] hour + ':([0-9][0-9])' + // [5] minute + ':([0-9][0-9])' + // [6] second + '(?:\\.([0-9]*))?' + // [7] fraction + '(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tz_hour + '(?::([0-9][0-9]))?))?$'); // [11] tz_minute + +function resolveYamlTimestamp(data) { + if (data === null) return false; + if (YAML_DATE_REGEXP.exec(data) !== null) return true; + if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true; + return false; +} + +function constructYamlTimestamp(data) { + var match, year, month, day, hour, minute, second, fraction = 0, + delta = null, tz_hour, tz_minute, date; + + match = YAML_DATE_REGEXP.exec(data); + if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data); + + if (match === null) throw new Error('Date resolve error'); + + // match: [1] year [2] month [3] day + + year = +(match[1]); + month = +(match[2]) - 1; // JS month starts with 0 + day = +(match[3]); + + if (!match[4]) { // no hour + return new Date(Date.UTC(year, month, day)); + } + + // match: [4] hour [5] minute [6] second [7] fraction + + hour = +(match[4]); + minute = +(match[5]); + second = +(match[6]); + + if (match[7]) { + fraction = match[7].slice(0, 3); + while (fraction.length < 3) { // milli-seconds + fraction += '0'; + } + fraction = +fraction; + } + + // match: [8] tz [9] tz_sign [10] tz_hour [11] tz_minute + + if (match[9]) { + tz_hour = +(match[10]); + tz_minute = +(match[11] || 0); + delta = (tz_hour * 60 + tz_minute) * 60000; // delta in mili-seconds + if (match[9] === '-') delta = -delta; + } + + date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction)); + + if (delta) date.setTime(date.getTime() - delta); + + return date; +} + +function representYamlTimestamp(object /*, style*/) { + return object.toISOString(); +} + +var timestamp = new type('tag:yaml.org,2002:timestamp', { + kind: 'scalar', + resolve: resolveYamlTimestamp, + construct: constructYamlTimestamp, + instanceOf: Date, + represent: representYamlTimestamp +}); + +function resolveYamlMerge(data) { + return data === '<<' || data === null; +} + +var merge = new type('tag:yaml.org,2002:merge', { + kind: 'scalar', + resolve: resolveYamlMerge +}); + +/*eslint-disable no-bitwise*/ + + + + + +// [ 64, 65, 66 ] -> [ padding, CR, LF ] +var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r'; + + +function resolveYamlBinary(data) { + if (data === null) return false; + + var code, idx, bitlen = 0, max = data.length, map = BASE64_MAP; + + // Convert one by one. + for (idx = 0; idx < max; idx++) { + code = map.indexOf(data.charAt(idx)); + + // Skip CR/LF + if (code > 64) continue; + + // Fail on illegal characters + if (code < 0) return false; + + bitlen += 6; + } + + // If there are any bits left, source was corrupted + return (bitlen % 8) === 0; +} + +function constructYamlBinary(data) { + var idx, tailbits, + input = data.replace(/[\r\n=]/g, ''), // remove CR/LF & padding to simplify scan + max = input.length, + map = BASE64_MAP, + bits = 0, + result = []; + + // Collect by 6*4 bits (3 bytes) + + for (idx = 0; idx < max; idx++) { + if ((idx % 4 === 0) && idx) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } + + bits = (bits << 6) | map.indexOf(input.charAt(idx)); + } + + // Dump tail + + tailbits = (max % 4) * 6; + + if (tailbits === 0) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } else if (tailbits === 18) { + result.push((bits >> 10) & 0xFF); + result.push((bits >> 2) & 0xFF); + } else if (tailbits === 12) { + result.push((bits >> 4) & 0xFF); + } + + return new Uint8Array(result); +} + +function representYamlBinary(object /*, style*/) { + var result = '', bits = 0, idx, tail, + max = object.length, + map = BASE64_MAP; + + // Convert every three bytes to 4 ASCII characters. + + for (idx = 0; idx < max; idx++) { + if ((idx % 3 === 0) && idx) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } + + bits = (bits << 8) + object[idx]; + } + + // Dump tail + + tail = max % 3; + + if (tail === 0) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } else if (tail === 2) { + result += map[(bits >> 10) & 0x3F]; + result += map[(bits >> 4) & 0x3F]; + result += map[(bits << 2) & 0x3F]; + result += map[64]; + } else if (tail === 1) { + result += map[(bits >> 2) & 0x3F]; + result += map[(bits << 4) & 0x3F]; + result += map[64]; + result += map[64]; + } + + return result; +} + +function isBinary(obj) { + return Object.prototype.toString.call(obj) === '[object Uint8Array]'; +} + +var binary = new type('tag:yaml.org,2002:binary', { + kind: 'scalar', + resolve: resolveYamlBinary, + construct: constructYamlBinary, + predicate: isBinary, + represent: representYamlBinary +}); + +var _hasOwnProperty$3 = Object.prototype.hasOwnProperty; +var _toString$2 = Object.prototype.toString; + +function resolveYamlOmap(data) { + if (data === null) return true; + + var objectKeys = [], index, length, pair, pairKey, pairHasKey, + object = data; + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + pairHasKey = false; + + if (_toString$2.call(pair) !== '[object Object]') return false; + + for (pairKey in pair) { + if (_hasOwnProperty$3.call(pair, pairKey)) { + if (!pairHasKey) pairHasKey = true; + else return false; + } + } + + if (!pairHasKey) return false; + + if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey); + else return false; + } + + return true; +} + +function constructYamlOmap(data) { + return data !== null ? data : []; +} + +var omap = new type('tag:yaml.org,2002:omap', { + kind: 'sequence', + resolve: resolveYamlOmap, + construct: constructYamlOmap +}); + +var _toString$1 = Object.prototype.toString; + +function resolveYamlPairs(data) { + if (data === null) return true; + + var index, length, pair, keys, result, + object = data; + + result = new Array(object.length); + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + + if (_toString$1.call(pair) !== '[object Object]') return false; + + keys = Object.keys(pair); + + if (keys.length !== 1) return false; + + result[index] = [ keys[0], pair[keys[0]] ]; + } + + return true; +} + +function constructYamlPairs(data) { + if (data === null) return []; + + var index, length, pair, keys, result, + object = data; + + result = new Array(object.length); + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + + keys = Object.keys(pair); + + result[index] = [ keys[0], pair[keys[0]] ]; + } + + return result; +} + +var pairs = new type('tag:yaml.org,2002:pairs', { + kind: 'sequence', + resolve: resolveYamlPairs, + construct: constructYamlPairs +}); + +var _hasOwnProperty$2 = Object.prototype.hasOwnProperty; + +function resolveYamlSet(data) { + if (data === null) return true; + + var key, object = data; + + for (key in object) { + if (_hasOwnProperty$2.call(object, key)) { + if (object[key] !== null) return false; + } + } + + return true; +} + +function constructYamlSet(data) { + return data !== null ? data : {}; +} + +var set = new type('tag:yaml.org,2002:set', { + kind: 'mapping', + resolve: resolveYamlSet, + construct: constructYamlSet +}); + +var _default = core.extend({ + implicit: [ + timestamp, + merge + ], + explicit: [ + binary, + omap, + pairs, + set + ] +}); + +/*eslint-disable max-len,no-use-before-define*/ + + + + + + + +var _hasOwnProperty$1 = Object.prototype.hasOwnProperty; + + +var CONTEXT_FLOW_IN = 1; +var CONTEXT_FLOW_OUT = 2; +var CONTEXT_BLOCK_IN = 3; +var CONTEXT_BLOCK_OUT = 4; + + +var CHOMPING_CLIP = 1; +var CHOMPING_STRIP = 2; +var CHOMPING_KEEP = 3; + + +var PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; +var PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/; +var PATTERN_FLOW_INDICATORS = /[,\[\]\{\}]/; +var PATTERN_TAG_HANDLE = /^(?:!|!!|![a-z\-]+!)$/i; +var PATTERN_TAG_URI = /^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i; + + +function _class(obj) { return Object.prototype.toString.call(obj); } + +function is_EOL(c) { + return (c === 0x0A/* LF */) || (c === 0x0D/* CR */); +} + +function is_WHITE_SPACE(c) { + return (c === 0x09/* Tab */) || (c === 0x20/* Space */); +} + +function is_WS_OR_EOL(c) { + return (c === 0x09/* Tab */) || + (c === 0x20/* Space */) || + (c === 0x0A/* LF */) || + (c === 0x0D/* CR */); +} + +function is_FLOW_INDICATOR(c) { + return c === 0x2C/* , */ || + c === 0x5B/* [ */ || + c === 0x5D/* ] */ || + c === 0x7B/* { */ || + c === 0x7D/* } */; +} + +function fromHexCode(c) { + var lc; + + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } + + /*eslint-disable no-bitwise*/ + lc = c | 0x20; + + if ((0x61/* a */ <= lc) && (lc <= 0x66/* f */)) { + return lc - 0x61 + 10; + } + + return -1; +} + +function escapedHexLen(c) { + if (c === 0x78/* x */) { return 2; } + if (c === 0x75/* u */) { return 4; } + if (c === 0x55/* U */) { return 8; } + return 0; +} + +function fromDecimalCode(c) { + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } + + return -1; +} + +function simpleEscapeSequence(c) { + /* eslint-disable indent */ + return (c === 0x30/* 0 */) ? '\x00' : + (c === 0x61/* a */) ? '\x07' : + (c === 0x62/* b */) ? '\x08' : + (c === 0x74/* t */) ? '\x09' : + (c === 0x09/* Tab */) ? '\x09' : + (c === 0x6E/* n */) ? '\x0A' : + (c === 0x76/* v */) ? '\x0B' : + (c === 0x66/* f */) ? '\x0C' : + (c === 0x72/* r */) ? '\x0D' : + (c === 0x65/* e */) ? '\x1B' : + (c === 0x20/* Space */) ? ' ' : + (c === 0x22/* " */) ? '\x22' : + (c === 0x2F/* / */) ? '/' : + (c === 0x5C/* \ */) ? '\x5C' : + (c === 0x4E/* N */) ? '\x85' : + (c === 0x5F/* _ */) ? '\xA0' : + (c === 0x4C/* L */) ? '\u2028' : + (c === 0x50/* P */) ? '\u2029' : ''; +} + +function charFromCodepoint(c) { + if (c <= 0xFFFF) { + return String.fromCharCode(c); + } + // Encode UTF-16 surrogate pair + // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF + return String.fromCharCode( + ((c - 0x010000) >> 10) + 0xD800, + ((c - 0x010000) & 0x03FF) + 0xDC00 + ); +} + +var simpleEscapeCheck = new Array(256); // integer, for fast access +var simpleEscapeMap = new Array(256); +for (var i = 0; i < 256; i++) { + simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0; + simpleEscapeMap[i] = simpleEscapeSequence(i); +} + + +function State$1(input, options) { + this.input = input; + + this.filename = options['filename'] || null; + this.schema = options['schema'] || _default; + this.onWarning = options['onWarning'] || null; + // (Hidden) Remove? makes the loader to expect YAML 1.1 documents + // if such documents have no explicit %YAML directive + this.legacy = options['legacy'] || false; + + this.json = options['json'] || false; + this.listener = options['listener'] || null; + + this.implicitTypes = this.schema.compiledImplicit; + this.typeMap = this.schema.compiledTypeMap; + + this.length = input.length; + this.position = 0; + this.line = 0; + this.lineStart = 0; + this.lineIndent = 0; + + // position of first leading tab in the current line, + // used to make sure there are no tabs in the indentation + this.firstTabInLine = -1; + + this.documents = []; + + /* + this.version; + this.checkLineBreaks; + this.tagMap; + this.anchorMap; + this.tag; + this.anchor; + this.kind; + this.result;*/ + +} + + +function generateError(state, message) { + var mark = { + name: state.filename, + buffer: state.input.slice(0, -1), // omit trailing \0 + position: state.position, + line: state.line, + column: state.position - state.lineStart + }; + + mark.snippet = snippet(mark); + + return new exception(message, mark); +} + +function throwError(state, message) { + throw generateError(state, message); +} + +function throwWarning(state, message) { + if (state.onWarning) { + state.onWarning.call(null, generateError(state, message)); + } +} + + +var directiveHandlers = { + + YAML: function handleYamlDirective(state, name, args) { + + var match, major, minor; + + if (state.version !== null) { + throwError(state, 'duplication of %YAML directive'); + } + + if (args.length !== 1) { + throwError(state, 'YAML directive accepts exactly one argument'); + } + + match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]); + + if (match === null) { + throwError(state, 'ill-formed argument of the YAML directive'); + } + + major = parseInt(match[1], 10); + minor = parseInt(match[2], 10); + + if (major !== 1) { + throwError(state, 'unacceptable YAML version of the document'); + } + + state.version = args[0]; + state.checkLineBreaks = (minor < 2); + + if (minor !== 1 && minor !== 2) { + throwWarning(state, 'unsupported YAML version of the document'); + } + }, + + TAG: function handleTagDirective(state, name, args) { + + var handle, prefix; + + if (args.length !== 2) { + throwError(state, 'TAG directive accepts exactly two arguments'); + } + + handle = args[0]; + prefix = args[1]; + + if (!PATTERN_TAG_HANDLE.test(handle)) { + throwError(state, 'ill-formed tag handle (first argument) of the TAG directive'); + } + + if (_hasOwnProperty$1.call(state.tagMap, handle)) { + throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle'); + } + + if (!PATTERN_TAG_URI.test(prefix)) { + throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive'); + } + + try { + prefix = decodeURIComponent(prefix); + } catch (err) { + throwError(state, 'tag prefix is malformed: ' + prefix); + } + + state.tagMap[handle] = prefix; + } +}; + + +function captureSegment(state, start, end, checkJson) { + var _position, _length, _character, _result; + + if (start < end) { + _result = state.input.slice(start, end); + + if (checkJson) { + for (_position = 0, _length = _result.length; _position < _length; _position += 1) { + _character = _result.charCodeAt(_position); + if (!(_character === 0x09 || + (0x20 <= _character && _character <= 0x10FFFF))) { + throwError(state, 'expected valid JSON character'); + } + } + } else if (PATTERN_NON_PRINTABLE.test(_result)) { + throwError(state, 'the stream contains non-printable characters'); + } + + state.result += _result; + } +} + +function mergeMappings(state, destination, source, overridableKeys) { + var sourceKeys, key, index, quantity; + + if (!common.isObject(source)) { + throwError(state, 'cannot merge mappings; the provided source object is unacceptable'); + } + + sourceKeys = Object.keys(source); + + for (index = 0, quantity = sourceKeys.length; index < quantity; index += 1) { + key = sourceKeys[index]; + + if (!_hasOwnProperty$1.call(destination, key)) { + destination[key] = source[key]; + overridableKeys[key] = true; + } + } +} + +function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, + startLine, startLineStart, startPos) { + + var index, quantity; + + // The output is a plain object here, so keys can only be strings. + // We need to convert keyNode to a string, but doing so can hang the process + // (deeply nested arrays that explode exponentially using aliases). + if (Array.isArray(keyNode)) { + keyNode = Array.prototype.slice.call(keyNode); + + for (index = 0, quantity = keyNode.length; index < quantity; index += 1) { + if (Array.isArray(keyNode[index])) { + throwError(state, 'nested arrays are not supported inside keys'); + } + + if (typeof keyNode === 'object' && _class(keyNode[index]) === '[object Object]') { + keyNode[index] = '[object Object]'; + } + } + } + + // Avoid code execution in load() via toString property + // (still use its own toString for arrays, timestamps, + // and whatever user schema extensions happen to have @@toStringTag) + if (typeof keyNode === 'object' && _class(keyNode) === '[object Object]') { + keyNode = '[object Object]'; + } + + + keyNode = String(keyNode); + + if (_result === null) { + _result = {}; + } + + if (keyTag === 'tag:yaml.org,2002:merge') { + if (Array.isArray(valueNode)) { + for (index = 0, quantity = valueNode.length; index < quantity; index += 1) { + mergeMappings(state, _result, valueNode[index], overridableKeys); + } + } else { + mergeMappings(state, _result, valueNode, overridableKeys); + } + } else { + if (!state.json && + !_hasOwnProperty$1.call(overridableKeys, keyNode) && + _hasOwnProperty$1.call(_result, keyNode)) { + state.line = startLine || state.line; + state.lineStart = startLineStart || state.lineStart; + state.position = startPos || state.position; + throwError(state, 'duplicated mapping key'); + } + + // used for this specific key only because Object.defineProperty is slow + if (keyNode === '__proto__') { + Object.defineProperty(_result, keyNode, { + configurable: true, + enumerable: true, + writable: true, + value: valueNode + }); + } else { + _result[keyNode] = valueNode; + } + delete overridableKeys[keyNode]; + } + + return _result; +} + +function readLineBreak(state) { + var ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x0A/* LF */) { + state.position++; + } else if (ch === 0x0D/* CR */) { + state.position++; + if (state.input.charCodeAt(state.position) === 0x0A/* LF */) { + state.position++; + } + } else { + throwError(state, 'a line break is expected'); + } + + state.line += 1; + state.lineStart = state.position; + state.firstTabInLine = -1; +} + +function skipSeparationSpace(state, allowComments, checkIndent) { + var lineBreaks = 0, + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + if (ch === 0x09/* Tab */ && state.firstTabInLine === -1) { + state.firstTabInLine = state.position; + } + ch = state.input.charCodeAt(++state.position); + } + + if (allowComments && ch === 0x23/* # */) { + do { + ch = state.input.charCodeAt(++state.position); + } while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && ch !== 0); + } + + if (is_EOL(ch)) { + readLineBreak(state); + + ch = state.input.charCodeAt(state.position); + lineBreaks++; + state.lineIndent = 0; + + while (ch === 0x20/* Space */) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + } else { + break; + } + } + + if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) { + throwWarning(state, 'deficient indentation'); + } + + return lineBreaks; +} + +function testDocumentSeparator(state) { + var _position = state.position, + ch; + + ch = state.input.charCodeAt(_position); + + // Condition state.position === state.lineStart is tested + // in parent on each call, for efficiency. No needs to test here again. + if ((ch === 0x2D/* - */ || ch === 0x2E/* . */) && + ch === state.input.charCodeAt(_position + 1) && + ch === state.input.charCodeAt(_position + 2)) { + + _position += 3; + + ch = state.input.charCodeAt(_position); + + if (ch === 0 || is_WS_OR_EOL(ch)) { + return true; + } + } + + return false; +} + +function writeFoldedLines(state, count) { + if (count === 1) { + state.result += ' '; + } else if (count > 1) { + state.result += common.repeat('\n', count - 1); + } +} + + +function readPlainScalar(state, nodeIndent, withinFlowCollection) { + var preceding, + following, + captureStart, + captureEnd, + hasPendingContent, + _line, + _lineStart, + _lineIndent, + _kind = state.kind, + _result = state.result, + ch; + + ch = state.input.charCodeAt(state.position); + + if (is_WS_OR_EOL(ch) || + is_FLOW_INDICATOR(ch) || + ch === 0x23/* # */ || + ch === 0x26/* & */ || + ch === 0x2A/* * */ || + ch === 0x21/* ! */ || + ch === 0x7C/* | */ || + ch === 0x3E/* > */ || + ch === 0x27/* ' */ || + ch === 0x22/* " */ || + ch === 0x25/* % */ || + ch === 0x40/* @ */ || + ch === 0x60/* ` */) { + return false; + } + + if (ch === 0x3F/* ? */ || ch === 0x2D/* - */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + return false; + } + } + + state.kind = 'scalar'; + state.result = ''; + captureStart = captureEnd = state.position; + hasPendingContent = false; + + while (ch !== 0) { + if (ch === 0x3A/* : */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + break; + } + + } else if (ch === 0x23/* # */) { + preceding = state.input.charCodeAt(state.position - 1); + + if (is_WS_OR_EOL(preceding)) { + break; + } + + } else if ((state.position === state.lineStart && testDocumentSeparator(state)) || + withinFlowCollection && is_FLOW_INDICATOR(ch)) { + break; + + } else if (is_EOL(ch)) { + _line = state.line; + _lineStart = state.lineStart; + _lineIndent = state.lineIndent; + skipSeparationSpace(state, false, -1); + + if (state.lineIndent >= nodeIndent) { + hasPendingContent = true; + ch = state.input.charCodeAt(state.position); + continue; + } else { + state.position = captureEnd; + state.line = _line; + state.lineStart = _lineStart; + state.lineIndent = _lineIndent; + break; + } + } + + if (hasPendingContent) { + captureSegment(state, captureStart, captureEnd, false); + writeFoldedLines(state, state.line - _line); + captureStart = captureEnd = state.position; + hasPendingContent = false; + } + + if (!is_WHITE_SPACE(ch)) { + captureEnd = state.position + 1; + } + + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, captureEnd, false); + + if (state.result) { + return true; + } + + state.kind = _kind; + state.result = _result; + return false; +} + +function readSingleQuotedScalar(state, nodeIndent) { + var ch, + captureStart, captureEnd; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x27/* ' */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x27/* ' */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x27/* ' */) { + captureStart = state.position; + state.position++; + captureEnd = state.position; + } else { + return true; + } + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a single quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a single quoted scalar'); +} + +function readDoubleQuotedScalar(state, nodeIndent) { + var captureStart, + captureEnd, + hexLength, + hexResult, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x22/* " */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x22/* " */) { + captureSegment(state, captureStart, state.position, true); + state.position++; + return true; + + } else if (ch === 0x5C/* \ */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (is_EOL(ch)) { + skipSeparationSpace(state, false, nodeIndent); + + // TODO: rework to inline fn with no type cast? + } else if (ch < 256 && simpleEscapeCheck[ch]) { + state.result += simpleEscapeMap[ch]; + state.position++; + + } else if ((tmp = escapedHexLen(ch)) > 0) { + hexLength = tmp; + hexResult = 0; + + for (; hexLength > 0; hexLength--) { + ch = state.input.charCodeAt(++state.position); + + if ((tmp = fromHexCode(ch)) >= 0) { + hexResult = (hexResult << 4) + tmp; + + } else { + throwError(state, 'expected hexadecimal character'); + } + } + + state.result += charFromCodepoint(hexResult); + + state.position++; + + } else { + throwError(state, 'unknown escape sequence'); + } + + captureStart = captureEnd = state.position; + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a double quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a double quoted scalar'); +} + +function readFlowCollection(state, nodeIndent) { + var readNext = true, + _line, + _lineStart, + _pos, + _tag = state.tag, + _result, + _anchor = state.anchor, + following, + terminator, + isPair, + isExplicitPair, + isMapping, + overridableKeys = Object.create(null), + keyNode, + keyTag, + valueNode, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x5B/* [ */) { + terminator = 0x5D;/* ] */ + isMapping = false; + _result = []; + } else if (ch === 0x7B/* { */) { + terminator = 0x7D;/* } */ + isMapping = true; + _result = {}; + } else { + return false; + } + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(++state.position); + + while (ch !== 0) { + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === terminator) { + state.position++; + state.tag = _tag; + state.anchor = _anchor; + state.kind = isMapping ? 'mapping' : 'sequence'; + state.result = _result; + return true; + } else if (!readNext) { + throwError(state, 'missed comma between flow collection entries'); + } else if (ch === 0x2C/* , */) { + // "flow collection entries can never be completely empty", as per YAML 1.2, section 7.4 + throwError(state, "expected the node content, but found ','"); + } + + keyTag = keyNode = valueNode = null; + isPair = isExplicitPair = false; + + if (ch === 0x3F/* ? */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following)) { + isPair = isExplicitPair = true; + state.position++; + skipSeparationSpace(state, true, nodeIndent); + } + } + + _line = state.line; // Save the current line. + _lineStart = state.lineStart; + _pos = state.position; + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + keyTag = state.tag; + keyNode = state.result; + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if ((isExplicitPair || state.line === _line) && ch === 0x3A/* : */) { + isPair = true; + ch = state.input.charCodeAt(++state.position); + skipSeparationSpace(state, true, nodeIndent); + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + valueNode = state.result; + } + + if (isMapping) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos); + } else if (isPair) { + _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos)); + } else { + _result.push(keyNode); + } + + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x2C/* , */) { + readNext = true; + ch = state.input.charCodeAt(++state.position); + } else { + readNext = false; + } + } + + throwError(state, 'unexpected end of the stream within a flow collection'); +} + +function readBlockScalar(state, nodeIndent) { + var captureStart, + folding, + chomping = CHOMPING_CLIP, + didReadContent = false, + detectedIndent = false, + textIndent = nodeIndent, + emptyLines = 0, + atMoreIndented = false, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x7C/* | */) { + folding = false; + } else if (ch === 0x3E/* > */) { + folding = true; + } else { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + + while (ch !== 0) { + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { + if (CHOMPING_CLIP === chomping) { + chomping = (ch === 0x2B/* + */) ? CHOMPING_KEEP : CHOMPING_STRIP; + } else { + throwError(state, 'repeat of a chomping mode identifier'); + } + + } else if ((tmp = fromDecimalCode(ch)) >= 0) { + if (tmp === 0) { + throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one'); + } else if (!detectedIndent) { + textIndent = nodeIndent + tmp - 1; + detectedIndent = true; + } else { + throwError(state, 'repeat of an indentation width identifier'); + } + + } else { + break; + } + } + + if (is_WHITE_SPACE(ch)) { + do { ch = state.input.charCodeAt(++state.position); } + while (is_WHITE_SPACE(ch)); + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (!is_EOL(ch) && (ch !== 0)); + } + } + + while (ch !== 0) { + readLineBreak(state); + state.lineIndent = 0; + + ch = state.input.charCodeAt(state.position); + + while ((!detectedIndent || state.lineIndent < textIndent) && + (ch === 0x20/* Space */)) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + + if (!detectedIndent && state.lineIndent > textIndent) { + textIndent = state.lineIndent; + } + + if (is_EOL(ch)) { + emptyLines++; + continue; + } + + // End of the scalar. + if (state.lineIndent < textIndent) { + + // Perform the chomping. + if (chomping === CHOMPING_KEEP) { + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } else if (chomping === CHOMPING_CLIP) { + if (didReadContent) { // i.e. only if the scalar is not empty. + state.result += '\n'; + } + } + + // Break this `while` cycle and go to the funciton's epilogue. + break; + } + + // Folded style: use fancy rules to handle line breaks. + if (folding) { + + // Lines starting with white space characters (more-indented lines) are not folded. + if (is_WHITE_SPACE(ch)) { + atMoreIndented = true; + // except for the first content line (cf. Example 8.1) + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + + // End of more-indented block. + } else if (atMoreIndented) { + atMoreIndented = false; + state.result += common.repeat('\n', emptyLines + 1); + + // Just one line break - perceive as the same line. + } else if (emptyLines === 0) { + if (didReadContent) { // i.e. only if we have already read some scalar content. + state.result += ' '; + } + + // Several line breaks - perceive as different lines. + } else { + state.result += common.repeat('\n', emptyLines); + } + + // Literal style: just add exact number of line breaks between content lines. + } else { + // Keep all line breaks except the header line break. + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } + + didReadContent = true; + detectedIndent = true; + emptyLines = 0; + captureStart = state.position; + + while (!is_EOL(ch) && (ch !== 0)) { + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, state.position, false); + } + + return true; +} + +function readBlockSequence(state, nodeIndent) { + var _line, + _tag = state.tag, + _anchor = state.anchor, + _result = [], + following, + detected = false, + ch; + + // there is a leading tab before this token, so it can't be a block sequence/mapping; + // it can still be flow sequence/mapping or a scalar + if (state.firstTabInLine !== -1) return false; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + if (state.firstTabInLine !== -1) { + state.position = state.firstTabInLine; + throwError(state, 'tab characters must not be used in indentation'); + } + + if (ch !== 0x2D/* - */) { + break; + } + + following = state.input.charCodeAt(state.position + 1); + + if (!is_WS_OR_EOL(following)) { + break; + } + + detected = true; + state.position++; + + if (skipSeparationSpace(state, true, -1)) { + if (state.lineIndent <= nodeIndent) { + _result.push(null); + ch = state.input.charCodeAt(state.position); + continue; + } + } + + _line = state.line; + composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true); + _result.push(state.result); + skipSeparationSpace(state, true, -1); + + ch = state.input.charCodeAt(state.position); + + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a sequence entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'sequence'; + state.result = _result; + return true; + } + return false; +} + +function readBlockMapping(state, nodeIndent, flowIndent) { + var following, + allowCompact, + _line, + _keyLine, + _keyLineStart, + _keyPos, + _tag = state.tag, + _anchor = state.anchor, + _result = {}, + overridableKeys = Object.create(null), + keyTag = null, + keyNode = null, + valueNode = null, + atExplicitKey = false, + detected = false, + ch; + + // there is a leading tab before this token, so it can't be a block sequence/mapping; + // it can still be flow sequence/mapping or a scalar + if (state.firstTabInLine !== -1) return false; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + if (!atExplicitKey && state.firstTabInLine !== -1) { + state.position = state.firstTabInLine; + throwError(state, 'tab characters must not be used in indentation'); + } + + following = state.input.charCodeAt(state.position + 1); + _line = state.line; // Save the current line. + + // + // Explicit notation case. There are two separate blocks: + // first for the key (denoted by "?") and second for the value (denoted by ":") + // + if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && is_WS_OR_EOL(following)) { + + if (ch === 0x3F/* ? */) { + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + + detected = true; + atExplicitKey = true; + allowCompact = true; + + } else if (atExplicitKey) { + // i.e. 0x3A/* : */ === character after the explicit key. + atExplicitKey = false; + allowCompact = true; + + } else { + throwError(state, 'incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line'); + } + + state.position += 1; + ch = following; + + // + // Implicit notation case. Flow-style node as the key first, then ":", and the value. + // + } else { + _keyLine = state.line; + _keyLineStart = state.lineStart; + _keyPos = state.position; + + if (!composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) { + // Neither implicit nor explicit notation. + // Reading is done. Go to the epilogue. + break; + } + + if (state.line === _line) { + ch = state.input.charCodeAt(state.position); + + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (ch === 0x3A/* : */) { + ch = state.input.charCodeAt(++state.position); + + if (!is_WS_OR_EOL(ch)) { + throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping'); + } + + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + + detected = true; + atExplicitKey = false; + allowCompact = false; + keyTag = state.tag; + keyNode = state.result; + + } else if (detected) { + throwError(state, 'can not read an implicit mapping pair; a colon is missed'); + + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + + } else if (detected) { + throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key'); + + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + } + + // + // Common reading code for both explicit and implicit notations. + // + if (state.line === _line || state.lineIndent > nodeIndent) { + if (atExplicitKey) { + _keyLine = state.line; + _keyLineStart = state.lineStart; + _keyPos = state.position; + } + + if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) { + if (atExplicitKey) { + keyNode = state.result; + } else { + valueNode = state.result; + } + } + + if (!atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + } + + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a mapping entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + + // + // Epilogue. + // + + // Special case: last mapping's node contains only the key in explicit notation. + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + } + + // Expose the resulting mapping. + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'mapping'; + state.result = _result; + } + + return detected; +} + +function readTagProperty(state) { + var _position, + isVerbatim = false, + isNamed = false, + tagHandle, + tagName, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x21/* ! */) return false; + + if (state.tag !== null) { + throwError(state, 'duplication of a tag property'); + } + + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x3C/* < */) { + isVerbatim = true; + ch = state.input.charCodeAt(++state.position); + + } else if (ch === 0x21/* ! */) { + isNamed = true; + tagHandle = '!!'; + ch = state.input.charCodeAt(++state.position); + + } else { + tagHandle = '!'; + } + + _position = state.position; + + if (isVerbatim) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && ch !== 0x3E/* > */); + + if (state.position < state.length) { + tagName = state.input.slice(_position, state.position); + ch = state.input.charCodeAt(++state.position); + } else { + throwError(state, 'unexpected end of the stream within a verbatim tag'); + } + } else { + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + + if (ch === 0x21/* ! */) { + if (!isNamed) { + tagHandle = state.input.slice(_position - 1, state.position + 1); + + if (!PATTERN_TAG_HANDLE.test(tagHandle)) { + throwError(state, 'named tag handle cannot contain such characters'); + } + + isNamed = true; + _position = state.position + 1; + } else { + throwError(state, 'tag suffix cannot contain exclamation marks'); + } + } + + ch = state.input.charCodeAt(++state.position); + } + + tagName = state.input.slice(_position, state.position); + + if (PATTERN_FLOW_INDICATORS.test(tagName)) { + throwError(state, 'tag suffix cannot contain flow indicator characters'); + } + } + + if (tagName && !PATTERN_TAG_URI.test(tagName)) { + throwError(state, 'tag name cannot contain such characters: ' + tagName); + } + + try { + tagName = decodeURIComponent(tagName); + } catch (err) { + throwError(state, 'tag name is malformed: ' + tagName); + } + + if (isVerbatim) { + state.tag = tagName; + + } else if (_hasOwnProperty$1.call(state.tagMap, tagHandle)) { + state.tag = state.tagMap[tagHandle] + tagName; + + } else if (tagHandle === '!') { + state.tag = '!' + tagName; + + } else if (tagHandle === '!!') { + state.tag = 'tag:yaml.org,2002:' + tagName; + + } else { + throwError(state, 'undeclared tag handle "' + tagHandle + '"'); + } + + return true; +} + +function readAnchorProperty(state) { + var _position, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x26/* & */) return false; + + if (state.anchor !== null) { + throwError(state, 'duplication of an anchor property'); + } + + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (state.position === _position) { + throwError(state, 'name of an anchor node must contain at least one character'); + } + + state.anchor = state.input.slice(_position, state.position); + return true; +} + +function readAlias(state) { + var _position, alias, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x2A/* * */) return false; + + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (state.position === _position) { + throwError(state, 'name of an alias node must contain at least one character'); + } + + alias = state.input.slice(_position, state.position); + + if (!_hasOwnProperty$1.call(state.anchorMap, alias)) { + throwError(state, 'unidentified alias "' + alias + '"'); + } + + state.result = state.anchorMap[alias]; + skipSeparationSpace(state, true, -1); + return true; +} + +function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) { + var allowBlockStyles, + allowBlockScalars, + allowBlockCollections, + indentStatus = 1, // 1: this>parent, 0: this=parent, -1: this parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } + } + + if (indentStatus === 1) { + while (readTagProperty(state) || readAnchorProperty(state)) { + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + allowBlockCollections = allowBlockStyles; + + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } else { + allowBlockCollections = false; + } + } + } + + if (allowBlockCollections) { + allowBlockCollections = atNewLine || allowCompact; + } + + if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) { + if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) { + flowIndent = parentIndent; + } else { + flowIndent = parentIndent + 1; + } + + blockIndent = state.position - state.lineStart; + + if (indentStatus === 1) { + if (allowBlockCollections && + (readBlockSequence(state, blockIndent) || + readBlockMapping(state, blockIndent, flowIndent)) || + readFlowCollection(state, flowIndent)) { + hasContent = true; + } else { + if ((allowBlockScalars && readBlockScalar(state, flowIndent)) || + readSingleQuotedScalar(state, flowIndent) || + readDoubleQuotedScalar(state, flowIndent)) { + hasContent = true; + + } else if (readAlias(state)) { + hasContent = true; + + if (state.tag !== null || state.anchor !== null) { + throwError(state, 'alias node should not have any properties'); + } + + } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) { + hasContent = true; + + if (state.tag === null) { + state.tag = '?'; + } + } + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } else if (indentStatus === 0) { + // Special case: block sequences are allowed to have same indentation level as the parent. + // http://www.yaml.org/spec/1.2/spec.html#id2799784 + hasContent = allowBlockCollections && readBlockSequence(state, blockIndent); + } + } + + if (state.tag === null) { + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + + } else if (state.tag === '?') { + // Implicit resolving is not allowed for non-scalar types, and '?' + // non-specific tag is only automatically assigned to plain scalars. + // + // We only need to check kind conformity in case user explicitly assigns '?' + // tag, for example like this: "! [0]" + // + if (state.result !== null && state.kind !== 'scalar') { + throwError(state, 'unacceptable node kind for ! tag; it should be "scalar", not "' + state.kind + '"'); + } + + for (typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) { + type = state.implicitTypes[typeIndex]; + + if (type.resolve(state.result)) { // `state.result` updated in resolver if matched + state.result = type.construct(state.result); + state.tag = type.tag; + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + break; + } + } + } else if (state.tag !== '!') { + if (_hasOwnProperty$1.call(state.typeMap[state.kind || 'fallback'], state.tag)) { + type = state.typeMap[state.kind || 'fallback'][state.tag]; + } else { + // looking for multi type + type = null; + typeList = state.typeMap.multi[state.kind || 'fallback']; + + for (typeIndex = 0, typeQuantity = typeList.length; typeIndex < typeQuantity; typeIndex += 1) { + if (state.tag.slice(0, typeList[typeIndex].tag.length) === typeList[typeIndex].tag) { + type = typeList[typeIndex]; + break; + } + } + } + + if (!type) { + throwError(state, 'unknown tag !<' + state.tag + '>'); + } + + if (state.result !== null && type.kind !== state.kind) { + throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"'); + } + + if (!type.resolve(state.result, state.tag)) { // `state.result` updated in resolver if matched + throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag'); + } else { + state.result = type.construct(state.result, state.tag); + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } + + if (state.listener !== null) { + state.listener('close', state); + } + return state.tag !== null || state.anchor !== null || hasContent; +} + +function readDocument(state) { + var documentStart = state.position, + _position, + directiveName, + directiveArgs, + hasDirectives = false, + ch; + + state.version = null; + state.checkLineBreaks = state.legacy; + state.tagMap = Object.create(null); + state.anchorMap = Object.create(null); + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + skipSeparationSpace(state, true, -1); + + ch = state.input.charCodeAt(state.position); + + if (state.lineIndent > 0 || ch !== 0x25/* % */) { + break; + } + + hasDirectives = true; + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + directiveName = state.input.slice(_position, state.position); + directiveArgs = []; + + if (directiveName.length < 1) { + throwError(state, 'directive name must not be less than one character in length'); + } + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && !is_EOL(ch)); + break; + } + + if (is_EOL(ch)) break; + + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + directiveArgs.push(state.input.slice(_position, state.position)); + } + + if (ch !== 0) readLineBreak(state); + + if (_hasOwnProperty$1.call(directiveHandlers, directiveName)) { + directiveHandlers[directiveName](state, directiveName, directiveArgs); + } else { + throwWarning(state, 'unknown document directive "' + directiveName + '"'); + } + } + + skipSeparationSpace(state, true, -1); + + if (state.lineIndent === 0 && + state.input.charCodeAt(state.position) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 1) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 2) === 0x2D/* - */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + + } else if (hasDirectives) { + throwError(state, 'directives end mark is expected'); + } + + composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true); + skipSeparationSpace(state, true, -1); + + if (state.checkLineBreaks && + PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) { + throwWarning(state, 'non-ASCII line breaks are interpreted as content'); + } + + state.documents.push(state.result); + + if (state.position === state.lineStart && testDocumentSeparator(state)) { + + if (state.input.charCodeAt(state.position) === 0x2E/* . */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + } + return; + } + + if (state.position < (state.length - 1)) { + throwError(state, 'end of the stream or a document separator is expected'); + } else { + return; + } +} + + +function loadDocuments(input, options) { + input = String(input); + options = options || {}; + + if (input.length !== 0) { + + // Add tailing `\n` if not exists + if (input.charCodeAt(input.length - 1) !== 0x0A/* LF */ && + input.charCodeAt(input.length - 1) !== 0x0D/* CR */) { + input += '\n'; + } + + // Strip BOM + if (input.charCodeAt(0) === 0xFEFF) { + input = input.slice(1); + } + } + + var state = new State$1(input, options); + + var nullpos = input.indexOf('\0'); + + if (nullpos !== -1) { + state.position = nullpos; + throwError(state, 'null byte is not allowed in input'); + } + + // Use 0 as string terminator. That significantly simplifies bounds check. + state.input += '\0'; + + while (state.input.charCodeAt(state.position) === 0x20/* Space */) { + state.lineIndent += 1; + state.position += 1; + } + + while (state.position < (state.length - 1)) { + readDocument(state); + } + + return state.documents; +} + + +function loadAll$1(input, iterator, options) { + if (iterator !== null && typeof iterator === 'object' && typeof options === 'undefined') { + options = iterator; + iterator = null; + } + + var documents = loadDocuments(input, options); + + if (typeof iterator !== 'function') { + return documents; + } + + for (var index = 0, length = documents.length; index < length; index += 1) { + iterator(documents[index]); + } +} + + +function load$1(input, options) { + var documents = loadDocuments(input, options); + + if (documents.length === 0) { + /*eslint-disable no-undefined*/ + return undefined; + } else if (documents.length === 1) { + return documents[0]; + } + throw new exception('expected a single document in the stream, but found more'); +} + + +var loadAll_1 = loadAll$1; +var load_1 = load$1; + +var loader = { + loadAll: loadAll_1, + load: load_1 +}; + +/*eslint-disable no-use-before-define*/ + + + + + +var _toString = Object.prototype.toString; +var _hasOwnProperty = Object.prototype.hasOwnProperty; + +var CHAR_BOM = 0xFEFF; +var CHAR_TAB = 0x09; /* Tab */ +var CHAR_LINE_FEED = 0x0A; /* LF */ +var CHAR_CARRIAGE_RETURN = 0x0D; /* CR */ +var CHAR_SPACE = 0x20; /* Space */ +var CHAR_EXCLAMATION = 0x21; /* ! */ +var CHAR_DOUBLE_QUOTE = 0x22; /* " */ +var CHAR_SHARP = 0x23; /* # */ +var CHAR_PERCENT = 0x25; /* % */ +var CHAR_AMPERSAND = 0x26; /* & */ +var CHAR_SINGLE_QUOTE = 0x27; /* ' */ +var CHAR_ASTERISK = 0x2A; /* * */ +var CHAR_COMMA = 0x2C; /* , */ +var CHAR_MINUS = 0x2D; /* - */ +var CHAR_COLON = 0x3A; /* : */ +var CHAR_EQUALS = 0x3D; /* = */ +var CHAR_GREATER_THAN = 0x3E; /* > */ +var CHAR_QUESTION = 0x3F; /* ? */ +var CHAR_COMMERCIAL_AT = 0x40; /* @ */ +var CHAR_LEFT_SQUARE_BRACKET = 0x5B; /* [ */ +var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */ +var CHAR_GRAVE_ACCENT = 0x60; /* ` */ +var CHAR_LEFT_CURLY_BRACKET = 0x7B; /* { */ +var CHAR_VERTICAL_LINE = 0x7C; /* | */ +var CHAR_RIGHT_CURLY_BRACKET = 0x7D; /* } */ + +var ESCAPE_SEQUENCES = {}; + +ESCAPE_SEQUENCES[0x00] = '\\0'; +ESCAPE_SEQUENCES[0x07] = '\\a'; +ESCAPE_SEQUENCES[0x08] = '\\b'; +ESCAPE_SEQUENCES[0x09] = '\\t'; +ESCAPE_SEQUENCES[0x0A] = '\\n'; +ESCAPE_SEQUENCES[0x0B] = '\\v'; +ESCAPE_SEQUENCES[0x0C] = '\\f'; +ESCAPE_SEQUENCES[0x0D] = '\\r'; +ESCAPE_SEQUENCES[0x1B] = '\\e'; +ESCAPE_SEQUENCES[0x22] = '\\"'; +ESCAPE_SEQUENCES[0x5C] = '\\\\'; +ESCAPE_SEQUENCES[0x85] = '\\N'; +ESCAPE_SEQUENCES[0xA0] = '\\_'; +ESCAPE_SEQUENCES[0x2028] = '\\L'; +ESCAPE_SEQUENCES[0x2029] = '\\P'; + +var DEPRECATED_BOOLEANS_SYNTAX = [ + 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON', + 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF' +]; + +var DEPRECATED_BASE60_SYNTAX = /^[-+]?[0-9_]+(?::[0-9_]+)+(?:\.[0-9_]*)?$/; + +function compileStyleMap(schema, map) { + var result, keys, index, length, tag, style, type; + + if (map === null) return {}; + + result = {}; + keys = Object.keys(map); + + for (index = 0, length = keys.length; index < length; index += 1) { + tag = keys[index]; + style = String(map[tag]); + + if (tag.slice(0, 2) === '!!') { + tag = 'tag:yaml.org,2002:' + tag.slice(2); + } + type = schema.compiledTypeMap['fallback'][tag]; + + if (type && _hasOwnProperty.call(type.styleAliases, style)) { + style = type.styleAliases[style]; + } + + result[tag] = style; + } + + return result; +} + +function encodeHex(character) { + var string, handle, length; + + string = character.toString(16).toUpperCase(); + + if (character <= 0xFF) { + handle = 'x'; + length = 2; + } else if (character <= 0xFFFF) { + handle = 'u'; + length = 4; + } else if (character <= 0xFFFFFFFF) { + handle = 'U'; + length = 8; + } else { + throw new exception('code point within a string may not be greater than 0xFFFFFFFF'); + } + + return '\\' + handle + common.repeat('0', length - string.length) + string; +} + + +var QUOTING_TYPE_SINGLE = 1, + QUOTING_TYPE_DOUBLE = 2; + +function State(options) { + this.schema = options['schema'] || _default; + this.indent = Math.max(1, (options['indent'] || 2)); + this.noArrayIndent = options['noArrayIndent'] || false; + this.skipInvalid = options['skipInvalid'] || false; + this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']); + this.styleMap = compileStyleMap(this.schema, options['styles'] || null); + this.sortKeys = options['sortKeys'] || false; + this.lineWidth = options['lineWidth'] || 80; + this.noRefs = options['noRefs'] || false; + this.noCompatMode = options['noCompatMode'] || false; + this.condenseFlow = options['condenseFlow'] || false; + this.quotingType = options['quotingType'] === '"' ? QUOTING_TYPE_DOUBLE : QUOTING_TYPE_SINGLE; + this.forceQuotes = options['forceQuotes'] || false; + this.replacer = typeof options['replacer'] === 'function' ? options['replacer'] : null; + + this.implicitTypes = this.schema.compiledImplicit; + this.explicitTypes = this.schema.compiledExplicit; + + this.tag = null; + this.result = ''; + + this.duplicates = []; + this.usedDuplicates = null; +} + +// Indents every line in a string. Empty lines (\n only) are not indented. +function indentString(string, spaces) { + var ind = common.repeat(' ', spaces), + position = 0, + next = -1, + result = '', + line, + length = string.length; + + while (position < length) { + next = string.indexOf('\n', position); + if (next === -1) { + line = string.slice(position); + position = length; + } else { + line = string.slice(position, next + 1); + position = next + 1; + } + + if (line.length && line !== '\n') result += ind; + + result += line; + } + + return result; +} + +function generateNextLine(state, level) { + return '\n' + common.repeat(' ', state.indent * level); +} + +function testImplicitResolving(state, str) { + var index, length, type; + + for (index = 0, length = state.implicitTypes.length; index < length; index += 1) { + type = state.implicitTypes[index]; + + if (type.resolve(str)) { + return true; + } + } + + return false; +} + +// [33] s-white ::= s-space | s-tab +function isWhitespace(c) { + return c === CHAR_SPACE || c === CHAR_TAB; +} + +// Returns true if the character can be printed without escaping. +// From YAML 1.2: "any allowed characters known to be non-printable +// should also be escaped. [However,] This isn’t mandatory" +// Derived from nb-char - \t - #x85 - #xA0 - #x2028 - #x2029. +function isPrintable(c) { + return (0x00020 <= c && c <= 0x00007E) + || ((0x000A1 <= c && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029) + || ((0x0E000 <= c && c <= 0x00FFFD) && c !== CHAR_BOM) + || (0x10000 <= c && c <= 0x10FFFF); +} + +// [34] ns-char ::= nb-char - s-white +// [27] nb-char ::= c-printable - b-char - c-byte-order-mark +// [26] b-char ::= b-line-feed | b-carriage-return +// Including s-white (for some reason, examples doesn't match specs in this aspect) +// ns-char ::= c-printable - b-line-feed - b-carriage-return - c-byte-order-mark +function isNsCharOrWhitespace(c) { + return isPrintable(c) + && c !== CHAR_BOM + // - b-char + && c !== CHAR_CARRIAGE_RETURN + && c !== CHAR_LINE_FEED; +} + +// [127] ns-plain-safe(c) ::= c = flow-out ⇒ ns-plain-safe-out +// c = flow-in ⇒ ns-plain-safe-in +// c = block-key ⇒ ns-plain-safe-out +// c = flow-key ⇒ ns-plain-safe-in +// [128] ns-plain-safe-out ::= ns-char +// [129] ns-plain-safe-in ::= ns-char - c-flow-indicator +// [130] ns-plain-char(c) ::= ( ns-plain-safe(c) - “:” - “#” ) +// | ( /* An ns-char preceding */ “#” ) +// | ( “:” /* Followed by an ns-plain-safe(c) */ ) +function isPlainSafe(c, prev, inblock) { + var cIsNsCharOrWhitespace = isNsCharOrWhitespace(c); + var cIsNsChar = cIsNsCharOrWhitespace && !isWhitespace(c); + return ( + // ns-plain-safe + inblock ? // c = flow-in + cIsNsCharOrWhitespace + : cIsNsCharOrWhitespace + // - c-flow-indicator + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + ) + // ns-plain-char + && c !== CHAR_SHARP // false on '#' + && !(prev === CHAR_COLON && !cIsNsChar) // false on ': ' + || (isNsCharOrWhitespace(prev) && !isWhitespace(prev) && c === CHAR_SHARP) // change to true on '[^ ]#' + || (prev === CHAR_COLON && cIsNsChar); // change to true on ':[^ ]' +} + +// Simplified test for values allowed as the first character in plain style. +function isPlainSafeFirst(c) { + // Uses a subset of ns-char - c-indicator + // where ns-char = nb-char - s-white. + // No support of ( ( “?” | “:” | “-” ) /* Followed by an ns-plain-safe(c)) */ ) part + return isPrintable(c) && c !== CHAR_BOM + && !isWhitespace(c) // - s-white + // - (c-indicator ::= + // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}” + && c !== CHAR_MINUS + && c !== CHAR_QUESTION + && c !== CHAR_COLON + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + // | “#” | “&” | “*” | “!” | “|” | “=” | “>” | “'” | “"” + && c !== CHAR_SHARP + && c !== CHAR_AMPERSAND + && c !== CHAR_ASTERISK + && c !== CHAR_EXCLAMATION + && c !== CHAR_VERTICAL_LINE + && c !== CHAR_EQUALS + && c !== CHAR_GREATER_THAN + && c !== CHAR_SINGLE_QUOTE + && c !== CHAR_DOUBLE_QUOTE + // | “%” | “@” | “`”) + && c !== CHAR_PERCENT + && c !== CHAR_COMMERCIAL_AT + && c !== CHAR_GRAVE_ACCENT; +} + +// Simplified test for values allowed as the last character in plain style. +function isPlainSafeLast(c) { + // just not whitespace or colon, it will be checked to be plain character later + return !isWhitespace(c) && c !== CHAR_COLON; +} + +// Same as 'string'.codePointAt(pos), but works in older browsers. +function codePointAt(string, pos) { + var first = string.charCodeAt(pos), second; + if (first >= 0xD800 && first <= 0xDBFF && pos + 1 < string.length) { + second = string.charCodeAt(pos + 1); + if (second >= 0xDC00 && second <= 0xDFFF) { + // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; + } + } + return first; +} + +// Determines whether block indentation indicator is required. +function needIndentIndicator(string) { + var leadingSpaceRe = /^\n* /; + return leadingSpaceRe.test(string); +} + +var STYLE_PLAIN = 1, + STYLE_SINGLE = 2, + STYLE_LITERAL = 3, + STYLE_FOLDED = 4, + STYLE_DOUBLE = 5; + +// Determines which scalar styles are possible and returns the preferred style. +// lineWidth = -1 => no limit. +// Pre-conditions: str.length > 0. +// Post-conditions: +// STYLE_PLAIN or STYLE_SINGLE => no \n are in the string. +// STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1). +// STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1). +function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, + testAmbiguousType, quotingType, forceQuotes, inblock) { + + var i; + var char = 0; + var prevChar = null; + var hasLineBreak = false; + var hasFoldableLine = false; // only checked if shouldTrackWidth + var shouldTrackWidth = lineWidth !== -1; + var previousLineBreak = -1; // count the first line correctly + var plain = isPlainSafeFirst(codePointAt(string, 0)) + && isPlainSafeLast(codePointAt(string, string.length - 1)); + + if (singleLineOnly || forceQuotes) { + // Case: no block styles. + // Check for disallowed characters to rule out plain and single. + for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char, prevChar, inblock); + prevChar = char; + } + } else { + // Case: block styles permitted. + for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + if (char === CHAR_LINE_FEED) { + hasLineBreak = true; + // Check if any line can be folded. + if (shouldTrackWidth) { + hasFoldableLine = hasFoldableLine || + // Foldable line = too long, and not more-indented. + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' '); + previousLineBreak = i; + } + } else if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char, prevChar, inblock); + prevChar = char; + } + // in case the end is missing a \n + hasFoldableLine = hasFoldableLine || (shouldTrackWidth && + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' ')); + } + // Although every style can represent \n without escaping, prefer block styles + // for multiline, since they're more readable and they don't add empty lines. + // Also prefer folding a super-long line. + if (!hasLineBreak && !hasFoldableLine) { + // Strings interpretable as another type have to be quoted; + // e.g. the string 'true' vs. the boolean true. + if (plain && !forceQuotes && !testAmbiguousType(string)) { + return STYLE_PLAIN; + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE; + } + // Edge case: block indentation indicator can only have one digit. + if (indentPerLevel > 9 && needIndentIndicator(string)) { + return STYLE_DOUBLE; + } + // At this point we know block styles are valid. + // Prefer literal style unless we want to fold. + if (!forceQuotes) { + return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL; + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE; +} + +// Note: line breaking/folding is implemented for only the folded style. +// NB. We drop the last trailing newline (if any) of a returned block scalar +// since the dumper adds its own newline. This always works: +// • No ending newline => unaffected; already using strip "-" chomping. +// • Ending newline => removed then restored. +// Importantly, this keeps the "+" chomp indicator from gaining an extra line. +function writeScalar(state, string, level, iskey, inblock) { + state.dump = (function () { + if (string.length === 0) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? '""' : "''"; + } + if (!state.noCompatMode) { + if (DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1 || DEPRECATED_BASE60_SYNTAX.test(string)) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? ('"' + string + '"') : ("'" + string + "'"); + } + } + + var indent = state.indent * Math.max(1, level); // no 0-indent scalars + // As indentation gets deeper, let the width decrease monotonically + // to the lower bound min(state.lineWidth, 40). + // Note that this implies + // state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound. + // state.lineWidth > 40 + state.indent: width decreases until the lower bound. + // This behaves better than a constant minimum width which disallows narrower options, + // or an indent threshold which causes the width to suddenly increase. + var lineWidth = state.lineWidth === -1 + ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent); + + // Without knowing if keys are implicit/explicit, assume implicit for safety. + var singleLineOnly = iskey + // No block styles in flow mode. + || (state.flowLevel > -1 && level >= state.flowLevel); + function testAmbiguity(string) { + return testImplicitResolving(state, string); + } + + switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, + testAmbiguity, state.quotingType, state.forceQuotes && !iskey, inblock)) { + + case STYLE_PLAIN: + return string; + case STYLE_SINGLE: + return "'" + string.replace(/'/g, "''") + "'"; + case STYLE_LITERAL: + return '|' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(string, indent)); + case STYLE_FOLDED: + return '>' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(foldString(string, lineWidth), indent)); + case STYLE_DOUBLE: + return '"' + escapeString(string) + '"'; + default: + throw new exception('impossible error: invalid scalar style'); + } + }()); +} + +// Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9. +function blockHeader(string, indentPerLevel) { + var indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : ''; + + // note the special case: the string '\n' counts as a "trailing" empty line. + var clip = string[string.length - 1] === '\n'; + var keep = clip && (string[string.length - 2] === '\n' || string === '\n'); + var chomp = keep ? '+' : (clip ? '' : '-'); + + return indentIndicator + chomp + '\n'; +} + +// (See the note for writeScalar.) +function dropEndingNewline(string) { + return string[string.length - 1] === '\n' ? string.slice(0, -1) : string; +} + +// Note: a long line without a suitable break point will exceed the width limit. +// Pre-conditions: every char in str isPrintable, str.length > 0, width > 0. +function foldString(string, width) { + // In folded style, $k$ consecutive newlines output as $k+1$ newlines— + // unless they're before or after a more-indented line, or at the very + // beginning or end, in which case $k$ maps to $k$. + // Therefore, parse each chunk as newline(s) followed by a content line. + var lineRe = /(\n+)([^\n]*)/g; + + // first line (possibly an empty line) + var result = (function () { + var nextLF = string.indexOf('\n'); + nextLF = nextLF !== -1 ? nextLF : string.length; + lineRe.lastIndex = nextLF; + return foldLine(string.slice(0, nextLF), width); + }()); + // If we haven't reached the first content line yet, don't add an extra \n. + var prevMoreIndented = string[0] === '\n' || string[0] === ' '; + var moreIndented; + + // rest of the lines + var match; + while ((match = lineRe.exec(string))) { + var prefix = match[1], line = match[2]; + moreIndented = (line[0] === ' '); + result += prefix + + (!prevMoreIndented && !moreIndented && line !== '' + ? '\n' : '') + + foldLine(line, width); + prevMoreIndented = moreIndented; + } + + return result; +} + +// Greedy line breaking. +// Picks the longest line under the limit each time, +// otherwise settles for the shortest line over the limit. +// NB. More-indented lines *cannot* be folded, as that would add an extra \n. +function foldLine(line, width) { + if (line === '' || line[0] === ' ') return line; + + // Since a more-indented line adds a \n, breaks can't be followed by a space. + var breakRe = / [^ ]/g; // note: the match index will always be <= length-2. + var match; + // start is an inclusive index. end, curr, and next are exclusive. + var start = 0, end, curr = 0, next = 0; + var result = ''; + + // Invariants: 0 <= start <= length-1. + // 0 <= curr <= next <= max(0, length-2). curr - start <= width. + // Inside the loop: + // A match implies length >= 2, so curr and next are <= length-2. + while ((match = breakRe.exec(line))) { + next = match.index; + // maintain invariant: curr - start <= width + if (next - start > width) { + end = (curr > start) ? curr : next; // derive end <= length-2 + result += '\n' + line.slice(start, end); + // skip the space that was output as \n + start = end + 1; // derive start <= length-1 + } + curr = next; + } + + // By the invariants, start <= length-1, so there is something left over. + // It is either the whole string or a part starting from non-whitespace. + result += '\n'; + // Insert a break if the remainder is too long and there is a break available. + if (line.length - start > width && curr > start) { + result += line.slice(start, curr) + '\n' + line.slice(curr + 1); + } else { + result += line.slice(start); + } + + return result.slice(1); // drop extra \n joiner +} + +// Escapes a double-quoted string. +function escapeString(string) { + var result = ''; + var char = 0; + var escapeSeq; + + for (var i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + escapeSeq = ESCAPE_SEQUENCES[char]; + + if (!escapeSeq && isPrintable(char)) { + result += string[i]; + if (char >= 0x10000) result += string[i + 1]; + } else { + result += escapeSeq || encodeHex(char); + } + } + + return result; +} + +function writeFlowSequence(state, level, object) { + var _result = '', + _tag = state.tag, + index, + length, + value; + + for (index = 0, length = object.length; index < length; index += 1) { + value = object[index]; + + if (state.replacer) { + value = state.replacer.call(object, String(index), value); + } + + // Write only valid elements, put null instead of invalid elements. + if (writeNode(state, level, value, false, false) || + (typeof value === 'undefined' && + writeNode(state, level, null, false, false))) { + + if (_result !== '') _result += ',' + (!state.condenseFlow ? ' ' : ''); + _result += state.dump; + } + } + + state.tag = _tag; + state.dump = '[' + _result + ']'; +} + +function writeBlockSequence(state, level, object, compact) { + var _result = '', + _tag = state.tag, + index, + length, + value; + + for (index = 0, length = object.length; index < length; index += 1) { + value = object[index]; + + if (state.replacer) { + value = state.replacer.call(object, String(index), value); + } + + // Write only valid elements, put null instead of invalid elements. + if (writeNode(state, level + 1, value, true, true, false, true) || + (typeof value === 'undefined' && + writeNode(state, level + 1, null, true, true, false, true))) { + + if (!compact || _result !== '') { + _result += generateNextLine(state, level); + } + + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + _result += '-'; + } else { + _result += '- '; + } + + _result += state.dump; + } + } + + state.tag = _tag; + state.dump = _result || '[]'; // Empty sequence if no valid values. +} + +function writeFlowMapping(state, level, object) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + pairBuffer; + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + + pairBuffer = ''; + if (_result !== '') pairBuffer += ', '; + + if (state.condenseFlow) pairBuffer += '"'; + + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue); + } + + if (!writeNode(state, level, objectKey, false, false)) { + continue; // Skip this pair because of invalid key; + } + + if (state.dump.length > 1024) pairBuffer += '? '; + + pairBuffer += state.dump + (state.condenseFlow ? '"' : '') + ':' + (state.condenseFlow ? '' : ' '); + + if (!writeNode(state, level, objectValue, false, false)) { + continue; // Skip this pair because of invalid value. + } + + pairBuffer += state.dump; + + // Both key and value are valid. + _result += pairBuffer; + } + + state.tag = _tag; + state.dump = '{' + _result + '}'; +} + +function writeBlockMapping(state, level, object, compact) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + explicitPair, + pairBuffer; + + // Allow sorting keys so that the output file is deterministic + if (state.sortKeys === true) { + // Default sorting + objectKeyList.sort(); + } else if (typeof state.sortKeys === 'function') { + // Custom sort function + objectKeyList.sort(state.sortKeys); + } else if (state.sortKeys) { + // Something is wrong + throw new exception('sortKeys must be a boolean or a function'); + } + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + pairBuffer = ''; + + if (!compact || _result !== '') { + pairBuffer += generateNextLine(state, level); + } + + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue); + } + + if (!writeNode(state, level + 1, objectKey, true, true, true)) { + continue; // Skip this pair because of invalid key. + } + + explicitPair = (state.tag !== null && state.tag !== '?') || + (state.dump && state.dump.length > 1024); + + if (explicitPair) { + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += '?'; + } else { + pairBuffer += '? '; + } + } + + pairBuffer += state.dump; + + if (explicitPair) { + pairBuffer += generateNextLine(state, level); + } + + if (!writeNode(state, level + 1, objectValue, true, explicitPair)) { + continue; // Skip this pair because of invalid value. + } + + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += ':'; + } else { + pairBuffer += ': '; + } + + pairBuffer += state.dump; + + // Both key and value are valid. + _result += pairBuffer; + } + + state.tag = _tag; + state.dump = _result || '{}'; // Empty mapping if no valid pairs. +} + +function detectType(state, object, explicit) { + var _result, typeList, index, length, type, style; + + typeList = explicit ? state.explicitTypes : state.implicitTypes; + + for (index = 0, length = typeList.length; index < length; index += 1) { + type = typeList[index]; + + if ((type.instanceOf || type.predicate) && + (!type.instanceOf || ((typeof object === 'object') && (object instanceof type.instanceOf))) && + (!type.predicate || type.predicate(object))) { + + if (explicit) { + if (type.multi && type.representName) { + state.tag = type.representName(object); + } else { + state.tag = type.tag; + } + } else { + state.tag = '?'; + } + + if (type.represent) { + style = state.styleMap[type.tag] || type.defaultStyle; + + if (_toString.call(type.represent) === '[object Function]') { + _result = type.represent(object, style); + } else if (_hasOwnProperty.call(type.represent, style)) { + _result = type.represent[style](object, style); + } else { + throw new exception('!<' + type.tag + '> tag resolver accepts not "' + style + '" style'); + } + + state.dump = _result; + } + + return true; + } + } + + return false; +} + +// Serializes `object` and writes it to global `result`. +// Returns true on success, or false on invalid object. +// +function writeNode(state, level, object, block, compact, iskey, isblockseq) { + state.tag = null; + state.dump = object; + + if (!detectType(state, object, false)) { + detectType(state, object, true); + } + + var type = _toString.call(state.dump); + var inblock = block; + var tagStr; + + if (block) { + block = (state.flowLevel < 0 || state.flowLevel > level); + } + + var objectOrArray = type === '[object Object]' || type === '[object Array]', + duplicateIndex, + duplicate; + + if (objectOrArray) { + duplicateIndex = state.duplicates.indexOf(object); + duplicate = duplicateIndex !== -1; + } + + if ((state.tag !== null && state.tag !== '?') || duplicate || (state.indent !== 2 && level > 0)) { + compact = false; + } + + if (duplicate && state.usedDuplicates[duplicateIndex]) { + state.dump = '*ref_' + duplicateIndex; + } else { + if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) { + state.usedDuplicates[duplicateIndex] = true; + } + if (type === '[object Object]') { + if (block && (Object.keys(state.dump).length !== 0)) { + writeBlockMapping(state, level, state.dump, compact); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowMapping(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object Array]') { + if (block && (state.dump.length !== 0)) { + if (state.noArrayIndent && !isblockseq && level > 0) { + writeBlockSequence(state, level - 1, state.dump, compact); + } else { + writeBlockSequence(state, level, state.dump, compact); + } + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowSequence(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object String]') { + if (state.tag !== '?') { + writeScalar(state, state.dump, level, iskey, inblock); + } + } else if (type === '[object Undefined]') { + return false; + } else { + if (state.skipInvalid) return false; + throw new exception('unacceptable kind of an object to dump ' + type); + } + + if (state.tag !== null && state.tag !== '?') { + // Need to encode all characters except those allowed by the spec: + // + // [35] ns-dec-digit ::= [#x30-#x39] /* 0-9 */ + // [36] ns-hex-digit ::= ns-dec-digit + // | [#x41-#x46] /* A-F */ | [#x61-#x66] /* a-f */ + // [37] ns-ascii-letter ::= [#x41-#x5A] /* A-Z */ | [#x61-#x7A] /* a-z */ + // [38] ns-word-char ::= ns-dec-digit | ns-ascii-letter | “-” + // [39] ns-uri-char ::= “%” ns-hex-digit ns-hex-digit | ns-word-char | “#” + // | “;” | “/” | “?” | “:” | “@” | “&” | “=” | “+” | “$” | “,” + // | “_” | “.” | “!” | “~” | “*” | “'” | “(” | “)” | “[” | “]” + // + // Also need to encode '!' because it has special meaning (end of tag prefix). + // + tagStr = encodeURI( + state.tag[0] === '!' ? state.tag.slice(1) : state.tag + ).replace(/!/g, '%21'); + + if (state.tag[0] === '!') { + tagStr = '!' + tagStr; + } else if (tagStr.slice(0, 18) === 'tag:yaml.org,2002:') { + tagStr = '!!' + tagStr.slice(18); + } else { + tagStr = '!<' + tagStr + '>'; + } + + state.dump = tagStr + ' ' + state.dump; + } + } + + return true; +} + +function getDuplicateReferences(object, state) { + var objects = [], + duplicatesIndexes = [], + index, + length; + + inspectNode(object, objects, duplicatesIndexes); + + for (index = 0, length = duplicatesIndexes.length; index < length; index += 1) { + state.duplicates.push(objects[duplicatesIndexes[index]]); + } + state.usedDuplicates = new Array(length); +} + +function inspectNode(object, objects, duplicatesIndexes) { + var objectKeyList, + index, + length; + + if (object !== null && typeof object === 'object') { + index = objects.indexOf(object); + if (index !== -1) { + if (duplicatesIndexes.indexOf(index) === -1) { + duplicatesIndexes.push(index); + } + } else { + objects.push(object); + + if (Array.isArray(object)) { + for (index = 0, length = object.length; index < length; index += 1) { + inspectNode(object[index], objects, duplicatesIndexes); + } + } else { + objectKeyList = Object.keys(object); + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + inspectNode(object[objectKeyList[index]], objects, duplicatesIndexes); + } + } + } + } +} + +function dump$1(input, options) { + options = options || {}; + + var state = new State(options); + + if (!state.noRefs) getDuplicateReferences(input, state); + + var value = input; + + if (state.replacer) { + value = state.replacer.call({ '': value }, '', value); + } + + if (writeNode(state, 0, value, true, true)) return state.dump + '\n'; + + return ''; +} + +var dump_1 = dump$1; + +var dumper = { + dump: dump_1 +}; + +function renamed(from, to) { + return function () { + throw new Error('Function yaml.' + from + ' is removed in js-yaml 4. ' + + 'Use yaml.' + to + ' instead, which is now safe by default.'); + }; +} + + +var Type = type; +var Schema = schema; +var FAILSAFE_SCHEMA = failsafe; +var JSON_SCHEMA = json; +var CORE_SCHEMA = core; +var DEFAULT_SCHEMA = _default; +var load = loader.load; +var loadAll = loader.loadAll; +var dump = dumper.dump; +var YAMLException = exception; + +// Re-export all types in case user wants to create custom schema +var types = { + binary: binary, + float: float, + map: map, + null: _null, + pairs: pairs, + set: set, + timestamp: timestamp, + bool: bool, + int: int, + merge: merge, + omap: omap, + seq: seq, + str: str +}; + +// Removed functions from JS-YAML 3.0.x +var safeLoad = renamed('safeLoad', 'load'); +var safeLoadAll = renamed('safeLoadAll', 'loadAll'); +var safeDump = renamed('safeDump', 'dump'); + +var jsYaml = { + Type: Type, + Schema: Schema, + FAILSAFE_SCHEMA: FAILSAFE_SCHEMA, + JSON_SCHEMA: JSON_SCHEMA, + CORE_SCHEMA: CORE_SCHEMA, + DEFAULT_SCHEMA: DEFAULT_SCHEMA, + load: load, + loadAll: loadAll, + dump: dump, + YAMLException: YAMLException, + types: types, + safeLoad: safeLoad, + safeLoadAll: safeLoadAll, + safeDump: safeDump +}; + +export default jsYaml; +export { CORE_SCHEMA, DEFAULT_SCHEMA, FAILSAFE_SCHEMA, JSON_SCHEMA, Schema, Type, YAMLException, dump, load, loadAll, safeDump, safeLoad, safeLoadAll, types }; diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/index.js b/node_modules/wfilesencoders/node_modules/js-yaml/index.js new file mode 100644 index 00000000..bcb7eba7 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/index.js @@ -0,0 +1,47 @@ +'use strict'; + + +var loader = require('./lib/loader'); +var dumper = require('./lib/dumper'); + + +function renamed(from, to) { + return function () { + throw new Error('Function yaml.' + from + ' is removed in js-yaml 4. ' + + 'Use yaml.' + to + ' instead, which is now safe by default.'); + }; +} + + +module.exports.Type = require('./lib/type'); +module.exports.Schema = require('./lib/schema'); +module.exports.FAILSAFE_SCHEMA = require('./lib/schema/failsafe'); +module.exports.JSON_SCHEMA = require('./lib/schema/json'); +module.exports.CORE_SCHEMA = require('./lib/schema/core'); +module.exports.DEFAULT_SCHEMA = require('./lib/schema/default'); +module.exports.load = loader.load; +module.exports.loadAll = loader.loadAll; +module.exports.dump = dumper.dump; +module.exports.YAMLException = require('./lib/exception'); + +// Re-export all types in case user wants to create custom schema +module.exports.types = { + binary: require('./lib/type/binary'), + float: require('./lib/type/float'), + map: require('./lib/type/map'), + null: require('./lib/type/null'), + pairs: require('./lib/type/pairs'), + set: require('./lib/type/set'), + timestamp: require('./lib/type/timestamp'), + bool: require('./lib/type/bool'), + int: require('./lib/type/int'), + merge: require('./lib/type/merge'), + omap: require('./lib/type/omap'), + seq: require('./lib/type/seq'), + str: require('./lib/type/str') +}; + +// Removed functions from JS-YAML 3.0.x +module.exports.safeLoad = renamed('safeLoad', 'load'); +module.exports.safeLoadAll = renamed('safeLoadAll', 'loadAll'); +module.exports.safeDump = renamed('safeDump', 'dump'); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/common.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/common.js new file mode 100644 index 00000000..25ef7d8e --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/common.js @@ -0,0 +1,59 @@ +'use strict'; + + +function isNothing(subject) { + return (typeof subject === 'undefined') || (subject === null); +} + + +function isObject(subject) { + return (typeof subject === 'object') && (subject !== null); +} + + +function toArray(sequence) { + if (Array.isArray(sequence)) return sequence; + else if (isNothing(sequence)) return []; + + return [ sequence ]; +} + + +function extend(target, source) { + var index, length, key, sourceKeys; + + if (source) { + sourceKeys = Object.keys(source); + + for (index = 0, length = sourceKeys.length; index < length; index += 1) { + key = sourceKeys[index]; + target[key] = source[key]; + } + } + + return target; +} + + +function repeat(string, count) { + var result = '', cycle; + + for (cycle = 0; cycle < count; cycle += 1) { + result += string; + } + + return result; +} + + +function isNegativeZero(number) { + return (number === 0) && (Number.NEGATIVE_INFINITY === 1 / number); +} + + +module.exports.isNothing = isNothing; +module.exports.isObject = isObject; +module.exports.toArray = toArray; +module.exports.repeat = repeat; +module.exports.isNegativeZero = isNegativeZero; +module.exports.extend = extend; diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/dumper.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/dumper.js new file mode 100644 index 00000000..f357a6ae --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/dumper.js @@ -0,0 +1,965 @@ +'use strict'; + +/*eslint-disable no-use-before-define*/ + +var common = require('./common'); +var YAMLException = require('./exception'); +var DEFAULT_SCHEMA = require('./schema/default'); + +var _toString = Object.prototype.toString; +var _hasOwnProperty = Object.prototype.hasOwnProperty; + +var CHAR_BOM = 0xFEFF; +var CHAR_TAB = 0x09; /* Tab */ +var CHAR_LINE_FEED = 0x0A; /* LF */ +var CHAR_CARRIAGE_RETURN = 0x0D; /* CR */ +var CHAR_SPACE = 0x20; /* Space */ +var CHAR_EXCLAMATION = 0x21; /* ! */ +var CHAR_DOUBLE_QUOTE = 0x22; /* " */ +var CHAR_SHARP = 0x23; /* # */ +var CHAR_PERCENT = 0x25; /* % */ +var CHAR_AMPERSAND = 0x26; /* & */ +var CHAR_SINGLE_QUOTE = 0x27; /* ' */ +var CHAR_ASTERISK = 0x2A; /* * */ +var CHAR_COMMA = 0x2C; /* , */ +var CHAR_MINUS = 0x2D; /* - */ +var CHAR_COLON = 0x3A; /* : */ +var CHAR_EQUALS = 0x3D; /* = */ +var CHAR_GREATER_THAN = 0x3E; /* > */ +var CHAR_QUESTION = 0x3F; /* ? */ +var CHAR_COMMERCIAL_AT = 0x40; /* @ */ +var CHAR_LEFT_SQUARE_BRACKET = 0x5B; /* [ */ +var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */ +var CHAR_GRAVE_ACCENT = 0x60; /* ` */ +var CHAR_LEFT_CURLY_BRACKET = 0x7B; /* { */ +var CHAR_VERTICAL_LINE = 0x7C; /* | */ +var CHAR_RIGHT_CURLY_BRACKET = 0x7D; /* } */ + +var ESCAPE_SEQUENCES = {}; + +ESCAPE_SEQUENCES[0x00] = '\\0'; +ESCAPE_SEQUENCES[0x07] = '\\a'; +ESCAPE_SEQUENCES[0x08] = '\\b'; +ESCAPE_SEQUENCES[0x09] = '\\t'; +ESCAPE_SEQUENCES[0x0A] = '\\n'; +ESCAPE_SEQUENCES[0x0B] = '\\v'; +ESCAPE_SEQUENCES[0x0C] = '\\f'; +ESCAPE_SEQUENCES[0x0D] = '\\r'; +ESCAPE_SEQUENCES[0x1B] = '\\e'; +ESCAPE_SEQUENCES[0x22] = '\\"'; +ESCAPE_SEQUENCES[0x5C] = '\\\\'; +ESCAPE_SEQUENCES[0x85] = '\\N'; +ESCAPE_SEQUENCES[0xA0] = '\\_'; +ESCAPE_SEQUENCES[0x2028] = '\\L'; +ESCAPE_SEQUENCES[0x2029] = '\\P'; + +var DEPRECATED_BOOLEANS_SYNTAX = [ + 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON', + 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF' +]; + +var DEPRECATED_BASE60_SYNTAX = /^[-+]?[0-9_]+(?::[0-9_]+)+(?:\.[0-9_]*)?$/; + +function compileStyleMap(schema, map) { + var result, keys, index, length, tag, style, type; + + if (map === null) return {}; + + result = {}; + keys = Object.keys(map); + + for (index = 0, length = keys.length; index < length; index += 1) { + tag = keys[index]; + style = String(map[tag]); + + if (tag.slice(0, 2) === '!!') { + tag = 'tag:yaml.org,2002:' + tag.slice(2); + } + type = schema.compiledTypeMap['fallback'][tag]; + + if (type && _hasOwnProperty.call(type.styleAliases, style)) { + style = type.styleAliases[style]; + } + + result[tag] = style; + } + + return result; +} + +function encodeHex(character) { + var string, handle, length; + + string = character.toString(16).toUpperCase(); + + if (character <= 0xFF) { + handle = 'x'; + length = 2; + } else if (character <= 0xFFFF) { + handle = 'u'; + length = 4; + } else if (character <= 0xFFFFFFFF) { + handle = 'U'; + length = 8; + } else { + throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF'); + } + + return '\\' + handle + common.repeat('0', length - string.length) + string; +} + + +var QUOTING_TYPE_SINGLE = 1, + QUOTING_TYPE_DOUBLE = 2; + +function State(options) { + this.schema = options['schema'] || DEFAULT_SCHEMA; + this.indent = Math.max(1, (options['indent'] || 2)); + this.noArrayIndent = options['noArrayIndent'] || false; + this.skipInvalid = options['skipInvalid'] || false; + this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']); + this.styleMap = compileStyleMap(this.schema, options['styles'] || null); + this.sortKeys = options['sortKeys'] || false; + this.lineWidth = options['lineWidth'] || 80; + this.noRefs = options['noRefs'] || false; + this.noCompatMode = options['noCompatMode'] || false; + this.condenseFlow = options['condenseFlow'] || false; + this.quotingType = options['quotingType'] === '"' ? QUOTING_TYPE_DOUBLE : QUOTING_TYPE_SINGLE; + this.forceQuotes = options['forceQuotes'] || false; + this.replacer = typeof options['replacer'] === 'function' ? options['replacer'] : null; + + this.implicitTypes = this.schema.compiledImplicit; + this.explicitTypes = this.schema.compiledExplicit; + + this.tag = null; + this.result = ''; + + this.duplicates = []; + this.usedDuplicates = null; +} + +// Indents every line in a string. Empty lines (\n only) are not indented. +function indentString(string, spaces) { + var ind = common.repeat(' ', spaces), + position = 0, + next = -1, + result = '', + line, + length = string.length; + + while (position < length) { + next = string.indexOf('\n', position); + if (next === -1) { + line = string.slice(position); + position = length; + } else { + line = string.slice(position, next + 1); + position = next + 1; + } + + if (line.length && line !== '\n') result += ind; + + result += line; + } + + return result; +} + +function generateNextLine(state, level) { + return '\n' + common.repeat(' ', state.indent * level); +} + +function testImplicitResolving(state, str) { + var index, length, type; + + for (index = 0, length = state.implicitTypes.length; index < length; index += 1) { + type = state.implicitTypes[index]; + + if (type.resolve(str)) { + return true; + } + } + + return false; +} + +// [33] s-white ::= s-space | s-tab +function isWhitespace(c) { + return c === CHAR_SPACE || c === CHAR_TAB; +} + +// Returns true if the character can be printed without escaping. +// From YAML 1.2: "any allowed characters known to be non-printable +// should also be escaped. [However,] This isn’t mandatory" +// Derived from nb-char - \t - #x85 - #xA0 - #x2028 - #x2029. +function isPrintable(c) { + return (0x00020 <= c && c <= 0x00007E) + || ((0x000A1 <= c && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029) + || ((0x0E000 <= c && c <= 0x00FFFD) && c !== CHAR_BOM) + || (0x10000 <= c && c <= 0x10FFFF); +} + +// [34] ns-char ::= nb-char - s-white +// [27] nb-char ::= c-printable - b-char - c-byte-order-mark +// [26] b-char ::= b-line-feed | b-carriage-return +// Including s-white (for some reason, examples doesn't match specs in this aspect) +// ns-char ::= c-printable - b-line-feed - b-carriage-return - c-byte-order-mark +function isNsCharOrWhitespace(c) { + return isPrintable(c) + && c !== CHAR_BOM + // - b-char + && c !== CHAR_CARRIAGE_RETURN + && c !== CHAR_LINE_FEED; +} + +// [127] ns-plain-safe(c) ::= c = flow-out ⇒ ns-plain-safe-out +// c = flow-in ⇒ ns-plain-safe-in +// c = block-key ⇒ ns-plain-safe-out +// c = flow-key ⇒ ns-plain-safe-in +// [128] ns-plain-safe-out ::= ns-char +// [129] ns-plain-safe-in ::= ns-char - c-flow-indicator +// [130] ns-plain-char(c) ::= ( ns-plain-safe(c) - “:” - “#” ) +// | ( /* An ns-char preceding */ “#” ) +// | ( “:” /* Followed by an ns-plain-safe(c) */ ) +function isPlainSafe(c, prev, inblock) { + var cIsNsCharOrWhitespace = isNsCharOrWhitespace(c); + var cIsNsChar = cIsNsCharOrWhitespace && !isWhitespace(c); + return ( + // ns-plain-safe + inblock ? // c = flow-in + cIsNsCharOrWhitespace + : cIsNsCharOrWhitespace + // - c-flow-indicator + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + ) + // ns-plain-char + && c !== CHAR_SHARP // false on '#' + && !(prev === CHAR_COLON && !cIsNsChar) // false on ': ' + || (isNsCharOrWhitespace(prev) && !isWhitespace(prev) && c === CHAR_SHARP) // change to true on '[^ ]#' + || (prev === CHAR_COLON && cIsNsChar); // change to true on ':[^ ]' +} + +// Simplified test for values allowed as the first character in plain style. +function isPlainSafeFirst(c) { + // Uses a subset of ns-char - c-indicator + // where ns-char = nb-char - s-white. + // No support of ( ( “?” | “:” | “-” ) /* Followed by an ns-plain-safe(c)) */ ) part + return isPrintable(c) && c !== CHAR_BOM + && !isWhitespace(c) // - s-white + // - (c-indicator ::= + // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}” + && c !== CHAR_MINUS + && c !== CHAR_QUESTION + && c !== CHAR_COLON + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + // | “#” | “&” | “*” | “!” | “|” | “=” | “>” | “'” | “"” + && c !== CHAR_SHARP + && c !== CHAR_AMPERSAND + && c !== CHAR_ASTERISK + && c !== CHAR_EXCLAMATION + && c !== CHAR_VERTICAL_LINE + && c !== CHAR_EQUALS + && c !== CHAR_GREATER_THAN + && c !== CHAR_SINGLE_QUOTE + && c !== CHAR_DOUBLE_QUOTE + // | “%” | “@” | “`”) + && c !== CHAR_PERCENT + && c !== CHAR_COMMERCIAL_AT + && c !== CHAR_GRAVE_ACCENT; +} + +// Simplified test for values allowed as the last character in plain style. +function isPlainSafeLast(c) { + // just not whitespace or colon, it will be checked to be plain character later + return !isWhitespace(c) && c !== CHAR_COLON; +} + +// Same as 'string'.codePointAt(pos), but works in older browsers. +function codePointAt(string, pos) { + var first = string.charCodeAt(pos), second; + if (first >= 0xD800 && first <= 0xDBFF && pos + 1 < string.length) { + second = string.charCodeAt(pos + 1); + if (second >= 0xDC00 && second <= 0xDFFF) { + // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; + } + } + return first; +} + +// Determines whether block indentation indicator is required. +function needIndentIndicator(string) { + var leadingSpaceRe = /^\n* /; + return leadingSpaceRe.test(string); +} + +var STYLE_PLAIN = 1, + STYLE_SINGLE = 2, + STYLE_LITERAL = 3, + STYLE_FOLDED = 4, + STYLE_DOUBLE = 5; + +// Determines which scalar styles are possible and returns the preferred style. +// lineWidth = -1 => no limit. +// Pre-conditions: str.length > 0. +// Post-conditions: +// STYLE_PLAIN or STYLE_SINGLE => no \n are in the string. +// STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1). +// STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1). +function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, + testAmbiguousType, quotingType, forceQuotes, inblock) { + + var i; + var char = 0; + var prevChar = null; + var hasLineBreak = false; + var hasFoldableLine = false; // only checked if shouldTrackWidth + var shouldTrackWidth = lineWidth !== -1; + var previousLineBreak = -1; // count the first line correctly + var plain = isPlainSafeFirst(codePointAt(string, 0)) + && isPlainSafeLast(codePointAt(string, string.length - 1)); + + if (singleLineOnly || forceQuotes) { + // Case: no block styles. + // Check for disallowed characters to rule out plain and single. + for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char, prevChar, inblock); + prevChar = char; + } + } else { + // Case: block styles permitted. + for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + if (char === CHAR_LINE_FEED) { + hasLineBreak = true; + // Check if any line can be folded. + if (shouldTrackWidth) { + hasFoldableLine = hasFoldableLine || + // Foldable line = too long, and not more-indented. + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' '); + previousLineBreak = i; + } + } else if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char, prevChar, inblock); + prevChar = char; + } + // in case the end is missing a \n + hasFoldableLine = hasFoldableLine || (shouldTrackWidth && + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' ')); + } + // Although every style can represent \n without escaping, prefer block styles + // for multiline, since they're more readable and they don't add empty lines. + // Also prefer folding a super-long line. + if (!hasLineBreak && !hasFoldableLine) { + // Strings interpretable as another type have to be quoted; + // e.g. the string 'true' vs. the boolean true. + if (plain && !forceQuotes && !testAmbiguousType(string)) { + return STYLE_PLAIN; + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE; + } + // Edge case: block indentation indicator can only have one digit. + if (indentPerLevel > 9 && needIndentIndicator(string)) { + return STYLE_DOUBLE; + } + // At this point we know block styles are valid. + // Prefer literal style unless we want to fold. + if (!forceQuotes) { + return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL; + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE; +} + +// Note: line breaking/folding is implemented for only the folded style. +// NB. We drop the last trailing newline (if any) of a returned block scalar +// since the dumper adds its own newline. This always works: +// • No ending newline => unaffected; already using strip "-" chomping. +// • Ending newline => removed then restored. +// Importantly, this keeps the "+" chomp indicator from gaining an extra line. +function writeScalar(state, string, level, iskey, inblock) { + state.dump = (function () { + if (string.length === 0) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? '""' : "''"; + } + if (!state.noCompatMode) { + if (DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1 || DEPRECATED_BASE60_SYNTAX.test(string)) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? ('"' + string + '"') : ("'" + string + "'"); + } + } + + var indent = state.indent * Math.max(1, level); // no 0-indent scalars + // As indentation gets deeper, let the width decrease monotonically + // to the lower bound min(state.lineWidth, 40). + // Note that this implies + // state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound. + // state.lineWidth > 40 + state.indent: width decreases until the lower bound. + // This behaves better than a constant minimum width which disallows narrower options, + // or an indent threshold which causes the width to suddenly increase. + var lineWidth = state.lineWidth === -1 + ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent); + + // Without knowing if keys are implicit/explicit, assume implicit for safety. + var singleLineOnly = iskey + // No block styles in flow mode. + || (state.flowLevel > -1 && level >= state.flowLevel); + function testAmbiguity(string) { + return testImplicitResolving(state, string); + } + + switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, + testAmbiguity, state.quotingType, state.forceQuotes && !iskey, inblock)) { + + case STYLE_PLAIN: + return string; + case STYLE_SINGLE: + return "'" + string.replace(/'/g, "''") + "'"; + case STYLE_LITERAL: + return '|' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(string, indent)); + case STYLE_FOLDED: + return '>' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(foldString(string, lineWidth), indent)); + case STYLE_DOUBLE: + return '"' + escapeString(string, lineWidth) + '"'; + default: + throw new YAMLException('impossible error: invalid scalar style'); + } + }()); +} + +// Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9. +function blockHeader(string, indentPerLevel) { + var indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : ''; + + // note the special case: the string '\n' counts as a "trailing" empty line. + var clip = string[string.length - 1] === '\n'; + var keep = clip && (string[string.length - 2] === '\n' || string === '\n'); + var chomp = keep ? '+' : (clip ? '' : '-'); + + return indentIndicator + chomp + '\n'; +} + +// (See the note for writeScalar.) +function dropEndingNewline(string) { + return string[string.length - 1] === '\n' ? string.slice(0, -1) : string; +} + +// Note: a long line without a suitable break point will exceed the width limit. +// Pre-conditions: every char in str isPrintable, str.length > 0, width > 0. +function foldString(string, width) { + // In folded style, $k$ consecutive newlines output as $k+1$ newlines— + // unless they're before or after a more-indented line, or at the very + // beginning or end, in which case $k$ maps to $k$. + // Therefore, parse each chunk as newline(s) followed by a content line. + var lineRe = /(\n+)([^\n]*)/g; + + // first line (possibly an empty line) + var result = (function () { + var nextLF = string.indexOf('\n'); + nextLF = nextLF !== -1 ? nextLF : string.length; + lineRe.lastIndex = nextLF; + return foldLine(string.slice(0, nextLF), width); + }()); + // If we haven't reached the first content line yet, don't add an extra \n. + var prevMoreIndented = string[0] === '\n' || string[0] === ' '; + var moreIndented; + + // rest of the lines + var match; + while ((match = lineRe.exec(string))) { + var prefix = match[1], line = match[2]; + moreIndented = (line[0] === ' '); + result += prefix + + (!prevMoreIndented && !moreIndented && line !== '' + ? '\n' : '') + + foldLine(line, width); + prevMoreIndented = moreIndented; + } + + return result; +} + +// Greedy line breaking. +// Picks the longest line under the limit each time, +// otherwise settles for the shortest line over the limit. +// NB. More-indented lines *cannot* be folded, as that would add an extra \n. +function foldLine(line, width) { + if (line === '' || line[0] === ' ') return line; + + // Since a more-indented line adds a \n, breaks can't be followed by a space. + var breakRe = / [^ ]/g; // note: the match index will always be <= length-2. + var match; + // start is an inclusive index. end, curr, and next are exclusive. + var start = 0, end, curr = 0, next = 0; + var result = ''; + + // Invariants: 0 <= start <= length-1. + // 0 <= curr <= next <= max(0, length-2). curr - start <= width. + // Inside the loop: + // A match implies length >= 2, so curr and next are <= length-2. + while ((match = breakRe.exec(line))) { + next = match.index; + // maintain invariant: curr - start <= width + if (next - start > width) { + end = (curr > start) ? curr : next; // derive end <= length-2 + result += '\n' + line.slice(start, end); + // skip the space that was output as \n + start = end + 1; // derive start <= length-1 + } + curr = next; + } + + // By the invariants, start <= length-1, so there is something left over. + // It is either the whole string or a part starting from non-whitespace. + result += '\n'; + // Insert a break if the remainder is too long and there is a break available. + if (line.length - start > width && curr > start) { + result += line.slice(start, curr) + '\n' + line.slice(curr + 1); + } else { + result += line.slice(start); + } + + return result.slice(1); // drop extra \n joiner +} + +// Escapes a double-quoted string. +function escapeString(string) { + var result = ''; + var char = 0; + var escapeSeq; + + for (var i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + escapeSeq = ESCAPE_SEQUENCES[char]; + + if (!escapeSeq && isPrintable(char)) { + result += string[i]; + if (char >= 0x10000) result += string[i + 1]; + } else { + result += escapeSeq || encodeHex(char); + } + } + + return result; +} + +function writeFlowSequence(state, level, object) { + var _result = '', + _tag = state.tag, + index, + length, + value; + + for (index = 0, length = object.length; index < length; index += 1) { + value = object[index]; + + if (state.replacer) { + value = state.replacer.call(object, String(index), value); + } + + // Write only valid elements, put null instead of invalid elements. + if (writeNode(state, level, value, false, false) || + (typeof value === 'undefined' && + writeNode(state, level, null, false, false))) { + + if (_result !== '') _result += ',' + (!state.condenseFlow ? ' ' : ''); + _result += state.dump; + } + } + + state.tag = _tag; + state.dump = '[' + _result + ']'; +} + +function writeBlockSequence(state, level, object, compact) { + var _result = '', + _tag = state.tag, + index, + length, + value; + + for (index = 0, length = object.length; index < length; index += 1) { + value = object[index]; + + if (state.replacer) { + value = state.replacer.call(object, String(index), value); + } + + // Write only valid elements, put null instead of invalid elements. + if (writeNode(state, level + 1, value, true, true, false, true) || + (typeof value === 'undefined' && + writeNode(state, level + 1, null, true, true, false, true))) { + + if (!compact || _result !== '') { + _result += generateNextLine(state, level); + } + + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + _result += '-'; + } else { + _result += '- '; + } + + _result += state.dump; + } + } + + state.tag = _tag; + state.dump = _result || '[]'; // Empty sequence if no valid values. +} + +function writeFlowMapping(state, level, object) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + pairBuffer; + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + + pairBuffer = ''; + if (_result !== '') pairBuffer += ', '; + + if (state.condenseFlow) pairBuffer += '"'; + + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue); + } + + if (!writeNode(state, level, objectKey, false, false)) { + continue; // Skip this pair because of invalid key; + } + + if (state.dump.length > 1024) pairBuffer += '? '; + + pairBuffer += state.dump + (state.condenseFlow ? '"' : '') + ':' + (state.condenseFlow ? '' : ' '); + + if (!writeNode(state, level, objectValue, false, false)) { + continue; // Skip this pair because of invalid value. + } + + pairBuffer += state.dump; + + // Both key and value are valid. + _result += pairBuffer; + } + + state.tag = _tag; + state.dump = '{' + _result + '}'; +} + +function writeBlockMapping(state, level, object, compact) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + explicitPair, + pairBuffer; + + // Allow sorting keys so that the output file is deterministic + if (state.sortKeys === true) { + // Default sorting + objectKeyList.sort(); + } else if (typeof state.sortKeys === 'function') { + // Custom sort function + objectKeyList.sort(state.sortKeys); + } else if (state.sortKeys) { + // Something is wrong + throw new YAMLException('sortKeys must be a boolean or a function'); + } + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + pairBuffer = ''; + + if (!compact || _result !== '') { + pairBuffer += generateNextLine(state, level); + } + + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue); + } + + if (!writeNode(state, level + 1, objectKey, true, true, true)) { + continue; // Skip this pair because of invalid key. + } + + explicitPair = (state.tag !== null && state.tag !== '?') || + (state.dump && state.dump.length > 1024); + + if (explicitPair) { + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += '?'; + } else { + pairBuffer += '? '; + } + } + + pairBuffer += state.dump; + + if (explicitPair) { + pairBuffer += generateNextLine(state, level); + } + + if (!writeNode(state, level + 1, objectValue, true, explicitPair)) { + continue; // Skip this pair because of invalid value. + } + + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += ':'; + } else { + pairBuffer += ': '; + } + + pairBuffer += state.dump; + + // Both key and value are valid. + _result += pairBuffer; + } + + state.tag = _tag; + state.dump = _result || '{}'; // Empty mapping if no valid pairs. +} + +function detectType(state, object, explicit) { + var _result, typeList, index, length, type, style; + + typeList = explicit ? state.explicitTypes : state.implicitTypes; + + for (index = 0, length = typeList.length; index < length; index += 1) { + type = typeList[index]; + + if ((type.instanceOf || type.predicate) && + (!type.instanceOf || ((typeof object === 'object') && (object instanceof type.instanceOf))) && + (!type.predicate || type.predicate(object))) { + + if (explicit) { + if (type.multi && type.representName) { + state.tag = type.representName(object); + } else { + state.tag = type.tag; + } + } else { + state.tag = '?'; + } + + if (type.represent) { + style = state.styleMap[type.tag] || type.defaultStyle; + + if (_toString.call(type.represent) === '[object Function]') { + _result = type.represent(object, style); + } else if (_hasOwnProperty.call(type.represent, style)) { + _result = type.represent[style](object, style); + } else { + throw new YAMLException('!<' + type.tag + '> tag resolver accepts not "' + style + '" style'); + } + + state.dump = _result; + } + + return true; + } + } + + return false; +} + +// Serializes `object` and writes it to global `result`. +// Returns true on success, or false on invalid object. +// +function writeNode(state, level, object, block, compact, iskey, isblockseq) { + state.tag = null; + state.dump = object; + + if (!detectType(state, object, false)) { + detectType(state, object, true); + } + + var type = _toString.call(state.dump); + var inblock = block; + var tagStr; + + if (block) { + block = (state.flowLevel < 0 || state.flowLevel > level); + } + + var objectOrArray = type === '[object Object]' || type === '[object Array]', + duplicateIndex, + duplicate; + + if (objectOrArray) { + duplicateIndex = state.duplicates.indexOf(object); + duplicate = duplicateIndex !== -1; + } + + if ((state.tag !== null && state.tag !== '?') || duplicate || (state.indent !== 2 && level > 0)) { + compact = false; + } + + if (duplicate && state.usedDuplicates[duplicateIndex]) { + state.dump = '*ref_' + duplicateIndex; + } else { + if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) { + state.usedDuplicates[duplicateIndex] = true; + } + if (type === '[object Object]') { + if (block && (Object.keys(state.dump).length !== 0)) { + writeBlockMapping(state, level, state.dump, compact); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowMapping(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object Array]') { + if (block && (state.dump.length !== 0)) { + if (state.noArrayIndent && !isblockseq && level > 0) { + writeBlockSequence(state, level - 1, state.dump, compact); + } else { + writeBlockSequence(state, level, state.dump, compact); + } + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowSequence(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object String]') { + if (state.tag !== '?') { + writeScalar(state, state.dump, level, iskey, inblock); + } + } else if (type === '[object Undefined]') { + return false; + } else { + if (state.skipInvalid) return false; + throw new YAMLException('unacceptable kind of an object to dump ' + type); + } + + if (state.tag !== null && state.tag !== '?') { + // Need to encode all characters except those allowed by the spec: + // + // [35] ns-dec-digit ::= [#x30-#x39] /* 0-9 */ + // [36] ns-hex-digit ::= ns-dec-digit + // | [#x41-#x46] /* A-F */ | [#x61-#x66] /* a-f */ + // [37] ns-ascii-letter ::= [#x41-#x5A] /* A-Z */ | [#x61-#x7A] /* a-z */ + // [38] ns-word-char ::= ns-dec-digit | ns-ascii-letter | “-” + // [39] ns-uri-char ::= “%” ns-hex-digit ns-hex-digit | ns-word-char | “#” + // | “;” | “/” | “?” | “:” | “@” | “&” | “=” | “+” | “$” | “,” + // | “_” | “.” | “!” | “~” | “*” | “'” | “(” | “)” | “[” | “]” + // + // Also need to encode '!' because it has special meaning (end of tag prefix). + // + tagStr = encodeURI( + state.tag[0] === '!' ? state.tag.slice(1) : state.tag + ).replace(/!/g, '%21'); + + if (state.tag[0] === '!') { + tagStr = '!' + tagStr; + } else if (tagStr.slice(0, 18) === 'tag:yaml.org,2002:') { + tagStr = '!!' + tagStr.slice(18); + } else { + tagStr = '!<' + tagStr + '>'; + } + + state.dump = tagStr + ' ' + state.dump; + } + } + + return true; +} + +function getDuplicateReferences(object, state) { + var objects = [], + duplicatesIndexes = [], + index, + length; + + inspectNode(object, objects, duplicatesIndexes); + + for (index = 0, length = duplicatesIndexes.length; index < length; index += 1) { + state.duplicates.push(objects[duplicatesIndexes[index]]); + } + state.usedDuplicates = new Array(length); +} + +function inspectNode(object, objects, duplicatesIndexes) { + var objectKeyList, + index, + length; + + if (object !== null && typeof object === 'object') { + index = objects.indexOf(object); + if (index !== -1) { + if (duplicatesIndexes.indexOf(index) === -1) { + duplicatesIndexes.push(index); + } + } else { + objects.push(object); + + if (Array.isArray(object)) { + for (index = 0, length = object.length; index < length; index += 1) { + inspectNode(object[index], objects, duplicatesIndexes); + } + } else { + objectKeyList = Object.keys(object); + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + inspectNode(object[objectKeyList[index]], objects, duplicatesIndexes); + } + } + } + } +} + +function dump(input, options) { + options = options || {}; + + var state = new State(options); + + if (!state.noRefs) getDuplicateReferences(input, state); + + var value = input; + + if (state.replacer) { + value = state.replacer.call({ '': value }, '', value); + } + + if (writeNode(state, 0, value, true, true)) return state.dump + '\n'; + + return ''; +} + +module.exports.dump = dump; diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/exception.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/exception.js new file mode 100644 index 00000000..7f62daae --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/exception.js @@ -0,0 +1,55 @@ +// YAML error class. http://stackoverflow.com/questions/8458984 +// +'use strict'; + + +function formatError(exception, compact) { + var where = '', message = exception.reason || '(unknown reason)'; + + if (!exception.mark) return message; + + if (exception.mark.name) { + where += 'in "' + exception.mark.name + '" '; + } + + where += '(' + (exception.mark.line + 1) + ':' + (exception.mark.column + 1) + ')'; + + if (!compact && exception.mark.snippet) { + where += '\n\n' + exception.mark.snippet; + } + + return message + ' ' + where; +} + + +function YAMLException(reason, mark) { + // Super constructor + Error.call(this); + + this.name = 'YAMLException'; + this.reason = reason; + this.mark = mark; + this.message = formatError(this, false); + + // Include stack trace in error object + if (Error.captureStackTrace) { + // Chrome and NodeJS + Error.captureStackTrace(this, this.constructor); + } else { + // FF, IE 10+ and Safari 6+. Fallback for others + this.stack = (new Error()).stack || ''; + } +} + + +// Inherit from Error +YAMLException.prototype = Object.create(Error.prototype); +YAMLException.prototype.constructor = YAMLException; + + +YAMLException.prototype.toString = function toString(compact) { + return this.name + ': ' + formatError(this, compact); +}; + + +module.exports = YAMLException; diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/loader.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/loader.js new file mode 100644 index 00000000..39f13f56 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/loader.js @@ -0,0 +1,1727 @@ +'use strict'; + +/*eslint-disable max-len,no-use-before-define*/ + +var common = require('./common'); +var YAMLException = require('./exception'); +var makeSnippet = require('./snippet'); +var DEFAULT_SCHEMA = require('./schema/default'); + + +var _hasOwnProperty = Object.prototype.hasOwnProperty; + + +var CONTEXT_FLOW_IN = 1; +var CONTEXT_FLOW_OUT = 2; +var CONTEXT_BLOCK_IN = 3; +var CONTEXT_BLOCK_OUT = 4; + + +var CHOMPING_CLIP = 1; +var CHOMPING_STRIP = 2; +var CHOMPING_KEEP = 3; + + +var PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; +var PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/; +var PATTERN_FLOW_INDICATORS = /[,\[\]\{\}]/; +var PATTERN_TAG_HANDLE = /^(?:!|!!|![a-z\-]+!)$/i; +var PATTERN_TAG_URI = /^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i; + + +function _class(obj) { return Object.prototype.toString.call(obj); } + +function is_EOL(c) { + return (c === 0x0A/* LF */) || (c === 0x0D/* CR */); +} + +function is_WHITE_SPACE(c) { + return (c === 0x09/* Tab */) || (c === 0x20/* Space */); +} + +function is_WS_OR_EOL(c) { + return (c === 0x09/* Tab */) || + (c === 0x20/* Space */) || + (c === 0x0A/* LF */) || + (c === 0x0D/* CR */); +} + +function is_FLOW_INDICATOR(c) { + return c === 0x2C/* , */ || + c === 0x5B/* [ */ || + c === 0x5D/* ] */ || + c === 0x7B/* { */ || + c === 0x7D/* } */; +} + +function fromHexCode(c) { + var lc; + + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } + + /*eslint-disable no-bitwise*/ + lc = c | 0x20; + + if ((0x61/* a */ <= lc) && (lc <= 0x66/* f */)) { + return lc - 0x61 + 10; + } + + return -1; +} + +function escapedHexLen(c) { + if (c === 0x78/* x */) { return 2; } + if (c === 0x75/* u */) { return 4; } + if (c === 0x55/* U */) { return 8; } + return 0; +} + +function fromDecimalCode(c) { + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } + + return -1; +} + +function simpleEscapeSequence(c) { + /* eslint-disable indent */ + return (c === 0x30/* 0 */) ? '\x00' : + (c === 0x61/* a */) ? '\x07' : + (c === 0x62/* b */) ? '\x08' : + (c === 0x74/* t */) ? '\x09' : + (c === 0x09/* Tab */) ? '\x09' : + (c === 0x6E/* n */) ? '\x0A' : + (c === 0x76/* v */) ? '\x0B' : + (c === 0x66/* f */) ? '\x0C' : + (c === 0x72/* r */) ? '\x0D' : + (c === 0x65/* e */) ? '\x1B' : + (c === 0x20/* Space */) ? ' ' : + (c === 0x22/* " */) ? '\x22' : + (c === 0x2F/* / */) ? '/' : + (c === 0x5C/* \ */) ? '\x5C' : + (c === 0x4E/* N */) ? '\x85' : + (c === 0x5F/* _ */) ? '\xA0' : + (c === 0x4C/* L */) ? '\u2028' : + (c === 0x50/* P */) ? '\u2029' : ''; +} + +function charFromCodepoint(c) { + if (c <= 0xFFFF) { + return String.fromCharCode(c); + } + // Encode UTF-16 surrogate pair + // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF + return String.fromCharCode( + ((c - 0x010000) >> 10) + 0xD800, + ((c - 0x010000) & 0x03FF) + 0xDC00 + ); +} + +var simpleEscapeCheck = new Array(256); // integer, for fast access +var simpleEscapeMap = new Array(256); +for (var i = 0; i < 256; i++) { + simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0; + simpleEscapeMap[i] = simpleEscapeSequence(i); +} + + +function State(input, options) { + this.input = input; + + this.filename = options['filename'] || null; + this.schema = options['schema'] || DEFAULT_SCHEMA; + this.onWarning = options['onWarning'] || null; + // (Hidden) Remove? makes the loader to expect YAML 1.1 documents + // if such documents have no explicit %YAML directive + this.legacy = options['legacy'] || false; + + this.json = options['json'] || false; + this.listener = options['listener'] || null; + + this.implicitTypes = this.schema.compiledImplicit; + this.typeMap = this.schema.compiledTypeMap; + + this.length = input.length; + this.position = 0; + this.line = 0; + this.lineStart = 0; + this.lineIndent = 0; + + // position of first leading tab in the current line, + // used to make sure there are no tabs in the indentation + this.firstTabInLine = -1; + + this.documents = []; + + /* + this.version; + this.checkLineBreaks; + this.tagMap; + this.anchorMap; + this.tag; + this.anchor; + this.kind; + this.result;*/ + +} + + +function generateError(state, message) { + var mark = { + name: state.filename, + buffer: state.input.slice(0, -1), // omit trailing \0 + position: state.position, + line: state.line, + column: state.position - state.lineStart + }; + + mark.snippet = makeSnippet(mark); + + return new YAMLException(message, mark); +} + +function throwError(state, message) { + throw generateError(state, message); +} + +function throwWarning(state, message) { + if (state.onWarning) { + state.onWarning.call(null, generateError(state, message)); + } +} + + +var directiveHandlers = { + + YAML: function handleYamlDirective(state, name, args) { + + var match, major, minor; + + if (state.version !== null) { + throwError(state, 'duplication of %YAML directive'); + } + + if (args.length !== 1) { + throwError(state, 'YAML directive accepts exactly one argument'); + } + + match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]); + + if (match === null) { + throwError(state, 'ill-formed argument of the YAML directive'); + } + + major = parseInt(match[1], 10); + minor = parseInt(match[2], 10); + + if (major !== 1) { + throwError(state, 'unacceptable YAML version of the document'); + } + + state.version = args[0]; + state.checkLineBreaks = (minor < 2); + + if (minor !== 1 && minor !== 2) { + throwWarning(state, 'unsupported YAML version of the document'); + } + }, + + TAG: function handleTagDirective(state, name, args) { + + var handle, prefix; + + if (args.length !== 2) { + throwError(state, 'TAG directive accepts exactly two arguments'); + } + + handle = args[0]; + prefix = args[1]; + + if (!PATTERN_TAG_HANDLE.test(handle)) { + throwError(state, 'ill-formed tag handle (first argument) of the TAG directive'); + } + + if (_hasOwnProperty.call(state.tagMap, handle)) { + throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle'); + } + + if (!PATTERN_TAG_URI.test(prefix)) { + throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive'); + } + + try { + prefix = decodeURIComponent(prefix); + } catch (err) { + throwError(state, 'tag prefix is malformed: ' + prefix); + } + + state.tagMap[handle] = prefix; + } +}; + + +function captureSegment(state, start, end, checkJson) { + var _position, _length, _character, _result; + + if (start < end) { + _result = state.input.slice(start, end); + + if (checkJson) { + for (_position = 0, _length = _result.length; _position < _length; _position += 1) { + _character = _result.charCodeAt(_position); + if (!(_character === 0x09 || + (0x20 <= _character && _character <= 0x10FFFF))) { + throwError(state, 'expected valid JSON character'); + } + } + } else if (PATTERN_NON_PRINTABLE.test(_result)) { + throwError(state, 'the stream contains non-printable characters'); + } + + state.result += _result; + } +} + +function mergeMappings(state, destination, source, overridableKeys) { + var sourceKeys, key, index, quantity; + + if (!common.isObject(source)) { + throwError(state, 'cannot merge mappings; the provided source object is unacceptable'); + } + + sourceKeys = Object.keys(source); + + for (index = 0, quantity = sourceKeys.length; index < quantity; index += 1) { + key = sourceKeys[index]; + + if (!_hasOwnProperty.call(destination, key)) { + destination[key] = source[key]; + overridableKeys[key] = true; + } + } +} + +function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, + startLine, startLineStart, startPos) { + + var index, quantity; + + // The output is a plain object here, so keys can only be strings. + // We need to convert keyNode to a string, but doing so can hang the process + // (deeply nested arrays that explode exponentially using aliases). + if (Array.isArray(keyNode)) { + keyNode = Array.prototype.slice.call(keyNode); + + for (index = 0, quantity = keyNode.length; index < quantity; index += 1) { + if (Array.isArray(keyNode[index])) { + throwError(state, 'nested arrays are not supported inside keys'); + } + + if (typeof keyNode === 'object' && _class(keyNode[index]) === '[object Object]') { + keyNode[index] = '[object Object]'; + } + } + } + + // Avoid code execution in load() via toString property + // (still use its own toString for arrays, timestamps, + // and whatever user schema extensions happen to have @@toStringTag) + if (typeof keyNode === 'object' && _class(keyNode) === '[object Object]') { + keyNode = '[object Object]'; + } + + + keyNode = String(keyNode); + + if (_result === null) { + _result = {}; + } + + if (keyTag === 'tag:yaml.org,2002:merge') { + if (Array.isArray(valueNode)) { + for (index = 0, quantity = valueNode.length; index < quantity; index += 1) { + mergeMappings(state, _result, valueNode[index], overridableKeys); + } + } else { + mergeMappings(state, _result, valueNode, overridableKeys); + } + } else { + if (!state.json && + !_hasOwnProperty.call(overridableKeys, keyNode) && + _hasOwnProperty.call(_result, keyNode)) { + state.line = startLine || state.line; + state.lineStart = startLineStart || state.lineStart; + state.position = startPos || state.position; + throwError(state, 'duplicated mapping key'); + } + + // used for this specific key only because Object.defineProperty is slow + if (keyNode === '__proto__') { + Object.defineProperty(_result, keyNode, { + configurable: true, + enumerable: true, + writable: true, + value: valueNode + }); + } else { + _result[keyNode] = valueNode; + } + delete overridableKeys[keyNode]; + } + + return _result; +} + +function readLineBreak(state) { + var ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x0A/* LF */) { + state.position++; + } else if (ch === 0x0D/* CR */) { + state.position++; + if (state.input.charCodeAt(state.position) === 0x0A/* LF */) { + state.position++; + } + } else { + throwError(state, 'a line break is expected'); + } + + state.line += 1; + state.lineStart = state.position; + state.firstTabInLine = -1; +} + +function skipSeparationSpace(state, allowComments, checkIndent) { + var lineBreaks = 0, + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + if (ch === 0x09/* Tab */ && state.firstTabInLine === -1) { + state.firstTabInLine = state.position; + } + ch = state.input.charCodeAt(++state.position); + } + + if (allowComments && ch === 0x23/* # */) { + do { + ch = state.input.charCodeAt(++state.position); + } while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && ch !== 0); + } + + if (is_EOL(ch)) { + readLineBreak(state); + + ch = state.input.charCodeAt(state.position); + lineBreaks++; + state.lineIndent = 0; + + while (ch === 0x20/* Space */) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + } else { + break; + } + } + + if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) { + throwWarning(state, 'deficient indentation'); + } + + return lineBreaks; +} + +function testDocumentSeparator(state) { + var _position = state.position, + ch; + + ch = state.input.charCodeAt(_position); + + // Condition state.position === state.lineStart is tested + // in parent on each call, for efficiency. No needs to test here again. + if ((ch === 0x2D/* - */ || ch === 0x2E/* . */) && + ch === state.input.charCodeAt(_position + 1) && + ch === state.input.charCodeAt(_position + 2)) { + + _position += 3; + + ch = state.input.charCodeAt(_position); + + if (ch === 0 || is_WS_OR_EOL(ch)) { + return true; + } + } + + return false; +} + +function writeFoldedLines(state, count) { + if (count === 1) { + state.result += ' '; + } else if (count > 1) { + state.result += common.repeat('\n', count - 1); + } +} + + +function readPlainScalar(state, nodeIndent, withinFlowCollection) { + var preceding, + following, + captureStart, + captureEnd, + hasPendingContent, + _line, + _lineStart, + _lineIndent, + _kind = state.kind, + _result = state.result, + ch; + + ch = state.input.charCodeAt(state.position); + + if (is_WS_OR_EOL(ch) || + is_FLOW_INDICATOR(ch) || + ch === 0x23/* # */ || + ch === 0x26/* & */ || + ch === 0x2A/* * */ || + ch === 0x21/* ! */ || + ch === 0x7C/* | */ || + ch === 0x3E/* > */ || + ch === 0x27/* ' */ || + ch === 0x22/* " */ || + ch === 0x25/* % */ || + ch === 0x40/* @ */ || + ch === 0x60/* ` */) { + return false; + } + + if (ch === 0x3F/* ? */ || ch === 0x2D/* - */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + return false; + } + } + + state.kind = 'scalar'; + state.result = ''; + captureStart = captureEnd = state.position; + hasPendingContent = false; + + while (ch !== 0) { + if (ch === 0x3A/* : */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + break; + } + + } else if (ch === 0x23/* # */) { + preceding = state.input.charCodeAt(state.position - 1); + + if (is_WS_OR_EOL(preceding)) { + break; + } + + } else if ((state.position === state.lineStart && testDocumentSeparator(state)) || + withinFlowCollection && is_FLOW_INDICATOR(ch)) { + break; + + } else if (is_EOL(ch)) { + _line = state.line; + _lineStart = state.lineStart; + _lineIndent = state.lineIndent; + skipSeparationSpace(state, false, -1); + + if (state.lineIndent >= nodeIndent) { + hasPendingContent = true; + ch = state.input.charCodeAt(state.position); + continue; + } else { + state.position = captureEnd; + state.line = _line; + state.lineStart = _lineStart; + state.lineIndent = _lineIndent; + break; + } + } + + if (hasPendingContent) { + captureSegment(state, captureStart, captureEnd, false); + writeFoldedLines(state, state.line - _line); + captureStart = captureEnd = state.position; + hasPendingContent = false; + } + + if (!is_WHITE_SPACE(ch)) { + captureEnd = state.position + 1; + } + + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, captureEnd, false); + + if (state.result) { + return true; + } + + state.kind = _kind; + state.result = _result; + return false; +} + +function readSingleQuotedScalar(state, nodeIndent) { + var ch, + captureStart, captureEnd; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x27/* ' */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x27/* ' */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x27/* ' */) { + captureStart = state.position; + state.position++; + captureEnd = state.position; + } else { + return true; + } + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a single quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a single quoted scalar'); +} + +function readDoubleQuotedScalar(state, nodeIndent) { + var captureStart, + captureEnd, + hexLength, + hexResult, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x22/* " */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x22/* " */) { + captureSegment(state, captureStart, state.position, true); + state.position++; + return true; + + } else if (ch === 0x5C/* \ */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (is_EOL(ch)) { + skipSeparationSpace(state, false, nodeIndent); + + // TODO: rework to inline fn with no type cast? + } else if (ch < 256 && simpleEscapeCheck[ch]) { + state.result += simpleEscapeMap[ch]; + state.position++; + + } else if ((tmp = escapedHexLen(ch)) > 0) { + hexLength = tmp; + hexResult = 0; + + for (; hexLength > 0; hexLength--) { + ch = state.input.charCodeAt(++state.position); + + if ((tmp = fromHexCode(ch)) >= 0) { + hexResult = (hexResult << 4) + tmp; + + } else { + throwError(state, 'expected hexadecimal character'); + } + } + + state.result += charFromCodepoint(hexResult); + + state.position++; + + } else { + throwError(state, 'unknown escape sequence'); + } + + captureStart = captureEnd = state.position; + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a double quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a double quoted scalar'); +} + +function readFlowCollection(state, nodeIndent) { + var readNext = true, + _line, + _lineStart, + _pos, + _tag = state.tag, + _result, + _anchor = state.anchor, + following, + terminator, + isPair, + isExplicitPair, + isMapping, + overridableKeys = Object.create(null), + keyNode, + keyTag, + valueNode, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x5B/* [ */) { + terminator = 0x5D;/* ] */ + isMapping = false; + _result = []; + } else if (ch === 0x7B/* { */) { + terminator = 0x7D;/* } */ + isMapping = true; + _result = {}; + } else { + return false; + } + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(++state.position); + + while (ch !== 0) { + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === terminator) { + state.position++; + state.tag = _tag; + state.anchor = _anchor; + state.kind = isMapping ? 'mapping' : 'sequence'; + state.result = _result; + return true; + } else if (!readNext) { + throwError(state, 'missed comma between flow collection entries'); + } else if (ch === 0x2C/* , */) { + // "flow collection entries can never be completely empty", as per YAML 1.2, section 7.4 + throwError(state, "expected the node content, but found ','"); + } + + keyTag = keyNode = valueNode = null; + isPair = isExplicitPair = false; + + if (ch === 0x3F/* ? */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following)) { + isPair = isExplicitPair = true; + state.position++; + skipSeparationSpace(state, true, nodeIndent); + } + } + + _line = state.line; // Save the current line. + _lineStart = state.lineStart; + _pos = state.position; + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + keyTag = state.tag; + keyNode = state.result; + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if ((isExplicitPair || state.line === _line) && ch === 0x3A/* : */) { + isPair = true; + ch = state.input.charCodeAt(++state.position); + skipSeparationSpace(state, true, nodeIndent); + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + valueNode = state.result; + } + + if (isMapping) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos); + } else if (isPair) { + _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos)); + } else { + _result.push(keyNode); + } + + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x2C/* , */) { + readNext = true; + ch = state.input.charCodeAt(++state.position); + } else { + readNext = false; + } + } + + throwError(state, 'unexpected end of the stream within a flow collection'); +} + +function readBlockScalar(state, nodeIndent) { + var captureStart, + folding, + chomping = CHOMPING_CLIP, + didReadContent = false, + detectedIndent = false, + textIndent = nodeIndent, + emptyLines = 0, + atMoreIndented = false, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x7C/* | */) { + folding = false; + } else if (ch === 0x3E/* > */) { + folding = true; + } else { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + + while (ch !== 0) { + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { + if (CHOMPING_CLIP === chomping) { + chomping = (ch === 0x2B/* + */) ? CHOMPING_KEEP : CHOMPING_STRIP; + } else { + throwError(state, 'repeat of a chomping mode identifier'); + } + + } else if ((tmp = fromDecimalCode(ch)) >= 0) { + if (tmp === 0) { + throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one'); + } else if (!detectedIndent) { + textIndent = nodeIndent + tmp - 1; + detectedIndent = true; + } else { + throwError(state, 'repeat of an indentation width identifier'); + } + + } else { + break; + } + } + + if (is_WHITE_SPACE(ch)) { + do { ch = state.input.charCodeAt(++state.position); } + while (is_WHITE_SPACE(ch)); + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (!is_EOL(ch) && (ch !== 0)); + } + } + + while (ch !== 0) { + readLineBreak(state); + state.lineIndent = 0; + + ch = state.input.charCodeAt(state.position); + + while ((!detectedIndent || state.lineIndent < textIndent) && + (ch === 0x20/* Space */)) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + + if (!detectedIndent && state.lineIndent > textIndent) { + textIndent = state.lineIndent; + } + + if (is_EOL(ch)) { + emptyLines++; + continue; + } + + // End of the scalar. + if (state.lineIndent < textIndent) { + + // Perform the chomping. + if (chomping === CHOMPING_KEEP) { + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } else if (chomping === CHOMPING_CLIP) { + if (didReadContent) { // i.e. only if the scalar is not empty. + state.result += '\n'; + } + } + + // Break this `while` cycle and go to the funciton's epilogue. + break; + } + + // Folded style: use fancy rules to handle line breaks. + if (folding) { + + // Lines starting with white space characters (more-indented lines) are not folded. + if (is_WHITE_SPACE(ch)) { + atMoreIndented = true; + // except for the first content line (cf. Example 8.1) + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + + // End of more-indented block. + } else if (atMoreIndented) { + atMoreIndented = false; + state.result += common.repeat('\n', emptyLines + 1); + + // Just one line break - perceive as the same line. + } else if (emptyLines === 0) { + if (didReadContent) { // i.e. only if we have already read some scalar content. + state.result += ' '; + } + + // Several line breaks - perceive as different lines. + } else { + state.result += common.repeat('\n', emptyLines); + } + + // Literal style: just add exact number of line breaks between content lines. + } else { + // Keep all line breaks except the header line break. + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } + + didReadContent = true; + detectedIndent = true; + emptyLines = 0; + captureStart = state.position; + + while (!is_EOL(ch) && (ch !== 0)) { + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, state.position, false); + } + + return true; +} + +function readBlockSequence(state, nodeIndent) { + var _line, + _tag = state.tag, + _anchor = state.anchor, + _result = [], + following, + detected = false, + ch; + + // there is a leading tab before this token, so it can't be a block sequence/mapping; + // it can still be flow sequence/mapping or a scalar + if (state.firstTabInLine !== -1) return false; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + if (state.firstTabInLine !== -1) { + state.position = state.firstTabInLine; + throwError(state, 'tab characters must not be used in indentation'); + } + + if (ch !== 0x2D/* - */) { + break; + } + + following = state.input.charCodeAt(state.position + 1); + + if (!is_WS_OR_EOL(following)) { + break; + } + + detected = true; + state.position++; + + if (skipSeparationSpace(state, true, -1)) { + if (state.lineIndent <= nodeIndent) { + _result.push(null); + ch = state.input.charCodeAt(state.position); + continue; + } + } + + _line = state.line; + composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true); + _result.push(state.result); + skipSeparationSpace(state, true, -1); + + ch = state.input.charCodeAt(state.position); + + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a sequence entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'sequence'; + state.result = _result; + return true; + } + return false; +} + +function readBlockMapping(state, nodeIndent, flowIndent) { + var following, + allowCompact, + _line, + _keyLine, + _keyLineStart, + _keyPos, + _tag = state.tag, + _anchor = state.anchor, + _result = {}, + overridableKeys = Object.create(null), + keyTag = null, + keyNode = null, + valueNode = null, + atExplicitKey = false, + detected = false, + ch; + + // there is a leading tab before this token, so it can't be a block sequence/mapping; + // it can still be flow sequence/mapping or a scalar + if (state.firstTabInLine !== -1) return false; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + if (!atExplicitKey && state.firstTabInLine !== -1) { + state.position = state.firstTabInLine; + throwError(state, 'tab characters must not be used in indentation'); + } + + following = state.input.charCodeAt(state.position + 1); + _line = state.line; // Save the current line. + + // + // Explicit notation case. There are two separate blocks: + // first for the key (denoted by "?") and second for the value (denoted by ":") + // + if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && is_WS_OR_EOL(following)) { + + if (ch === 0x3F/* ? */) { + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + + detected = true; + atExplicitKey = true; + allowCompact = true; + + } else if (atExplicitKey) { + // i.e. 0x3A/* : */ === character after the explicit key. + atExplicitKey = false; + allowCompact = true; + + } else { + throwError(state, 'incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line'); + } + + state.position += 1; + ch = following; + + // + // Implicit notation case. Flow-style node as the key first, then ":", and the value. + // + } else { + _keyLine = state.line; + _keyLineStart = state.lineStart; + _keyPos = state.position; + + if (!composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) { + // Neither implicit nor explicit notation. + // Reading is done. Go to the epilogue. + break; + } + + if (state.line === _line) { + ch = state.input.charCodeAt(state.position); + + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (ch === 0x3A/* : */) { + ch = state.input.charCodeAt(++state.position); + + if (!is_WS_OR_EOL(ch)) { + throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping'); + } + + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + + detected = true; + atExplicitKey = false; + allowCompact = false; + keyTag = state.tag; + keyNode = state.result; + + } else if (detected) { + throwError(state, 'can not read an implicit mapping pair; a colon is missed'); + + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + + } else if (detected) { + throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key'); + + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + } + + // + // Common reading code for both explicit and implicit notations. + // + if (state.line === _line || state.lineIndent > nodeIndent) { + if (atExplicitKey) { + _keyLine = state.line; + _keyLineStart = state.lineStart; + _keyPos = state.position; + } + + if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) { + if (atExplicitKey) { + keyNode = state.result; + } else { + valueNode = state.result; + } + } + + if (!atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + } + + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a mapping entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + + // + // Epilogue. + // + + // Special case: last mapping's node contains only the key in explicit notation. + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + } + + // Expose the resulting mapping. + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'mapping'; + state.result = _result; + } + + return detected; +} + +function readTagProperty(state) { + var _position, + isVerbatim = false, + isNamed = false, + tagHandle, + tagName, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x21/* ! */) return false; + + if (state.tag !== null) { + throwError(state, 'duplication of a tag property'); + } + + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x3C/* < */) { + isVerbatim = true; + ch = state.input.charCodeAt(++state.position); + + } else if (ch === 0x21/* ! */) { + isNamed = true; + tagHandle = '!!'; + ch = state.input.charCodeAt(++state.position); + + } else { + tagHandle = '!'; + } + + _position = state.position; + + if (isVerbatim) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && ch !== 0x3E/* > */); + + if (state.position < state.length) { + tagName = state.input.slice(_position, state.position); + ch = state.input.charCodeAt(++state.position); + } else { + throwError(state, 'unexpected end of the stream within a verbatim tag'); + } + } else { + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + + if (ch === 0x21/* ! */) { + if (!isNamed) { + tagHandle = state.input.slice(_position - 1, state.position + 1); + + if (!PATTERN_TAG_HANDLE.test(tagHandle)) { + throwError(state, 'named tag handle cannot contain such characters'); + } + + isNamed = true; + _position = state.position + 1; + } else { + throwError(state, 'tag suffix cannot contain exclamation marks'); + } + } + + ch = state.input.charCodeAt(++state.position); + } + + tagName = state.input.slice(_position, state.position); + + if (PATTERN_FLOW_INDICATORS.test(tagName)) { + throwError(state, 'tag suffix cannot contain flow indicator characters'); + } + } + + if (tagName && !PATTERN_TAG_URI.test(tagName)) { + throwError(state, 'tag name cannot contain such characters: ' + tagName); + } + + try { + tagName = decodeURIComponent(tagName); + } catch (err) { + throwError(state, 'tag name is malformed: ' + tagName); + } + + if (isVerbatim) { + state.tag = tagName; + + } else if (_hasOwnProperty.call(state.tagMap, tagHandle)) { + state.tag = state.tagMap[tagHandle] + tagName; + + } else if (tagHandle === '!') { + state.tag = '!' + tagName; + + } else if (tagHandle === '!!') { + state.tag = 'tag:yaml.org,2002:' + tagName; + + } else { + throwError(state, 'undeclared tag handle "' + tagHandle + '"'); + } + + return true; +} + +function readAnchorProperty(state) { + var _position, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x26/* & */) return false; + + if (state.anchor !== null) { + throwError(state, 'duplication of an anchor property'); + } + + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (state.position === _position) { + throwError(state, 'name of an anchor node must contain at least one character'); + } + + state.anchor = state.input.slice(_position, state.position); + return true; +} + +function readAlias(state) { + var _position, alias, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x2A/* * */) return false; + + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (state.position === _position) { + throwError(state, 'name of an alias node must contain at least one character'); + } + + alias = state.input.slice(_position, state.position); + + if (!_hasOwnProperty.call(state.anchorMap, alias)) { + throwError(state, 'unidentified alias "' + alias + '"'); + } + + state.result = state.anchorMap[alias]; + skipSeparationSpace(state, true, -1); + return true; +} + +function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) { + var allowBlockStyles, + allowBlockScalars, + allowBlockCollections, + indentStatus = 1, // 1: this>parent, 0: this=parent, -1: this parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } + } + + if (indentStatus === 1) { + while (readTagProperty(state) || readAnchorProperty(state)) { + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + allowBlockCollections = allowBlockStyles; + + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } else { + allowBlockCollections = false; + } + } + } + + if (allowBlockCollections) { + allowBlockCollections = atNewLine || allowCompact; + } + + if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) { + if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) { + flowIndent = parentIndent; + } else { + flowIndent = parentIndent + 1; + } + + blockIndent = state.position - state.lineStart; + + if (indentStatus === 1) { + if (allowBlockCollections && + (readBlockSequence(state, blockIndent) || + readBlockMapping(state, blockIndent, flowIndent)) || + readFlowCollection(state, flowIndent)) { + hasContent = true; + } else { + if ((allowBlockScalars && readBlockScalar(state, flowIndent)) || + readSingleQuotedScalar(state, flowIndent) || + readDoubleQuotedScalar(state, flowIndent)) { + hasContent = true; + + } else if (readAlias(state)) { + hasContent = true; + + if (state.tag !== null || state.anchor !== null) { + throwError(state, 'alias node should not have any properties'); + } + + } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) { + hasContent = true; + + if (state.tag === null) { + state.tag = '?'; + } + } + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } else if (indentStatus === 0) { + // Special case: block sequences are allowed to have same indentation level as the parent. + // http://www.yaml.org/spec/1.2/spec.html#id2799784 + hasContent = allowBlockCollections && readBlockSequence(state, blockIndent); + } + } + + if (state.tag === null) { + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + + } else if (state.tag === '?') { + // Implicit resolving is not allowed for non-scalar types, and '?' + // non-specific tag is only automatically assigned to plain scalars. + // + // We only need to check kind conformity in case user explicitly assigns '?' + // tag, for example like this: "! [0]" + // + if (state.result !== null && state.kind !== 'scalar') { + throwError(state, 'unacceptable node kind for ! tag; it should be "scalar", not "' + state.kind + '"'); + } + + for (typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) { + type = state.implicitTypes[typeIndex]; + + if (type.resolve(state.result)) { // `state.result` updated in resolver if matched + state.result = type.construct(state.result); + state.tag = type.tag; + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + break; + } + } + } else if (state.tag !== '!') { + if (_hasOwnProperty.call(state.typeMap[state.kind || 'fallback'], state.tag)) { + type = state.typeMap[state.kind || 'fallback'][state.tag]; + } else { + // looking for multi type + type = null; + typeList = state.typeMap.multi[state.kind || 'fallback']; + + for (typeIndex = 0, typeQuantity = typeList.length; typeIndex < typeQuantity; typeIndex += 1) { + if (state.tag.slice(0, typeList[typeIndex].tag.length) === typeList[typeIndex].tag) { + type = typeList[typeIndex]; + break; + } + } + } + + if (!type) { + throwError(state, 'unknown tag !<' + state.tag + '>'); + } + + if (state.result !== null && type.kind !== state.kind) { + throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"'); + } + + if (!type.resolve(state.result, state.tag)) { // `state.result` updated in resolver if matched + throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag'); + } else { + state.result = type.construct(state.result, state.tag); + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } + + if (state.listener !== null) { + state.listener('close', state); + } + return state.tag !== null || state.anchor !== null || hasContent; +} + +function readDocument(state) { + var documentStart = state.position, + _position, + directiveName, + directiveArgs, + hasDirectives = false, + ch; + + state.version = null; + state.checkLineBreaks = state.legacy; + state.tagMap = Object.create(null); + state.anchorMap = Object.create(null); + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + skipSeparationSpace(state, true, -1); + + ch = state.input.charCodeAt(state.position); + + if (state.lineIndent > 0 || ch !== 0x25/* % */) { + break; + } + + hasDirectives = true; + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + directiveName = state.input.slice(_position, state.position); + directiveArgs = []; + + if (directiveName.length < 1) { + throwError(state, 'directive name must not be less than one character in length'); + } + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && !is_EOL(ch)); + break; + } + + if (is_EOL(ch)) break; + + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + directiveArgs.push(state.input.slice(_position, state.position)); + } + + if (ch !== 0) readLineBreak(state); + + if (_hasOwnProperty.call(directiveHandlers, directiveName)) { + directiveHandlers[directiveName](state, directiveName, directiveArgs); + } else { + throwWarning(state, 'unknown document directive "' + directiveName + '"'); + } + } + + skipSeparationSpace(state, true, -1); + + if (state.lineIndent === 0 && + state.input.charCodeAt(state.position) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 1) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 2) === 0x2D/* - */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + + } else if (hasDirectives) { + throwError(state, 'directives end mark is expected'); + } + + composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true); + skipSeparationSpace(state, true, -1); + + if (state.checkLineBreaks && + PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) { + throwWarning(state, 'non-ASCII line breaks are interpreted as content'); + } + + state.documents.push(state.result); + + if (state.position === state.lineStart && testDocumentSeparator(state)) { + + if (state.input.charCodeAt(state.position) === 0x2E/* . */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + } + return; + } + + if (state.position < (state.length - 1)) { + throwError(state, 'end of the stream or a document separator is expected'); + } else { + return; + } +} + + +function loadDocuments(input, options) { + input = String(input); + options = options || {}; + + if (input.length !== 0) { + + // Add tailing `\n` if not exists + if (input.charCodeAt(input.length - 1) !== 0x0A/* LF */ && + input.charCodeAt(input.length - 1) !== 0x0D/* CR */) { + input += '\n'; + } + + // Strip BOM + if (input.charCodeAt(0) === 0xFEFF) { + input = input.slice(1); + } + } + + var state = new State(input, options); + + var nullpos = input.indexOf('\0'); + + if (nullpos !== -1) { + state.position = nullpos; + throwError(state, 'null byte is not allowed in input'); + } + + // Use 0 as string terminator. That significantly simplifies bounds check. + state.input += '\0'; + + while (state.input.charCodeAt(state.position) === 0x20/* Space */) { + state.lineIndent += 1; + state.position += 1; + } + + while (state.position < (state.length - 1)) { + readDocument(state); + } + + return state.documents; +} + + +function loadAll(input, iterator, options) { + if (iterator !== null && typeof iterator === 'object' && typeof options === 'undefined') { + options = iterator; + iterator = null; + } + + var documents = loadDocuments(input, options); + + if (typeof iterator !== 'function') { + return documents; + } + + for (var index = 0, length = documents.length; index < length; index += 1) { + iterator(documents[index]); + } +} + + +function load(input, options) { + var documents = loadDocuments(input, options); + + if (documents.length === 0) { + /*eslint-disable no-undefined*/ + return undefined; + } else if (documents.length === 1) { + return documents[0]; + } + throw new YAMLException('expected a single document in the stream, but found more'); +} + + +module.exports.loadAll = loadAll; +module.exports.load = load; diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema.js new file mode 100644 index 00000000..65b41f40 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema.js @@ -0,0 +1,121 @@ +'use strict'; + +/*eslint-disable max-len*/ + +var YAMLException = require('./exception'); +var Type = require('./type'); + + +function compileList(schema, name) { + var result = []; + + schema[name].forEach(function (currentType) { + var newIndex = result.length; + + result.forEach(function (previousType, previousIndex) { + if (previousType.tag === currentType.tag && + previousType.kind === currentType.kind && + previousType.multi === currentType.multi) { + + newIndex = previousIndex; + } + }); + + result[newIndex] = currentType; + }); + + return result; +} + + +function compileMap(/* lists... */) { + var result = { + scalar: {}, + sequence: {}, + mapping: {}, + fallback: {}, + multi: { + scalar: [], + sequence: [], + mapping: [], + fallback: [] + } + }, index, length; + + function collectType(type) { + if (type.multi) { + result.multi[type.kind].push(type); + result.multi['fallback'].push(type); + } else { + result[type.kind][type.tag] = result['fallback'][type.tag] = type; + } + } + + for (index = 0, length = arguments.length; index < length; index += 1) { + arguments[index].forEach(collectType); + } + return result; +} + + +function Schema(definition) { + return this.extend(definition); +} + + +Schema.prototype.extend = function extend(definition) { + var implicit = []; + var explicit = []; + + if (definition instanceof Type) { + // Schema.extend(type) + explicit.push(definition); + + } else if (Array.isArray(definition)) { + // Schema.extend([ type1, type2, ... ]) + explicit = explicit.concat(definition); + + } else if (definition && (Array.isArray(definition.implicit) || Array.isArray(definition.explicit))) { + // Schema.extend({ explicit: [ type1, type2, ... ], implicit: [ type1, type2, ... ] }) + if (definition.implicit) implicit = implicit.concat(definition.implicit); + if (definition.explicit) explicit = explicit.concat(definition.explicit); + + } else { + throw new YAMLException('Schema.extend argument should be a Type, [ Type ], ' + + 'or a schema definition ({ implicit: [...], explicit: [...] })'); + } + + implicit.forEach(function (type) { + if (!(type instanceof Type)) { + throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.'); + } + + if (type.loadKind && type.loadKind !== 'scalar') { + throw new YAMLException('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.'); + } + + if (type.multi) { + throw new YAMLException('There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.'); + } + }); + + explicit.forEach(function (type) { + if (!(type instanceof Type)) { + throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.'); + } + }); + + var result = Object.create(Schema.prototype); + + result.implicit = (this.implicit || []).concat(implicit); + result.explicit = (this.explicit || []).concat(explicit); + + result.compiledImplicit = compileList(result, 'implicit'); + result.compiledExplicit = compileList(result, 'explicit'); + result.compiledTypeMap = compileMap(result.compiledImplicit, result.compiledExplicit); + + return result; +}; + + +module.exports = Schema; diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/core.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/core.js new file mode 100644 index 00000000..608b26de --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/core.js @@ -0,0 +1,11 @@ +// Standard YAML's Core schema. +// http://www.yaml.org/spec/1.2/spec.html#id2804923 +// +// NOTE: JS-YAML does not support schema-specific tag resolution restrictions. +// So, Core schema has no distinctions from JSON schema is JS-YAML. + + +'use strict'; + + +module.exports = require('./json'); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/default.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/default.js new file mode 100644 index 00000000..3af0520d --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/default.js @@ -0,0 +1,22 @@ +// JS-YAML's default schema for `safeLoad` function. +// It is not described in the YAML specification. +// +// This schema is based on standard YAML's Core schema and includes most of +// extra types described at YAML tag repository. (http://yaml.org/type/) + + +'use strict'; + + +module.exports = require('./core').extend({ + implicit: [ + require('../type/timestamp'), + require('../type/merge') + ], + explicit: [ + require('../type/binary'), + require('../type/omap'), + require('../type/pairs'), + require('../type/set') + ] +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/failsafe.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/failsafe.js new file mode 100644 index 00000000..b7a33eb7 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/failsafe.js @@ -0,0 +1,17 @@ +// Standard YAML's Failsafe schema. +// http://www.yaml.org/spec/1.2/spec.html#id2802346 + + +'use strict'; + + +var Schema = require('../schema'); + + +module.exports = new Schema({ + explicit: [ + require('../type/str'), + require('../type/seq'), + require('../type/map') + ] +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/json.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/json.js new file mode 100644 index 00000000..b73df78e --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/schema/json.js @@ -0,0 +1,19 @@ +// Standard YAML's JSON schema. +// http://www.yaml.org/spec/1.2/spec.html#id2803231 +// +// NOTE: JS-YAML does not support schema-specific tag resolution restrictions. +// So, this schema is not such strict as defined in the YAML specification. +// It allows numbers in binary notaion, use `Null` and `NULL` as `null`, etc. + + +'use strict'; + + +module.exports = require('./failsafe').extend({ + implicit: [ + require('../type/null'), + require('../type/bool'), + require('../type/int'), + require('../type/float') + ] +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/snippet.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/snippet.js new file mode 100644 index 00000000..00e2133c --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/snippet.js @@ -0,0 +1,101 @@ +'use strict'; + + +var common = require('./common'); + + +// get snippet for a single line, respecting maxLength +function getLine(buffer, lineStart, lineEnd, position, maxLineLength) { + var head = ''; + var tail = ''; + var maxHalfLength = Math.floor(maxLineLength / 2) - 1; + + if (position - lineStart > maxHalfLength) { + head = ' ... '; + lineStart = position - maxHalfLength + head.length; + } + + if (lineEnd - position > maxHalfLength) { + tail = ' ...'; + lineEnd = position + maxHalfLength - tail.length; + } + + return { + str: head + buffer.slice(lineStart, lineEnd).replace(/\t/g, '→') + tail, + pos: position - lineStart + head.length // relative position + }; +} + + +function padStart(string, max) { + return common.repeat(' ', max - string.length) + string; +} + + +function makeSnippet(mark, options) { + options = Object.create(options || null); + + if (!mark.buffer) return null; + + if (!options.maxLength) options.maxLength = 79; + if (typeof options.indent !== 'number') options.indent = 1; + if (typeof options.linesBefore !== 'number') options.linesBefore = 3; + if (typeof options.linesAfter !== 'number') options.linesAfter = 2; + + var re = /\r?\n|\r|\0/g; + var lineStarts = [ 0 ]; + var lineEnds = []; + var match; + var foundLineNo = -1; + + while ((match = re.exec(mark.buffer))) { + lineEnds.push(match.index); + lineStarts.push(match.index + match[0].length); + + if (mark.position <= match.index && foundLineNo < 0) { + foundLineNo = lineStarts.length - 2; + } + } + + if (foundLineNo < 0) foundLineNo = lineStarts.length - 1; + + var result = '', i, line; + var lineNoLength = Math.min(mark.line + options.linesAfter, lineEnds.length).toString().length; + var maxLineLength = options.maxLength - (options.indent + lineNoLength + 3); + + for (i = 1; i <= options.linesBefore; i++) { + if (foundLineNo - i < 0) break; + line = getLine( + mark.buffer, + lineStarts[foundLineNo - i], + lineEnds[foundLineNo - i], + mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo - i]), + maxLineLength + ); + result = common.repeat(' ', options.indent) + padStart((mark.line - i + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n' + result; + } + + line = getLine(mark.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark.position, maxLineLength); + result += common.repeat(' ', options.indent) + padStart((mark.line + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n'; + result += common.repeat('-', options.indent + lineNoLength + 3 + line.pos) + '^' + '\n'; + + for (i = 1; i <= options.linesAfter; i++) { + if (foundLineNo + i >= lineEnds.length) break; + line = getLine( + mark.buffer, + lineStarts[foundLineNo + i], + lineEnds[foundLineNo + i], + mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo + i]), + maxLineLength + ); + result += common.repeat(' ', options.indent) + padStart((mark.line + i + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n'; + } + + return result.replace(/\n$/, ''); +} + + +module.exports = makeSnippet; diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/type.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type.js new file mode 100644 index 00000000..5e57877f --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type.js @@ -0,0 +1,66 @@ +'use strict'; + +var YAMLException = require('./exception'); + +var TYPE_CONSTRUCTOR_OPTIONS = [ + 'kind', + 'multi', + 'resolve', + 'construct', + 'instanceOf', + 'predicate', + 'represent', + 'representName', + 'defaultStyle', + 'styleAliases' +]; + +var YAML_NODE_KINDS = [ + 'scalar', + 'sequence', + 'mapping' +]; + +function compileStyleAliases(map) { + var result = {}; + + if (map !== null) { + Object.keys(map).forEach(function (style) { + map[style].forEach(function (alias) { + result[String(alias)] = style; + }); + }); + } + + return result; +} + +function Type(tag, options) { + options = options || {}; + + Object.keys(options).forEach(function (name) { + if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { + throw new YAMLException('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); + } + }); + + // TODO: Add tag format check. + this.options = options; // keep original options in case user wants to extend this type later + this.tag = tag; + this.kind = options['kind'] || null; + this.resolve = options['resolve'] || function () { return true; }; + this.construct = options['construct'] || function (data) { return data; }; + this.instanceOf = options['instanceOf'] || null; + this.predicate = options['predicate'] || null; + this.represent = options['represent'] || null; + this.representName = options['representName'] || null; + this.defaultStyle = options['defaultStyle'] || null; + this.multi = options['multi'] || false; + this.styleAliases = compileStyleAliases(options['styleAliases'] || null); + + if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { + throw new YAMLException('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); + } +} + +module.exports = Type; diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/binary.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/binary.js new file mode 100644 index 00000000..e1523513 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/binary.js @@ -0,0 +1,125 @@ +'use strict'; + +/*eslint-disable no-bitwise*/ + + +var Type = require('../type'); + + +// [ 64, 65, 66 ] -> [ padding, CR, LF ] +var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r'; + + +function resolveYamlBinary(data) { + if (data === null) return false; + + var code, idx, bitlen = 0, max = data.length, map = BASE64_MAP; + + // Convert one by one. + for (idx = 0; idx < max; idx++) { + code = map.indexOf(data.charAt(idx)); + + // Skip CR/LF + if (code > 64) continue; + + // Fail on illegal characters + if (code < 0) return false; + + bitlen += 6; + } + + // If there are any bits left, source was corrupted + return (bitlen % 8) === 0; +} + +function constructYamlBinary(data) { + var idx, tailbits, + input = data.replace(/[\r\n=]/g, ''), // remove CR/LF & padding to simplify scan + max = input.length, + map = BASE64_MAP, + bits = 0, + result = []; + + // Collect by 6*4 bits (3 bytes) + + for (idx = 0; idx < max; idx++) { + if ((idx % 4 === 0) && idx) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } + + bits = (bits << 6) | map.indexOf(input.charAt(idx)); + } + + // Dump tail + + tailbits = (max % 4) * 6; + + if (tailbits === 0) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } else if (tailbits === 18) { + result.push((bits >> 10) & 0xFF); + result.push((bits >> 2) & 0xFF); + } else if (tailbits === 12) { + result.push((bits >> 4) & 0xFF); + } + + return new Uint8Array(result); +} + +function representYamlBinary(object /*, style*/) { + var result = '', bits = 0, idx, tail, + max = object.length, + map = BASE64_MAP; + + // Convert every three bytes to 4 ASCII characters. + + for (idx = 0; idx < max; idx++) { + if ((idx % 3 === 0) && idx) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } + + bits = (bits << 8) + object[idx]; + } + + // Dump tail + + tail = max % 3; + + if (tail === 0) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } else if (tail === 2) { + result += map[(bits >> 10) & 0x3F]; + result += map[(bits >> 4) & 0x3F]; + result += map[(bits << 2) & 0x3F]; + result += map[64]; + } else if (tail === 1) { + result += map[(bits >> 2) & 0x3F]; + result += map[(bits << 4) & 0x3F]; + result += map[64]; + result += map[64]; + } + + return result; +} + +function isBinary(obj) { + return Object.prototype.toString.call(obj) === '[object Uint8Array]'; +} + +module.exports = new Type('tag:yaml.org,2002:binary', { + kind: 'scalar', + resolve: resolveYamlBinary, + construct: constructYamlBinary, + predicate: isBinary, + represent: representYamlBinary +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/bool.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/bool.js new file mode 100644 index 00000000..cb774593 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/bool.js @@ -0,0 +1,35 @@ +'use strict'; + +var Type = require('../type'); + +function resolveYamlBoolean(data) { + if (data === null) return false; + + var max = data.length; + + return (max === 4 && (data === 'true' || data === 'True' || data === 'TRUE')) || + (max === 5 && (data === 'false' || data === 'False' || data === 'FALSE')); +} + +function constructYamlBoolean(data) { + return data === 'true' || + data === 'True' || + data === 'TRUE'; +} + +function isBoolean(object) { + return Object.prototype.toString.call(object) === '[object Boolean]'; +} + +module.exports = new Type('tag:yaml.org,2002:bool', { + kind: 'scalar', + resolve: resolveYamlBoolean, + construct: constructYamlBoolean, + predicate: isBoolean, + represent: { + lowercase: function (object) { return object ? 'true' : 'false'; }, + uppercase: function (object) { return object ? 'TRUE' : 'FALSE'; }, + camelcase: function (object) { return object ? 'True' : 'False'; } + }, + defaultStyle: 'lowercase' +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/float.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/float.js new file mode 100644 index 00000000..74d77ec2 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/float.js @@ -0,0 +1,97 @@ +'use strict'; + +var common = require('../common'); +var Type = require('../type'); + +var YAML_FLOAT_PATTERN = new RegExp( + // 2.5e4, 2.5 and integers + '^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?' + + // .2e4, .2 + // special case, seems not from spec + '|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?' + + // .inf + '|[-+]?\\.(?:inf|Inf|INF)' + + // .nan + '|\\.(?:nan|NaN|NAN))$'); + +function resolveYamlFloat(data) { + if (data === null) return false; + + if (!YAML_FLOAT_PATTERN.test(data) || + // Quick hack to not allow integers end with `_` + // Probably should update regexp & check speed + data[data.length - 1] === '_') { + return false; + } + + return true; +} + +function constructYamlFloat(data) { + var value, sign; + + value = data.replace(/_/g, '').toLowerCase(); + sign = value[0] === '-' ? -1 : 1; + + if ('+-'.indexOf(value[0]) >= 0) { + value = value.slice(1); + } + + if (value === '.inf') { + return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; + + } else if (value === '.nan') { + return NaN; + } + return sign * parseFloat(value, 10); +} + + +var SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/; + +function representYamlFloat(object, style) { + var res; + + if (isNaN(object)) { + switch (style) { + case 'lowercase': return '.nan'; + case 'uppercase': return '.NAN'; + case 'camelcase': return '.NaN'; + } + } else if (Number.POSITIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '.inf'; + case 'uppercase': return '.INF'; + case 'camelcase': return '.Inf'; + } + } else if (Number.NEGATIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '-.inf'; + case 'uppercase': return '-.INF'; + case 'camelcase': return '-.Inf'; + } + } else if (common.isNegativeZero(object)) { + return '-0.0'; + } + + res = object.toString(10); + + // JS stringifier can build scientific format without dots: 5e-100, + // while YAML requres dot: 5.e-100. Fix it with simple hack + + return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res; +} + +function isFloat(object) { + return (Object.prototype.toString.call(object) === '[object Number]') && + (object % 1 !== 0 || common.isNegativeZero(object)); +} + +module.exports = new Type('tag:yaml.org,2002:float', { + kind: 'scalar', + resolve: resolveYamlFloat, + construct: constructYamlFloat, + predicate: isFloat, + represent: representYamlFloat, + defaultStyle: 'lowercase' +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/int.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/int.js new file mode 100644 index 00000000..3fe3a443 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/int.js @@ -0,0 +1,156 @@ +'use strict'; + +var common = require('../common'); +var Type = require('../type'); + +function isHexCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) || + ((0x41/* A */ <= c) && (c <= 0x46/* F */)) || + ((0x61/* a */ <= c) && (c <= 0x66/* f */)); +} + +function isOctCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x37/* 7 */)); +} + +function isDecCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)); +} + +function resolveYamlInteger(data) { + if (data === null) return false; + + var max = data.length, + index = 0, + hasDigits = false, + ch; + + if (!max) return false; + + ch = data[index]; + + // sign + if (ch === '-' || ch === '+') { + ch = data[++index]; + } + + if (ch === '0') { + // 0 + if (index + 1 === max) return true; + ch = data[++index]; + + // base 2, base 8, base 16 + + if (ch === 'b') { + // base 2 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (ch !== '0' && ch !== '1') return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + + + if (ch === 'x') { + // base 16 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isHexCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + + + if (ch === 'o') { + // base 8 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isOctCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + } + + // base 10 (except 0) + + // value should not start with `_`; + if (ch === '_') return false; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isDecCode(data.charCodeAt(index))) { + return false; + } + hasDigits = true; + } + + // Should have digits and should not end with `_` + if (!hasDigits || ch === '_') return false; + + return true; +} + +function constructYamlInteger(data) { + var value = data, sign = 1, ch; + + if (value.indexOf('_') !== -1) { + value = value.replace(/_/g, ''); + } + + ch = value[0]; + + if (ch === '-' || ch === '+') { + if (ch === '-') sign = -1; + value = value.slice(1); + ch = value[0]; + } + + if (value === '0') return 0; + + if (ch === '0') { + if (value[1] === 'b') return sign * parseInt(value.slice(2), 2); + if (value[1] === 'x') return sign * parseInt(value.slice(2), 16); + if (value[1] === 'o') return sign * parseInt(value.slice(2), 8); + } + + return sign * parseInt(value, 10); +} + +function isInteger(object) { + return (Object.prototype.toString.call(object)) === '[object Number]' && + (object % 1 === 0 && !common.isNegativeZero(object)); +} + +module.exports = new Type('tag:yaml.org,2002:int', { + kind: 'scalar', + resolve: resolveYamlInteger, + construct: constructYamlInteger, + predicate: isInteger, + represent: { + binary: function (obj) { return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1); }, + octal: function (obj) { return obj >= 0 ? '0o' + obj.toString(8) : '-0o' + obj.toString(8).slice(1); }, + decimal: function (obj) { return obj.toString(10); }, + /* eslint-disable max-len */ + hexadecimal: function (obj) { return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1); } + }, + defaultStyle: 'decimal', + styleAliases: { + binary: [ 2, 'bin' ], + octal: [ 8, 'oct' ], + decimal: [ 10, 'dec' ], + hexadecimal: [ 16, 'hex' ] + } +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/map.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/map.js new file mode 100644 index 00000000..f327beeb --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/map.js @@ -0,0 +1,8 @@ +'use strict'; + +var Type = require('../type'); + +module.exports = new Type('tag:yaml.org,2002:map', { + kind: 'mapping', + construct: function (data) { return data !== null ? data : {}; } +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/merge.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/merge.js new file mode 100644 index 00000000..ae08a864 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/merge.js @@ -0,0 +1,12 @@ +'use strict'; + +var Type = require('../type'); + +function resolveYamlMerge(data) { + return data === '<<' || data === null; +} + +module.exports = new Type('tag:yaml.org,2002:merge', { + kind: 'scalar', + resolve: resolveYamlMerge +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/null.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/null.js new file mode 100644 index 00000000..315ca4e2 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/null.js @@ -0,0 +1,35 @@ +'use strict'; + +var Type = require('../type'); + +function resolveYamlNull(data) { + if (data === null) return true; + + var max = data.length; + + return (max === 1 && data === '~') || + (max === 4 && (data === 'null' || data === 'Null' || data === 'NULL')); +} + +function constructYamlNull() { + return null; +} + +function isNull(object) { + return object === null; +} + +module.exports = new Type('tag:yaml.org,2002:null', { + kind: 'scalar', + resolve: resolveYamlNull, + construct: constructYamlNull, + predicate: isNull, + represent: { + canonical: function () { return '~'; }, + lowercase: function () { return 'null'; }, + uppercase: function () { return 'NULL'; }, + camelcase: function () { return 'Null'; }, + empty: function () { return ''; } + }, + defaultStyle: 'lowercase' +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/omap.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/omap.js new file mode 100644 index 00000000..b2b5323b --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/omap.js @@ -0,0 +1,44 @@ +'use strict'; + +var Type = require('../type'); + +var _hasOwnProperty = Object.prototype.hasOwnProperty; +var _toString = Object.prototype.toString; + +function resolveYamlOmap(data) { + if (data === null) return true; + + var objectKeys = [], index, length, pair, pairKey, pairHasKey, + object = data; + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + pairHasKey = false; + + if (_toString.call(pair) !== '[object Object]') return false; + + for (pairKey in pair) { + if (_hasOwnProperty.call(pair, pairKey)) { + if (!pairHasKey) pairHasKey = true; + else return false; + } + } + + if (!pairHasKey) return false; + + if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey); + else return false; + } + + return true; +} + +function constructYamlOmap(data) { + return data !== null ? data : []; +} + +module.exports = new Type('tag:yaml.org,2002:omap', { + kind: 'sequence', + resolve: resolveYamlOmap, + construct: constructYamlOmap +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/pairs.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/pairs.js new file mode 100644 index 00000000..74b52403 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/pairs.js @@ -0,0 +1,53 @@ +'use strict'; + +var Type = require('../type'); + +var _toString = Object.prototype.toString; + +function resolveYamlPairs(data) { + if (data === null) return true; + + var index, length, pair, keys, result, + object = data; + + result = new Array(object.length); + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + + if (_toString.call(pair) !== '[object Object]') return false; + + keys = Object.keys(pair); + + if (keys.length !== 1) return false; + + result[index] = [ keys[0], pair[keys[0]] ]; + } + + return true; +} + +function constructYamlPairs(data) { + if (data === null) return []; + + var index, length, pair, keys, result, + object = data; + + result = new Array(object.length); + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + + keys = Object.keys(pair); + + result[index] = [ keys[0], pair[keys[0]] ]; + } + + return result; +} + +module.exports = new Type('tag:yaml.org,2002:pairs', { + kind: 'sequence', + resolve: resolveYamlPairs, + construct: constructYamlPairs +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/seq.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/seq.js new file mode 100644 index 00000000..be8f77f2 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/seq.js @@ -0,0 +1,8 @@ +'use strict'; + +var Type = require('../type'); + +module.exports = new Type('tag:yaml.org,2002:seq', { + kind: 'sequence', + construct: function (data) { return data !== null ? data : []; } +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/set.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/set.js new file mode 100644 index 00000000..f885a329 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/set.js @@ -0,0 +1,29 @@ +'use strict'; + +var Type = require('../type'); + +var _hasOwnProperty = Object.prototype.hasOwnProperty; + +function resolveYamlSet(data) { + if (data === null) return true; + + var key, object = data; + + for (key in object) { + if (_hasOwnProperty.call(object, key)) { + if (object[key] !== null) return false; + } + } + + return true; +} + +function constructYamlSet(data) { + return data !== null ? data : {}; +} + +module.exports = new Type('tag:yaml.org,2002:set', { + kind: 'mapping', + resolve: resolveYamlSet, + construct: constructYamlSet +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/str.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/str.js new file mode 100644 index 00000000..27acc106 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/str.js @@ -0,0 +1,8 @@ +'use strict'; + +var Type = require('../type'); + +module.exports = new Type('tag:yaml.org,2002:str', { + kind: 'scalar', + construct: function (data) { return data !== null ? data : ''; } +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/timestamp.js b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/timestamp.js new file mode 100644 index 00000000..8fa9c586 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/lib/type/timestamp.js @@ -0,0 +1,88 @@ +'use strict'; + +var Type = require('../type'); + +var YAML_DATE_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9])' + // [2] month + '-([0-9][0-9])$'); // [3] day + +var YAML_TIMESTAMP_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9]?)' + // [2] month + '-([0-9][0-9]?)' + // [3] day + '(?:[Tt]|[ \\t]+)' + // ... + '([0-9][0-9]?)' + // [4] hour + ':([0-9][0-9])' + // [5] minute + ':([0-9][0-9])' + // [6] second + '(?:\\.([0-9]*))?' + // [7] fraction + '(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tz_hour + '(?::([0-9][0-9]))?))?$'); // [11] tz_minute + +function resolveYamlTimestamp(data) { + if (data === null) return false; + if (YAML_DATE_REGEXP.exec(data) !== null) return true; + if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true; + return false; +} + +function constructYamlTimestamp(data) { + var match, year, month, day, hour, minute, second, fraction = 0, + delta = null, tz_hour, tz_minute, date; + + match = YAML_DATE_REGEXP.exec(data); + if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data); + + if (match === null) throw new Error('Date resolve error'); + + // match: [1] year [2] month [3] day + + year = +(match[1]); + month = +(match[2]) - 1; // JS month starts with 0 + day = +(match[3]); + + if (!match[4]) { // no hour + return new Date(Date.UTC(year, month, day)); + } + + // match: [4] hour [5] minute [6] second [7] fraction + + hour = +(match[4]); + minute = +(match[5]); + second = +(match[6]); + + if (match[7]) { + fraction = match[7].slice(0, 3); + while (fraction.length < 3) { // milli-seconds + fraction += '0'; + } + fraction = +fraction; + } + + // match: [8] tz [9] tz_sign [10] tz_hour [11] tz_minute + + if (match[9]) { + tz_hour = +(match[10]); + tz_minute = +(match[11] || 0); + delta = (tz_hour * 60 + tz_minute) * 60000; // delta in mili-seconds + if (match[9] === '-') delta = -delta; + } + + date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction)); + + if (delta) date.setTime(date.getTime() - delta); + + return date; +} + +function representYamlTimestamp(object /*, style*/) { + return object.toISOString(); +} + +module.exports = new Type('tag:yaml.org,2002:timestamp', { + kind: 'scalar', + resolve: resolveYamlTimestamp, + construct: constructYamlTimestamp, + instanceOf: Date, + represent: representYamlTimestamp +}); diff --git a/node_modules/wfilesencoders/node_modules/js-yaml/package.json b/node_modules/wfilesencoders/node_modules/js-yaml/package.json new file mode 100644 index 00000000..17574da8 --- /dev/null +++ b/node_modules/wfilesencoders/node_modules/js-yaml/package.json @@ -0,0 +1,66 @@ +{ + "name": "js-yaml", + "version": "4.1.0", + "description": "YAML 1.2 parser and serializer", + "keywords": [ + "yaml", + "parser", + "serializer", + "pyyaml" + ], + "author": "Vladimir Zapparov ", + "contributors": [ + "Aleksey V Zapparov (http://www.ixti.net/)", + "Vitaly Puzrin (https://github.com/puzrin)", + "Martin Grenfell (http://got-ravings.blogspot.com)" + ], + "license": "MIT", + "repository": "nodeca/js-yaml", + "files": [ + "index.js", + "lib/", + "bin/", + "dist/" + ], + "bin": { + "js-yaml": "bin/js-yaml.js" + }, + "module": "./dist/js-yaml.mjs", + "exports": { + ".": { + "import": "./dist/js-yaml.mjs", + "require": "./index.js" + }, + "./package.json": "./package.json" + }, + "scripts": { + "lint": "eslint .", + "test": "npm run lint && mocha", + "coverage": "npm run lint && nyc mocha && nyc report --reporter html", + "demo": "npm run lint && node support/build_demo.js", + "gh-demo": "npm run demo && gh-pages -d demo -f", + "browserify": "rollup -c support/rollup.config.js", + "prepublishOnly": "npm run gh-demo" + }, + "unpkg": "dist/js-yaml.min.js", + "jsdelivr": "dist/js-yaml.min.js", + "dependencies": { + "argparse": "^2.0.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^17.0.0", + "@rollup/plugin-node-resolve": "^11.0.0", + "ansi": "^0.3.1", + "benchmark": "^2.1.4", + "codemirror": "^5.13.4", + "eslint": "^7.0.0", + "fast-check": "^2.8.0", + "gh-pages": "^3.1.0", + "mocha": "^8.2.1", + "nyc": "^15.1.0", + "rollup": "^2.34.1", + "rollup-plugin-node-polyfills": "^0.2.1", + "rollup-plugin-terser": "^7.0.2", + "shelljs": "^0.8.4" + } +} diff --git a/package.json b/package.json index 37a43693..c17d47f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wretry.action", - "version": "1.0.19", + "version": "1.0.20", "description": "Retries an Github Action step on failure", "enabled": 0, "author": "Kostiantyn Wandalen ", @@ -31,9 +31,8 @@ "src/Main.js" ], "dependencies": { - "@actions/core": "^1.8.2", "wgittools": "alpha", - "willbe": "^0.5.535" + "@actions/core": "^1.8.2" }, "devDependencies": { "wTesting": "" diff --git a/will.yml b/will.yml index ff39e3f9..8648aa07 100644 --- a/will.yml +++ b/will.yml @@ -1,6 +1,6 @@ about: name: wretry.action - version: 1.0.19 + version: 1.0.20 description: Retries an Github Action step on failure enabled: 0 author: Kostiantyn Wandalen