You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							130 lines
						
					
					
						
							3.3 KiB
						
					
					
				
			
		
		
	
	
							130 lines
						
					
					
						
							3.3 KiB
						
					
					
				'use strict'
 | 
						|
 | 
						|
const Ajv = require('ajv')
 | 
						|
 | 
						|
const separator = {
 | 
						|
  keyword: 'separator',
 | 
						|
  type: 'string',
 | 
						|
  metaSchema: {
 | 
						|
    type: 'string',
 | 
						|
    description: 'value separator'
 | 
						|
  },
 | 
						|
  modifying: true,
 | 
						|
  valid: true,
 | 
						|
  errors: false,
 | 
						|
  compile: (schema) => (data, dataPath, parentData, parentDataProperty) => {
 | 
						|
    // In some cases parentData and parentDataProperty will be undefined.
 | 
						|
    // We need to fall back to the dataPath object to provide those values.
 | 
						|
    if (parentData && parentDataProperty) {
 | 
						|
      parentData[parentDataProperty] = data === '' ? [] : data.split(schema)
 | 
						|
    } else {
 | 
						|
      const {
 | 
						|
        parentData: pData,
 | 
						|
        parentDataProperty: pDataProperty
 | 
						|
      } = dataPath
 | 
						|
      pData[pDataProperty] = data === '' ? [] : data.split(schema)
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
const optsSchema = {
 | 
						|
  type: 'object',
 | 
						|
  required: ['schema'],
 | 
						|
  properties: {
 | 
						|
    schema: { type: 'object', additionalProperties: true },
 | 
						|
    data: {
 | 
						|
      oneOf: [
 | 
						|
        { type: 'array', items: { type: 'object' }, minItems: 1 },
 | 
						|
        { type: 'object' }
 | 
						|
      ],
 | 
						|
      default: {}
 | 
						|
    },
 | 
						|
    env: { type: 'boolean', default: true },
 | 
						|
    dotenv: { type: ['boolean', 'object'], default: false },
 | 
						|
    expandEnv: { type: ['boolean'], default: false },
 | 
						|
    ajv: { type: 'object', additionalProperties: true }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
const sharedAjvInstance = getDefaultInstance()
 | 
						|
 | 
						|
const optsSchemaValidator = sharedAjvInstance.compile(optsSchema)
 | 
						|
 | 
						|
function loadAndValidateEnvironment (_opts) {
 | 
						|
  const opts = Object.assign({}, _opts)
 | 
						|
 | 
						|
  if (opts.schema && opts.schema[Symbol.for('fluent-schema-object')]) {
 | 
						|
    opts.schema = opts.schema.valueOf()
 | 
						|
  }
 | 
						|
 | 
						|
  const isOptionValid = optsSchemaValidator(opts)
 | 
						|
  if (!isOptionValid) {
 | 
						|
    const error = new Error(sharedAjvInstance.errorsText(optsSchemaValidator.errors, { dataVar: 'opts' }))
 | 
						|
    error.errors = optsSchemaValidator.errors
 | 
						|
    throw error
 | 
						|
  }
 | 
						|
 | 
						|
  const schema = opts.schema
 | 
						|
  schema.additionalProperties = false
 | 
						|
 | 
						|
  let data = opts.data
 | 
						|
  if (!Array.isArray(opts.data)) {
 | 
						|
    data = [data]
 | 
						|
  }
 | 
						|
 | 
						|
  if (opts.dotenv) {
 | 
						|
    require('dotenv').config(Object.assign({}, opts.dotenv))
 | 
						|
  }
 | 
						|
 | 
						|
  if (opts.env) {
 | 
						|
    if (opts.expandEnv) {
 | 
						|
      require('dotenv-expand').expand({ parsed: process.env })
 | 
						|
    }
 | 
						|
    data.unshift(process.env)
 | 
						|
  }
 | 
						|
 | 
						|
  const merge = {}
 | 
						|
  data.forEach(d => Object.assign(merge, d))
 | 
						|
 | 
						|
  const ajv = chooseAjvInstance(sharedAjvInstance, opts.ajv)
 | 
						|
 | 
						|
  const valid = ajv.validate(schema, merge)
 | 
						|
  if (!valid) {
 | 
						|
    const error = new Error(ajv.errorsText(ajv.errors, { dataVar: 'env' }))
 | 
						|
    error.errors = ajv.errors
 | 
						|
    throw error
 | 
						|
  }
 | 
						|
 | 
						|
  return merge
 | 
						|
}
 | 
						|
 | 
						|
function chooseAjvInstance (defaultInstance, ajvOpts) {
 | 
						|
  if (!ajvOpts) {
 | 
						|
    return defaultInstance
 | 
						|
  } else if (typeof ajvOpts === 'object' && typeof ajvOpts.customOptions === 'function') {
 | 
						|
    const ajv = ajvOpts.customOptions(getDefaultInstance())
 | 
						|
    if (!(ajv instanceof Ajv)) {
 | 
						|
      throw new Error('customOptions function must return an instance of Ajv')
 | 
						|
    }
 | 
						|
    return ajv
 | 
						|
  }
 | 
						|
  return ajvOpts
 | 
						|
}
 | 
						|
 | 
						|
function getDefaultInstance () {
 | 
						|
  return new Ajv({
 | 
						|
    allErrors: true,
 | 
						|
    removeAdditional: true,
 | 
						|
    useDefaults: true,
 | 
						|
    coerceTypes: true,
 | 
						|
    allowUnionTypes: true,
 | 
						|
    addUsedSchema: false,
 | 
						|
    keywords: [separator]
 | 
						|
  })
 | 
						|
}
 | 
						|
 | 
						|
module.exports = loadAndValidateEnvironment
 | 
						|
module.exports.default = loadAndValidateEnvironment
 | 
						|
module.exports.envSchema = loadAndValidateEnvironment
 | 
						|
module.exports.envSchema.keywords = { separator }
 |