Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to JSON Schema draft 2019/09 #239

Open
ramtinsoltani opened this issue Nov 6, 2022 · 8 comments
Open

Upgrade to JSON Schema draft 2019/09 #239

ramtinsoltani opened this issue Nov 6, 2022 · 8 comments

Comments

@ramtinsoltani
Copy link

Any plans to upgrade to JSON Schema draft 2019/09? It unlocks some goodies including unevaluatedProperties which is very important when working with schema compositions.

This is an example where not having unevaluatedProperties support limits the schema:

import { Schema } from 'electron-store';

export interface BasicAuthCredentials {
  type: 'basic',
  username: string,
  password: string
}

export interface BearerTokenCredentials {
  type: 'bearer',
  token: string
}

export interface CredentialsStore {
  credentials: {
    [id: string]: BasicAuthCredentials | BearerTokenCredentials
  }
}

export const CredentialsSchema: Schema<CredentialsStore> = {
  credentials: {
    type: 'object',
    additionalProperties: false,
    patternProperties: {
      '^[a-zA-Z0-9]{10}$': {
        /* We cannot use 'oneOf' while disallowing additional properties
        without the support for 'unevaluatedProperties'. */
        unevaluatedProperties: false,
        type: 'object',
        oneOf: [{
          properties: {
            type: { type: 'string', enum: ['basic'] },
            username: { type: 'string', pattern: '^[^:]{1,255}$' },
            password: { type: 'string', minLength: 1, maxLength: 255 }
          },
          required: ['type', 'username', 'password']
        }, {
          properties: {
            type: { type: 'string', enum: ['bearer'] },
            token: { type: 'string', minLength: 1 }
          },
          required: ['type', 'token']
        }]
      }
    }
  }
};
@sindresorhus
Copy link
Owner

This package depends on ajv 8, which supports:

JSON Schema draft-06/07/2019-09/2020-12

https://github.com/ajv-validator/ajv

@ramtinsoltani
Copy link
Author

@sindresorhus Correct. But in order to use draft-2019-09 the ajv import needs to be updated to:

import Ajv from 'ajv/dist/2019';

according to https://ajv.js.org/json-schema.html#draft-2019-09.

I looked at the code inside conf and it can be updated easily. Though the issue is with package json-schema-typed. It needs to be updated to version 8.0.1 to support the new drafts. If the import is changed to the following at conf/source/types.ts:1 after the update:

import {type JSONSchema as TypedJSONSchema} from 'json-schema-typed/draft-2019-09';

we'll get a bunch of errors:

source/index.ts:110:5 - error TS2322: Type 'Schema<T>' is not assignable to type 'Record<string, JSONSchema<any, TypeValue>>'.
  Type 'ValueSchema' is not assignable to type 'JSONSchema<any, TypeValue>'.
    Type '{ $anchor?: string | undefined; $comment?: string | undefined; $defs?: Record<string, JSONSchema<any, TypeValue>> | undefined; $id?: string | undefined; ... 54 more ...; writeOnly?: boolean | undefined; }' is not assignable to type 'JSONSchema<any, TypeValue>'.
      Type '{ $anchor?: string | undefined; $comment?: string | undefined; $defs?: Record<string, JSONSchema<any, TypeValue>> | undefined; $id?: string | undefined; ... 54 more ...; writeOnly?: boolean | undefined; }' is not assignable to type '{ $anchor?: string | undefined; $comment?: string | undefined; $defs?: Record<string, JSONSchema<any, TypeValue>> | undefined; $dynamicAnchor?: string | undefined; ... 55 more ...; writeOnly?: boolean | undefined; }'.
        Types of property 'additionalItems' are incompatible.
          Type 'import("/Users/ramtin/repos/misc/conf/node_modules/json-schema-typed/draft-2019-09").JSONSchema<any, import("/Users/ramtin/repos/misc/conf/node_modules/json-schema-typed/draft-2019-09").JSONSchema.TypeValue> | undefined' is not assignable to type 'import("/Users/ramtin/repos/misc/conf/node_modules/json-schema-typed/draft-2020-12").JSONSchema<any, import("/Users/ramtin/repos/misc/conf/node_modules/json-schema-typed/draft-2020-12").JSONSchema.TypeValue> | undefined'.
            Type '{ $anchor?: string | undefined; $comment?: string | undefined; $defs?: Record<string, JSONSchema<any, TypeValue>> | undefined; $id?: string | undefined; ... 54 more ...; writeOnly?: boolean | undefined; }' is not assignable to type 'JSONSchema<any, TypeValue> | undefined'.

110     properties: options.schema
        ~~~~~~~~~~

source/index.ts:115:58 - error TS2345: Argument of type 'Schema<T>' is not assignable to parameter of type '{ [s: string]: JSONSchema<any, TypeValue>; } | ArrayLike<JSONSchema<any, TypeValue>>'.
  Property 'length' is missing in type 'Schema<T>' but required in type 'ArrayLike<JSONSchema<any, TypeValue>>'.

115    for (const [key, value] of Object.entries<JSONSchema>(options.schema)) {
                                                             ~~~~~~~~~~~~~~

  node_modules/typescript/lib/lib.es5.d.ts:1542:14
    1542     readonly length: number;
                      ~~~~~~
    'length' is declared here.

source/index.ts:116:16 - error TS2339: Property 'default' does not exist on type 'JSONSchema<any, TypeValue>'.
  Property 'default' does not exist on type 'false'.

116     if (value?.default) {
                   ~~~~~~~

source/index.ts:117:50 - error TS2339: Property 'default' does not exist on type 'JSONSchema<any, TypeValue>'.
  Property 'default' does not exist on type 'false'.

117      this.#defaultValues[key as keyof T] = value.default;

Is there another way to use draft-2019-09?

@sindresorhus
Copy link
Owner

Hmm. Weird that they would not use the latest draft as the default.

I guess we can just do a major version where we update it to the latest draft.

I assume you would be ok with draft-2020-12?

@ramtinsoltani
Copy link
Author

ramtinsoltani commented Nov 6, 2022

@sindresorhus Yes, I think it makes sense to move on to the latest draft. The only thing to keep in mind is that draft-2019-09 is backward compatible with draft-07, while draft-2020-12 has breaking changes.

@sindresorhus
Copy link
Owner

Looks like it's not possible to upgrade. We need to upgrade to json-schema-typed v8 to get the 2020 or 2019 types, but the package moved to ESM in v8, which is not yet supported by Electron.

@ramtinsoltani
Copy link
Author

@sindresorhus Can't we drop json-schema-typed and use ajv's JSONSchemaType instead?
Here's the documentation: https://ajv.js.org/guide/typescript.html#utility-types-for-schemas

@sindresorhus
Copy link
Owner

json-schema-typed has the benefit that it has extensive doc comments and I believe it's more strictly typed. I'm sure I'll get complaints if I switch to worse types.

@ramtinsoltani
Copy link
Author

Not sure what the alternative would be in this case. It doesn't seem like Electron would support ES modules anytime soon (see this thread that's been going on for 3 years!).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants