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
			| 
								 
											3 years ago
										 
									 | 
							
								'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 }
							 |