electron-store icon indicating copy to clipboard operation
electron-store copied to clipboard

Upgrade to JSON Schema draft 2019/09

Open ramtinsoltani opened this issue 2 years ago • 8 comments

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']
        }]
      }
    }
  }
};

ramtinsoltani avatar Nov 06 '22 03:11 ramtinsoltani

This package depends on ajv 8, which supports:

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

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

sindresorhus avatar Nov 06 '22 03:11 sindresorhus

@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?

ramtinsoltani avatar Nov 06 '22 04:11 ramtinsoltani

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?

sindresorhus avatar Nov 06 '22 05:11 sindresorhus

@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.

ramtinsoltani avatar Nov 06 '22 05:11 ramtinsoltani

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.

sindresorhus avatar Nov 06 '22 14:11 sindresorhus

@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

ramtinsoltani avatar Nov 06 '22 23:11 ramtinsoltani

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.

sindresorhus avatar Nov 08 '22 06:11 sindresorhus

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!).

ramtinsoltani avatar Nov 09 '22 20:11 ramtinsoltani

Any plan to upgrade JSON Schema draft now ESM are supported?

julien3 avatar Jun 14 '24 16:06 julien3

https://github.com/sindresorhus/electron-store/releases/tag/v10.0.0

sindresorhus avatar Jun 14 '24 17:06 sindresorhus