import fs = require ( 'fs' ) ; import path = require ( 'path' ) ; var Ajv = require ( './ajv-bundle' ) ; export class JsonSchema { private _fileName : string ; private _validator : any ; private static _ajv = Ajv ( ) ; public validate ( jsValue ) { return this . _validator ( jsValue ) ; } public getFileName ( ) { return this . _fileName ; } public getErrors ( ) { return this . _validator . errors ; } public constructor ( fileName ) { this . _fileName = fileName ; var schemaObject = parseJsonFile ( fileName ) ; this . _validator = JsonSchema . _ajv . compile ( schemaObject ) ; } } export function ensureSchema ( jsValue , jsonSchema ) { if ( ! jsonSchema . validate ( jsValue ) ) { throw new Error ( "Object '" + "' doesn't match schema '" + jsonSchema . getFileName ( ) + "':" + JSON . stringify ( jsonSchema . getErrors ( ) ) ) ; } } export function parseJsonString ( jsonString , jsonSchema = undefined , allowComments = false ) { if ( allowComments ) { var stripJsonComments = require ( 'strip-json-comments' ) ; jsonString = stripJsonComments ( jsonString ) ; } try { var jsValue = JSON . parse ( jsonString ) ; } catch ( error ) { throw new Error ( "Failed to parse JSON ':" + error . toString ( ) ) ; } if ( jsonSchema != null ) { ensureSchema ( jsValue , jsonSchema ) ; } return jsValue ; } export function parseJsonFile ( jsonFile , jsonSchema = undefined , allowComments = false ) { return appendMessageOnException ( ".Error file name: '" + jsonFile + "'." , ( ) => { return parseJsonString ( readJsonString ( jsonFile ) , jsonSchema , allowComments ) ; } ) ; } export function readJsonString ( jsonFile ) { return fs . readFileSync ( jsonFile , 'utf8' ) . replace ( /^\uFEFF/ , '' ) ; } export function readConfig ( filePath , jsonSchema ? ) { if ( path . extname ( filePath ) . toLowerCase ( ) != '.json' ) { throw new Error ( "readConfig only support '.json' as extension. filePath='" + filePath + "'." ) ; } if ( ! filePath . startsWith ( '.' ) ) { filePath = require . resolve ( filePath ) ; } return parseJsonFile ( filePath , jsonSchema , true ) ; } export interface Transform { apply ( jsValue ) : any ; } ; export class ChainableTransform implements Transform { protected _next : ChainableTransform = null ; public add ( next ) { var node = this ; while ( node . _next != null ) { node = node . _next ; } node . _next = next ; return this ; } public apply ( jsValue ) { var transformedValue = this . transform ( jsValue ) ; if ( this . _next != null ) { return this . _next . apply ( transformedValue ) ; } return transformedValue ; } protected transform ( jsValue ) { throw new Error ( "Not implemented" ) ; } } ; export class RenameProperties extends ChainableTransform { private _nameMap : { [ oldName ] : string ; } ; public constructor ( nameMap ) { super ( ) ; this . _nameMap = nameMap ; } public transform ( jsObject ) { var oldNames = Object . keys ( this . _nameMap ) ; oldNames . forEach ( oldName => { jsObject [ this . _nameMap [ oldName ] ] = jsObject [ oldName ] ; delete jsObject [ oldName ] ; } ) ; return jsObject ; } } export class SetDefaultValue extends ChainableTransform { private _defaultValueMap : { [ propertyName ] : any ; } ; public constructor ( defaultValueMap ) { super ( ) ; this . _defaultValueMap = defaultValueMap ; } public transform ( jsObject ) { var propertyNames = Object . keys ( this . _defaultValueMap ) ; propertyNames . forEach ( propertyName => { if ( ! jsObject . hasOwnProperty ( propertyName ) ) { jsObject [ propertyName ] = this . _defaultValueMap [ propertyName ] ; } } ) ; return jsObject ; } } export interface ValueTransform { ( input ) : any ; } export class TransformPropertyValues extends ChainableTransform { private _propertyNameToTransformMap : { [ propertyName ] : ValueTransform ; } ; public constructor ( propertyNameToTransformMap ) { super ( ) ; this . _propertyNameToTransformMap = propertyNameToTransformMap ; } public transform ( jsObject ) { var oldNames = Object . keys ( this . _propertyNameToTransformMap ) ; oldNames . forEach ( ( propertyName ) => { jsObject [ propertyName ] = this . _propertyNameToTransformMap [ propertyName ] ( jsObject [ propertyName ] ) ; } ) ; return jsObject ; } } interface SingularNodeOperation { ( node ) : any ; } class SingularNodeOperationResult { public constructor ( public operationPerformed , public result ? ) { } } export function appendMessageOnException ( message , fun ) { try { return fun ( ) ; } catch ( error ) { error . message += message ; throw error ; } } export function makePromiseIfNotAlready ( returnValue ) { if ( returnValue != null && typeof returnValue === 'object' && typeof returnValue [ 'then' ] === 'function' ) { return returnValue ; } return Promise . resolve ( returnValue ) ; } export function loadFunction ( moduleName , functionName ) { let module = require ( moduleName ) ; if ( module == null ) { throw new Error ( "Cannot load module '" + moduleName + "'." ) ; } let func = module ; for ( let token of functionName . split ( "." ) ) { if ( token . length == 0 ) { continue ; } func = func [ token ] ; if ( func == null ) { throw new Error ( "Cannot load function '" + functionName + "' in module '" + moduleName + "'. Symbol '" + token + "' doesn't exist." ) ; } } return func ; }