ajv#Schema TypeScript Examples

The following examples show how to use ajv#Schema. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: validateLists.ts    From default-token-list with MIT License 6 votes vote down vote up
newSchema: Schema = deepmerge(schema, {
  definitions: {
    TokenInfo: {
      properties: {
        name: {
          pattern: "^[ \\w.'+\\-%/À-ÖØ-öø-ÿ:]+$",
        },
        tags: {
          maxItems: schema.definitions.TokenInfo.properties.tags.maxItems,
        },
      },
    },
  },
})
Example #2
Source File: ajv.ts    From backstage with Apache License 2.0 6 votes vote down vote up
// Compiles the given schema, and makes sure to also grab any core dependencies
// that it depends on
export function compileAjvSchema(
  schema: Schema,
  options: { disableCache?: boolean } = {},
): ValidateFunction<unknown> {
  const disableCache = options?.disableCache ?? false;
  const cacheKey = disableCache ? '' : JSON.stringify(schema);

  if (!disableCache) {
    const cached = compiledSchemaCache.get(cacheKey);
    if (cached) {
      return cached;
    }
  }

  const extraSchemas = getExtraSchemas(schema);
  const ajv = new Ajv({
    allowUnionTypes: true,
    allErrors: true,
    validateSchema: true,
  });
  if (extraSchemas.length) {
    ajv.addSchema(extraSchemas, undefined, undefined, true);
  }
  const compiled = ajv.compile(schema);

  if (!disableCache) {
    compiledSchemaCache.set(cacheKey, compiled);
  }

  return compiled;
}
Example #3
Source File: ajv.ts    From backstage with Apache License 2.0 6 votes vote down vote up
// Find refs in the given schema and recursively in all known schemas it
// targets, collecting that list of schemas as we go
function getExtraSchemas(schema: Schema): Schema[] {
  if (typeof schema !== 'object') {
    return [];
  }

  const seen = new Set<string>();
  if (schema.$id) {
    seen.add(schema.$id);
  }

  const selected = new Array<Schema>();

  const todo: Schema[] = [schema];
  while (todo.length) {
    const current = todo.pop()!;

    for (const ref of getAllRefs(current)) {
      if (!seen.has(ref)) {
        seen.add(ref);

        const match = refDependencyCandidates.find(c => c.$id === ref);
        if (match) {
          selected.push(match);
          todo.push(match);
        }
      }
    }
  }

  return selected;
}
Example #4
Source File: ajv.ts    From backstage with Apache License 2.0 6 votes vote down vote up
// Naively step through the entire schema looking for "$ref": "x" pairs. The
// resulting iterator may contain duplicates. Ignores fragments, i.e. for a ref
// of "a#b", it will just yield "a".
function* getAllRefs(schema: Schema): Iterable<string> {
  const todo: any[] = [schema];
  while (todo.length) {
    const current = todo.pop()!;
    if (typeof current === 'object' && current) {
      for (const [key, value] of Object.entries(current)) {
        if (key === '$ref' && typeof value === 'string') {
          yield value.split('#')[0];
        } else {
          todo.push(value);
        }
      }
    }
  }
}
Example #5
Source File: entitySchemaValidator.ts    From backstage with Apache License 2.0 6 votes vote down vote up
/**
 * Creates a validation function that takes some arbitrary data, and either
 * returns that data cast to an {@link Entity} (or the given subtype) if it
 * matches that schema, or throws a {@link globals#TypeError} describing the errors.
 *
 * @remarks
 *
 * Note that this validator is only meant for applying the base schema checks;
 * it does not take custom policies or additional processor based validation
 * into account.
 *
 * By default, the plain {@link Entity} schema is used. If you pass in your own, it
 * may contain `$ref` references to the following, which are resolved
 * automatically for you:
 *
 * - {@link Entity}
 * - {@link EntityEnvelope}
 * - {@link EntityMeta}
 * - `common#<id>`
 *
 * @public
 * @see {@link https://github.com/backstage/backstage/tree/master/packages/catalog-model/src/schema}
 */
export function entitySchemaValidator<T extends Entity = Entity>(
  schema?: unknown,
): (data: unknown) => T {
  const validate = compileAjvSchema(schema ? (schema as Schema) : entitySchema);

  return data => {
    const result = validate(data);
    if (result === true) {
      return data as T;
    }

    throw throwAjvError(validate.errors);
  };
}
Example #6
Source File: ConfigBuilder.ts    From context-mod with MIT License 5 votes vote down vote up
validateJson = (config: object, schema: Schema, logger: Logger): any => {
    const ajv = createAjvFactory(logger);
    const valid = ajv.validate(schema, config);
    if (valid) {
        return config;
    } else {
        logger.error('Json config was not valid. Please use schema to check validity.', {leaf: 'Config'});
        if (Array.isArray(ajv.errors)) {
            for (const err of ajv.errors) {
                let parts = [
                    `At: ${err.dataPath}`,
                ];
                let data;
                if (typeof err.data === 'string') {
                    data = err.data;
                } else if (err.data !== null && typeof err.data === 'object' && (err.data as any).name !== undefined) {
                    data = `Object named '${(err.data as any).name}'`;
                }
                if (data !== undefined) {
                    parts.push(`Data: ${data}`);
                }
                let suffix = '';
                // @ts-ignore
                if (err.params.allowedValues !== undefined) {
                    // @ts-ignore
                    suffix = err.params.allowedValues.join(', ');
                    suffix = ` [${suffix}]`;
                }
                parts.push(`${err.keyword}: ${err.schemaPath} => ${err.message}${suffix}`);

                // if we have a reference in the description parse it out so we can log it here for context
                if (err.parentSchema !== undefined && err.parentSchema.description !== undefined) {
                    const desc = err.parentSchema.description as string;
                    const seeIndex = desc.indexOf('[See]');
                    if (seeIndex !== -1) {
                        let newLineIndex: number | undefined = desc.indexOf('\n', seeIndex);
                        if (newLineIndex === -1) {
                            newLineIndex = undefined;
                        }
                        const seeFragment = desc.slice(seeIndex + 5, newLineIndex);
                        parts.push(`See:${seeFragment}`);
                    }
                }

                logger.error(`Schema Error:\r\n${parts.join('\r\n')}`, {leaf: 'Config'});
            }
        }
        throw new LoggedError('Config schema validity failure');
    }
}
Example #7
Source File: entityEnvelopeSchemaValidator.ts    From backstage with Apache License 2.0 5 votes vote down vote up
/**
 * Creates a validation function that takes some arbitrary data, and either
 * returns that data cast to an {@link EntityEnvelope} (or the given subtype)
 * if it matches that schema, or throws a {@link globals#TypeError} describing the
 * errors.
 *
 * @remarks
 *
 * Note that this validator is only meant for applying the base schema checks;
 * it does not take custom policies or additional processor based validation
 * into account.
 *
 * By default, the plain `EntityEnvelope` schema is used. If you pass in your
 * own, it may contain `$ref` references to the following, which are resolved
 * automatically for you:
 *
 * - {@link EntityEnvelope}
 * - {@link Entity}
 * - {@link EntityMeta}
 * - `common#<id>`
 *
 * See also {@link https://github.com/backstage/backstage/tree/master/packages/catalog-model/src/schema}
 *
 * @public
 *
 */
export function entityEnvelopeSchemaValidator<
  T extends EntityEnvelope = EntityEnvelope,
>(schema?: unknown): (data: unknown) => T {
  const validate = compileAjvSchema(
    schema ? (schema as Schema) : entityEnvelopeSchema,
  );

  return data => {
    const result = validate(data);
    if (result === true) {
      return data as T;
    }

    throw throwAjvError(validate.errors);
  };
}
Example #8
Source File: entityKindSchemaValidator.ts    From backstage with Apache License 2.0 5 votes vote down vote up
/**
 * Creates a validation function that takes some arbitrary data, and either
 * returns that data cast to a `T` if it matches that schema, or `false` if the
 * schema apiVersion/kind didn't apply to that data, or throws a
 * {@link globals#TypeError} describing actual errors.
 *
 * @remarks
 *
 * This validator is highly specialized, in that it has special treatment of
 * the `kind` and `apiVersion` root keys. This only works if your schema has
 * their rule set to `"enum"`:
 *
 * ```
 * "apiVersion": {
 *    "enum": ["backstage.io/v1alpha1", "backstage.io/v1beta1"]
 * },
 * "kind": {
 *   "enum": ["Group"]
 * },
 * ```
 *
 * In the above example, the created validator will return `false` if and only
 * if the kind and/or apiVersion mismatch.
 *
 * Note that this validator is only meant for applying the base schema checks;
 * it does not take custom policies or additional processor based validation
 * into account.
 *
 * The given schema may contain `$ref` references to the following, which are
 * resolved automatically for you:
 *
 * - {@link Entity}
 *
 * - {@link EntityEnvelope}
 *
 * - {@link EntityMeta}
 *
 * - `common#<id>`
 * @see {@link https://github.com/backstage/backstage/tree/master/packages/catalog-model/src/schema}
 *
 * @public
 */
export function entityKindSchemaValidator<T extends Entity>(
  schema: unknown,
): (data: unknown) => T | false {
  const validate = compileAjvSchema(schema as Schema);

  return data => {
    const result = validate(data);
    if (result === true) {
      return data as T;
    }

    // Only in the case where kind and/or apiVersion have enum mismatches AND
    // have NO other errors, we call it a soft error.
    const softCandidates = validate.errors?.filter(e =>
      ['/kind', '/apiVersion'].includes(e.instancePath),
    );
    if (
      softCandidates?.length &&
      softCandidates.every(e => e.keyword === 'enum')
    ) {
      return false;
    }

    throw throwAjvError(validate.errors);
  };
}