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 |