code.ts 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import type {AnySchema, SchemaMap} from "../types"
  2. import type {SchemaCxt} from "../compile"
  3. import type KeywordCxt from "../compile/context"
  4. import {CodeGen, _, or, nil, strConcat, getProperty, Code, Name} from "../compile/codegen"
  5. import {alwaysValidSchema} from "../compile/util"
  6. import N from "../compile/names"
  7. export function checkReportMissingProp(cxt: KeywordCxt, prop: string): void {
  8. const {gen, data, it} = cxt
  9. gen.if(noPropertyInData(data, prop, it.opts.ownProperties), () => {
  10. cxt.setParams({missingProperty: _`${prop}`}, true)
  11. cxt.error()
  12. })
  13. }
  14. export function checkMissingProp(
  15. {data, it: {opts}}: KeywordCxt,
  16. properties: string[],
  17. missing: Name
  18. ): Code {
  19. return or(
  20. ...properties.map(
  21. (prop) => _`${noPropertyInData(data, prop, opts.ownProperties)} && (${missing} = ${prop})`
  22. )
  23. )
  24. }
  25. export function reportMissingProp(cxt: KeywordCxt, missing: Name): void {
  26. cxt.setParams({missingProperty: missing}, true)
  27. cxt.error()
  28. }
  29. function isOwnProperty(data: Name, property: Name | string): Code {
  30. return _`Object.prototype.hasOwnProperty.call(${data}, ${property})`
  31. }
  32. export function propertyInData(data: Name, property: Name | string, ownProperties?: boolean): Code {
  33. const cond = _`${data}${getProperty(property)} !== undefined`
  34. return ownProperties ? _`${cond} && ${isOwnProperty(data, property)}` : cond
  35. }
  36. export function noPropertyInData(
  37. data: Name,
  38. property: Name | string,
  39. ownProperties?: boolean
  40. ): Code {
  41. const cond = _`${data}${getProperty(property)} === undefined`
  42. return ownProperties ? _`${cond} || !${isOwnProperty(data, property)}` : cond
  43. }
  44. export function allSchemaProperties(schemaMap?: SchemaMap): string[] {
  45. return schemaMap ? Object.keys(schemaMap).filter((p) => p !== "__proto__") : []
  46. }
  47. export function schemaProperties(it: SchemaCxt, schemaMap: SchemaMap): string[] {
  48. return allSchemaProperties(schemaMap).filter(
  49. (p) => !alwaysValidSchema(it, schemaMap[p] as AnySchema)
  50. )
  51. }
  52. export function callValidateCode(
  53. {schemaCode, data, it: {gen, topSchemaRef, schemaPath, errorPath}, it}: KeywordCxt,
  54. func: Code,
  55. context: Code,
  56. passSchema?: boolean
  57. ): Code {
  58. const dataAndSchema = passSchema ? _`${schemaCode}, ${data}, ${topSchemaRef}${schemaPath}` : data
  59. const valCxt: [Name, Code | number][] = [
  60. [N.dataPath, strConcat(N.dataPath, errorPath)],
  61. [N.parentData, it.parentData],
  62. [N.parentDataProperty, it.parentDataProperty],
  63. [N.rootData, N.rootData],
  64. ]
  65. if (it.opts.dynamicRef) valCxt.push([N.dynamicAnchors, N.dynamicAnchors])
  66. const args = _`${dataAndSchema}, ${gen.object(...valCxt)}`
  67. return context !== nil ? _`${func}.call(${context}, ${args})` : _`${func}(${args})`
  68. }
  69. export function usePattern(gen: CodeGen, pattern: string): Name {
  70. return gen.scopeValue("pattern", {
  71. key: pattern,
  72. ref: new RegExp(pattern, "u"),
  73. code: _`new RegExp(${pattern}, "u")`,
  74. })
  75. }