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.
		
		
		
		
		
			
		
			
				
					101 lines
				
				4.1 KiB
			
		
		
			
		
	
	
					101 lines
				
				4.1 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								import type AjvCore from "../core"
							 | 
						||
| 
								 | 
							
								import type {AnyValidateFunction, SourceCode} from "../types"
							 | 
						||
| 
								 | 
							
								import type {SchemaEnv} from "../compile"
							 | 
						||
| 
								 | 
							
								import {UsedScopeValues, UsedValueState, ValueScopeName, varKinds} from "../compile/codegen/scope"
							 | 
						||
| 
								 | 
							
								import {_, nil, _Code, Code, getProperty, getEsmExportName} from "../compile/codegen/code"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function standaloneCode(
							 | 
						||
| 
								 | 
							
								  ajv: AjvCore,
							 | 
						||
| 
								 | 
							
								  refsOrFunc?: {[K in string]?: string} | AnyValidateFunction
							 | 
						||
| 
								 | 
							
								): string {
							 | 
						||
| 
								 | 
							
								  if (!ajv.opts.code.source) {
							 | 
						||
| 
								 | 
							
								    throw new Error("moduleCode: ajv instance must have code.source option")
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  const {_n} = ajv.scope.opts
							 | 
						||
| 
								 | 
							
								  return typeof refsOrFunc == "function"
							 | 
						||
| 
								 | 
							
								    ? funcExportCode(refsOrFunc.source)
							 | 
						||
| 
								 | 
							
								    : refsOrFunc !== undefined
							 | 
						||
| 
								 | 
							
								    ? multiExportsCode<string>(refsOrFunc, getValidate)
							 | 
						||
| 
								 | 
							
								    : multiExportsCode<SchemaEnv>(ajv.schemas, (sch) =>
							 | 
						||
| 
								 | 
							
								        sch.meta ? undefined : ajv.compile(sch.schema)
							 | 
						||
| 
								 | 
							
								      )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function getValidate(id: string): AnyValidateFunction {
							 | 
						||
| 
								 | 
							
								    const v = ajv.getSchema(id)
							 | 
						||
| 
								 | 
							
								    if (!v) throw new Error(`moduleCode: no schema with id ${id}`)
							 | 
						||
| 
								 | 
							
								    return v
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function funcExportCode(source?: SourceCode): string {
							 | 
						||
| 
								 | 
							
								    const usedValues: UsedScopeValues = {}
							 | 
						||
| 
								 | 
							
								    const n = source?.validateName
							 | 
						||
| 
								 | 
							
								    const vCode = validateCode(usedValues, source)
							 | 
						||
| 
								 | 
							
								    if (ajv.opts.code.esm) {
							 | 
						||
| 
								 | 
							
								      // Always do named export as `validate` rather than the variable `n` which is `validateXX` for known export value
							 | 
						||
| 
								 | 
							
								      return `"use strict";${_n}export const validate = ${n};${_n}export default ${n};${_n}${vCode}`
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return `"use strict";${_n}module.exports = ${n};${_n}module.exports.default = ${n};${_n}${vCode}`
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function multiExportsCode<T extends SchemaEnv | string>(
							 | 
						||
| 
								 | 
							
								    schemas: {[K in string]?: T},
							 | 
						||
| 
								 | 
							
								    getValidateFunc: (schOrId: T) => AnyValidateFunction | undefined
							 | 
						||
| 
								 | 
							
								  ): string {
							 | 
						||
| 
								 | 
							
								    const usedValues: UsedScopeValues = {}
							 | 
						||
| 
								 | 
							
								    let code = _`"use strict";`
							 | 
						||
| 
								 | 
							
								    for (const name in schemas) {
							 | 
						||
| 
								 | 
							
								      const v = getValidateFunc(schemas[name] as T)
							 | 
						||
| 
								 | 
							
								      if (v) {
							 | 
						||
| 
								 | 
							
								        const vCode = validateCode(usedValues, v.source)
							 | 
						||
| 
								 | 
							
								        const exportSyntax = ajv.opts.code.esm
							 | 
						||
| 
								 | 
							
								          ? _`export const ${getEsmExportName(name)}`
							 | 
						||
| 
								 | 
							
								          : _`exports${getProperty(name)}`
							 | 
						||
| 
								 | 
							
								        code = _`${code}${_n}${exportSyntax} = ${v.source?.validateName};${_n}${vCode}`
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return `${code}`
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function validateCode(usedValues: UsedScopeValues, s?: SourceCode): Code {
							 | 
						||
| 
								 | 
							
								    if (!s) throw new Error('moduleCode: function does not have "source" property')
							 | 
						||
| 
								 | 
							
								    if (usedState(s.validateName) === UsedValueState.Completed) return nil
							 | 
						||
| 
								 | 
							
								    setUsedState(s.validateName, UsedValueState.Started)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const scopeCode = ajv.scope.scopeCode(s.scopeValues, usedValues, refValidateCode)
							 | 
						||
| 
								 | 
							
								    const code = new _Code(`${scopeCode}${_n}${s.validateCode}`)
							 | 
						||
| 
								 | 
							
								    return s.evaluated ? _`${code}${s.validateName}.evaluated = ${s.evaluated};${_n}` : code
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function refValidateCode(n: ValueScopeName): Code | undefined {
							 | 
						||
| 
								 | 
							
								      const vRef = n.value?.ref
							 | 
						||
| 
								 | 
							
								      if (n.prefix === "validate" && typeof vRef == "function") {
							 | 
						||
| 
								 | 
							
								        const v = vRef as AnyValidateFunction
							 | 
						||
| 
								 | 
							
								        return validateCode(usedValues, v.source)
							 | 
						||
| 
								 | 
							
								      } else if ((n.prefix === "root" || n.prefix === "wrapper") && typeof vRef == "object") {
							 | 
						||
| 
								 | 
							
								        const {validate, validateName} = vRef as SchemaEnv
							 | 
						||
| 
								 | 
							
								        if (!validateName) throw new Error("ajv internal error")
							 | 
						||
| 
								 | 
							
								        const def = ajv.opts.code.es5 ? varKinds.var : varKinds.const
							 | 
						||
| 
								 | 
							
								        const wrapper = _`${def} ${n} = {validate: ${validateName}};`
							 | 
						||
| 
								 | 
							
								        if (usedState(validateName) === UsedValueState.Started) return wrapper
							 | 
						||
| 
								 | 
							
								        const vCode = validateCode(usedValues, validate?.source)
							 | 
						||
| 
								 | 
							
								        return _`${wrapper}${_n}${vCode}`
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      return undefined
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function usedState(name: ValueScopeName): UsedValueState | undefined {
							 | 
						||
| 
								 | 
							
								      return usedValues[name.prefix]?.get(name)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function setUsedState(name: ValueScopeName, state: UsedValueState): void {
							 | 
						||
| 
								 | 
							
								      const {prefix} = name
							 | 
						||
| 
								 | 
							
								      const names = (usedValues[prefix] = usedValues[prefix] || new Map())
							 | 
						||
| 
								 | 
							
								      names.set(name, state)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = exports = standaloneCode
							 | 
						||
| 
								 | 
							
								Object.defineProperty(exports, "__esModule", {value: true})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export default standaloneCode
							 |